@hivemind-os/collective-daemon 0.2.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/chunk-57QD6553.js +803 -0
- package/dist/chunk-57QD6553.js.map +1 -0
- package/dist/chunk-BHN4GOYD.js +1196 -0
- package/dist/chunk-BHN4GOYD.js.map +1 -0
- package/dist/chunk-BJW47ZD5.js +341 -0
- package/dist/chunk-BJW47ZD5.js.map +1 -0
- package/dist/chunk-CJHYQ7RR.js +656 -0
- package/dist/chunk-CJHYQ7RR.js.map +1 -0
- package/dist/chunk-NXIFS427.js +183 -0
- package/dist/chunk-NXIFS427.js.map +1 -0
- package/dist/chunk-Q3V4V7UR.js +305 -0
- package/dist/chunk-Q3V4V7UR.js.map +1 -0
- package/dist/chunk-VHECO532.js +1005 -0
- package/dist/chunk-VHECO532.js.map +1 -0
- package/dist/config-SuloXL2_.d.ts +90 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.js +19 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +523 -0
- package/dist/index.js.map +1 -0
- package/dist/ipc/server.d.ts +69 -0
- package/dist/ipc/server.js +8 -0
- package/dist/ipc/server.js.map +1 -0
- package/dist/portal/server.d.ts +72 -0
- package/dist/portal/server.js +10 -0
- package/dist/portal/server.js.map +1 -0
- package/dist/provider/index.d.ts +202 -0
- package/dist/provider/index.js +22 -0
- package/dist/provider/index.js.map +1 -0
- package/dist/relay/index.d.ts +55 -0
- package/dist/relay/index.js +7 -0
- package/dist/relay/index.js.map +1 -0
- package/dist/session-monitor-P9hNAFw4.d.ts +16 -0
- package/dist/state.d.ts +59 -0
- package/dist/state.js +11 -0
- package/dist/state.js.map +1 -0
- package/package.json +72 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
IpcServer
|
|
4
|
+
} from "./chunk-BHN4GOYD.js";
|
|
5
|
+
import {
|
|
6
|
+
PortalServer
|
|
7
|
+
} from "./chunk-VHECO532.js";
|
|
8
|
+
import {
|
|
9
|
+
getConfigPath,
|
|
10
|
+
loadConfig
|
|
11
|
+
} from "./chunk-CJHYQ7RR.js";
|
|
12
|
+
import {
|
|
13
|
+
DaemonState,
|
|
14
|
+
createDaemonIdentityContext
|
|
15
|
+
} from "./chunk-Q3V4V7UR.js";
|
|
16
|
+
import "./chunk-NXIFS427.js";
|
|
17
|
+
import {
|
|
18
|
+
ProviderRuntime,
|
|
19
|
+
loadProviderConfig
|
|
20
|
+
} from "./chunk-57QD6553.js";
|
|
21
|
+
import "./chunk-BJW47ZD5.js";
|
|
22
|
+
|
|
23
|
+
// src/index.ts
|
|
24
|
+
import { mkdir as mkdir2 } from "fs/promises";
|
|
25
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
26
|
+
import pino from "pino";
|
|
27
|
+
import open from "open";
|
|
28
|
+
|
|
29
|
+
// src/auth/session-monitor.ts
|
|
30
|
+
import { EventEmitter } from "events";
|
|
31
|
+
var DEFAULT_CHECK_INTERVAL_MS = 6e4;
|
|
32
|
+
var DEFAULT_WARNING_WINDOW_MS = 5 * 60 * 1e3;
|
|
33
|
+
var SessionMonitor = class extends EventEmitter {
|
|
34
|
+
constructor(options) {
|
|
35
|
+
super();
|
|
36
|
+
this.options = options;
|
|
37
|
+
this.checkIntervalMs = options.checkIntervalMs ?? DEFAULT_CHECK_INTERVAL_MS;
|
|
38
|
+
this.warningWindowMs = options.warningWindowMs ?? DEFAULT_WARNING_WINDOW_MS;
|
|
39
|
+
this.logger = options.logger;
|
|
40
|
+
this.status = this.createStatus(null, "reauth_required");
|
|
41
|
+
}
|
|
42
|
+
options;
|
|
43
|
+
checkIntervalMs;
|
|
44
|
+
warningWindowMs;
|
|
45
|
+
logger;
|
|
46
|
+
interval;
|
|
47
|
+
checkInFlight;
|
|
48
|
+
status;
|
|
49
|
+
on(eventName, listener) {
|
|
50
|
+
return super.on(eventName, listener);
|
|
51
|
+
}
|
|
52
|
+
emit(eventName, ...args) {
|
|
53
|
+
return super.emit(eventName, ...args);
|
|
54
|
+
}
|
|
55
|
+
start() {
|
|
56
|
+
if (this.interval) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
void this.checkNow();
|
|
60
|
+
this.interval = setInterval(() => {
|
|
61
|
+
void this.checkNow();
|
|
62
|
+
}, this.checkIntervalMs);
|
|
63
|
+
}
|
|
64
|
+
stop() {
|
|
65
|
+
if (!this.interval) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
clearInterval(this.interval);
|
|
69
|
+
this.interval = void 0;
|
|
70
|
+
}
|
|
71
|
+
getStatus() {
|
|
72
|
+
return { ...this.status };
|
|
73
|
+
}
|
|
74
|
+
async checkNow() {
|
|
75
|
+
if (this.checkInFlight) {
|
|
76
|
+
return await this.checkInFlight;
|
|
77
|
+
}
|
|
78
|
+
this.checkInFlight = this.evaluate().finally(() => {
|
|
79
|
+
this.checkInFlight = void 0;
|
|
80
|
+
});
|
|
81
|
+
return await this.checkInFlight;
|
|
82
|
+
}
|
|
83
|
+
async evaluate() {
|
|
84
|
+
const previous = this.status;
|
|
85
|
+
const session = this.options.authProvider.getSession();
|
|
86
|
+
if (!session || !this.options.authProvider.isAuthenticated()) {
|
|
87
|
+
const status = this.updateStatus(this.createStatus(session, "reauth_required"));
|
|
88
|
+
if (previous.state !== status.state || previous.address !== status.address) {
|
|
89
|
+
this.emit("session:reauth_required", { ...status });
|
|
90
|
+
}
|
|
91
|
+
return status;
|
|
92
|
+
}
|
|
93
|
+
const expiresAt = this.options.authProvider.getSessionExpiryMs(session);
|
|
94
|
+
const now = Date.now();
|
|
95
|
+
const expiresInMs = expiresAt === null ? null : expiresAt - now;
|
|
96
|
+
if (expiresInMs !== null && expiresInMs <= 0) {
|
|
97
|
+
const expiredStatus = this.updateStatus(this.createStatus(session, "expired", null, expiresAt, expiresInMs));
|
|
98
|
+
if (previous.state !== expiredStatus.state || previous.expiresAt !== expiredStatus.expiresAt) {
|
|
99
|
+
this.emit("session:expired", { ...expiredStatus });
|
|
100
|
+
}
|
|
101
|
+
await this.options.authProvider.clearSession(session);
|
|
102
|
+
const reauthStatus = this.updateStatus(
|
|
103
|
+
this.createStatus(null, "reauth_required", "Authentication expired. Please re-authenticate via the daemon portal.")
|
|
104
|
+
);
|
|
105
|
+
this.emit("session:reauth_required", { ...reauthStatus });
|
|
106
|
+
this.logger?.warn?.({ expiresAt }, "zkLogin session expired.");
|
|
107
|
+
return reauthStatus;
|
|
108
|
+
}
|
|
109
|
+
if (expiresInMs !== null && expiresInMs <= this.warningWindowMs) {
|
|
110
|
+
const expiringStatus = this.updateStatus(this.createStatus(session, "expiring", null, expiresAt, expiresInMs));
|
|
111
|
+
if (previous.state !== expiringStatus.state || previous.expiresAt !== expiringStatus.expiresAt) {
|
|
112
|
+
this.emit("session:expiring", { ...expiringStatus });
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
const refreshed2 = await this.options.authProvider.refreshSessionIfNeeded(void 0, {
|
|
116
|
+
force: true,
|
|
117
|
+
invalidateOnFailure: true,
|
|
118
|
+
throwOnFailure: true
|
|
119
|
+
});
|
|
120
|
+
if (!refreshed2) {
|
|
121
|
+
const reauthStatus = this.updateStatus(
|
|
122
|
+
this.createStatus(null, "reauth_required", "Authentication expired. Please re-authenticate via the daemon portal.")
|
|
123
|
+
);
|
|
124
|
+
this.emit("session:reauth_required", { ...reauthStatus });
|
|
125
|
+
return reauthStatus;
|
|
126
|
+
}
|
|
127
|
+
const refreshedStatus = this.updateStatus(this.createStatus(refreshed2, "authenticated"));
|
|
128
|
+
this.emit("session:refreshed", { ...refreshedStatus });
|
|
129
|
+
this.logger?.info?.({ expiresAt: refreshedStatus.expiresAt }, "zkLogin session refreshed.");
|
|
130
|
+
return refreshedStatus;
|
|
131
|
+
} catch (error) {
|
|
132
|
+
const detail = error instanceof Error && error.message ? error.message : "Authentication expired. Please re-authenticate via the daemon portal.";
|
|
133
|
+
const reauthStatus = this.updateStatus(this.createStatus(null, "reauth_required", detail));
|
|
134
|
+
this.emit("session:reauth_required", { ...reauthStatus });
|
|
135
|
+
this.logger?.warn?.({ err: error }, "zkLogin session refresh failed.");
|
|
136
|
+
return reauthStatus;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const refreshed = await this.options.authProvider.refreshSessionIfNeeded();
|
|
140
|
+
if (!refreshed) {
|
|
141
|
+
const reauthStatus = this.updateStatus(
|
|
142
|
+
this.createStatus(null, "reauth_required", "Authentication expired. Please re-authenticate via the daemon portal.")
|
|
143
|
+
);
|
|
144
|
+
if (previous.state !== reauthStatus.state || previous.address !== reauthStatus.address) {
|
|
145
|
+
this.emit("session:reauth_required", { ...reauthStatus });
|
|
146
|
+
}
|
|
147
|
+
return reauthStatus;
|
|
148
|
+
}
|
|
149
|
+
if (refreshed.jwt !== session.jwt || refreshed.updatedAt !== session.updatedAt) {
|
|
150
|
+
const refreshedStatus = this.updateStatus(this.createStatus(refreshed, "authenticated"));
|
|
151
|
+
this.emit("session:refreshed", { ...refreshedStatus });
|
|
152
|
+
return refreshedStatus;
|
|
153
|
+
}
|
|
154
|
+
return this.updateStatus(this.createStatus(refreshed, "authenticated"));
|
|
155
|
+
}
|
|
156
|
+
createStatus(session, state, lastError = null, expiresAt = session ? this.options.authProvider.getSessionExpiryMs(session) : null, expiresInMs = expiresAt === null ? null : expiresAt - Date.now()) {
|
|
157
|
+
return {
|
|
158
|
+
authMode: this.options.authProvider.mode,
|
|
159
|
+
authenticated: state === "authenticated" || state === "expiring",
|
|
160
|
+
state,
|
|
161
|
+
address: session?.address ?? null,
|
|
162
|
+
expiresAt,
|
|
163
|
+
expiresInMs,
|
|
164
|
+
refreshAvailable: Boolean(session?.refreshToken),
|
|
165
|
+
lastError,
|
|
166
|
+
updatedAt: Date.now()
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
updateStatus(nextStatus) {
|
|
170
|
+
this.status = nextStatus;
|
|
171
|
+
return nextStatus;
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
// src/lifecycle.ts
|
|
176
|
+
import { chmod, mkdir, readFile, rm, writeFile } from "fs/promises";
|
|
177
|
+
import { dirname } from "path";
|
|
178
|
+
var DaemonLifecycle = class {
|
|
179
|
+
constructor(pidFilePath) {
|
|
180
|
+
this.pidFilePath = pidFilePath;
|
|
181
|
+
}
|
|
182
|
+
pidFilePath;
|
|
183
|
+
async acquireLock() {
|
|
184
|
+
await mkdir(dirname(this.pidFilePath), { recursive: true, mode: 448 });
|
|
185
|
+
try {
|
|
186
|
+
await writePrivateFile(this.pidFilePath, `${process.pid}
|
|
187
|
+
`);
|
|
188
|
+
return;
|
|
189
|
+
} catch (error) {
|
|
190
|
+
if (!isErrnoException(error, "EEXIST")) {
|
|
191
|
+
throw error;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (await this.isRunning()) {
|
|
195
|
+
throw new Error(`Daemon is already running (pid file: ${this.pidFilePath}).`);
|
|
196
|
+
}
|
|
197
|
+
await rm(this.pidFilePath, { force: true });
|
|
198
|
+
await writePrivateFile(this.pidFilePath, `${process.pid}
|
|
199
|
+
`);
|
|
200
|
+
}
|
|
201
|
+
async isRunning() {
|
|
202
|
+
try {
|
|
203
|
+
const contents = await readFile(this.pidFilePath, "utf8");
|
|
204
|
+
const pid = Number.parseInt(contents.trim(), 10);
|
|
205
|
+
if (!Number.isInteger(pid) || pid <= 0) {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
if (isProcessRunning(pid)) {
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
await rm(this.pidFilePath, { force: true });
|
|
212
|
+
return false;
|
|
213
|
+
} catch (error) {
|
|
214
|
+
if (isErrnoException(error, "ENOENT")) {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
throw error;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
async releaseLock() {
|
|
221
|
+
await rm(this.pidFilePath, { force: true });
|
|
222
|
+
}
|
|
223
|
+
setupSignalHandlers(onShutdown) {
|
|
224
|
+
let shuttingDown = false;
|
|
225
|
+
const handleSignal = (signal) => {
|
|
226
|
+
if (shuttingDown) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
shuttingDown = true;
|
|
230
|
+
void (async () => {
|
|
231
|
+
try {
|
|
232
|
+
await onShutdown();
|
|
233
|
+
process.exit(0);
|
|
234
|
+
} catch (error) {
|
|
235
|
+
console.error(`Failed to shut down cleanly after ${signal}:`, error);
|
|
236
|
+
process.exit(1);
|
|
237
|
+
}
|
|
238
|
+
})();
|
|
239
|
+
};
|
|
240
|
+
for (const signal of ["SIGINT", "SIGTERM"]) {
|
|
241
|
+
process.once(signal, () => {
|
|
242
|
+
handleSignal(signal);
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
async function writePrivateFile(path, contents) {
|
|
248
|
+
await writeFile(path, contents, { encoding: "utf8", flag: "wx", mode: 384 });
|
|
249
|
+
await chmod(path, 384);
|
|
250
|
+
}
|
|
251
|
+
function isProcessRunning(pid) {
|
|
252
|
+
try {
|
|
253
|
+
process.kill(pid, 0);
|
|
254
|
+
return true;
|
|
255
|
+
} catch (error) {
|
|
256
|
+
return !isErrnoException(error, "ESRCH");
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function isErrnoException(error, code) {
|
|
260
|
+
return error instanceof Error && "code" in error && error.code === code;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// src/mcp/tool-context.ts
|
|
264
|
+
import { join } from "path";
|
|
265
|
+
import {
|
|
266
|
+
DisputeClient,
|
|
267
|
+
MarketplaceClient,
|
|
268
|
+
PaymentRailSelector,
|
|
269
|
+
RelayRegistryClient,
|
|
270
|
+
ReputationEventPublisher,
|
|
271
|
+
ReputationStore,
|
|
272
|
+
StakingClient
|
|
273
|
+
} from "@hivemind-os/collective-core";
|
|
274
|
+
function buildMeshToolContext(state, dataDir) {
|
|
275
|
+
const base = {
|
|
276
|
+
did: state.did,
|
|
277
|
+
keypair: state.keypair,
|
|
278
|
+
suiClient: state.suiClient,
|
|
279
|
+
registryClient: state.registryClient,
|
|
280
|
+
taskClient: state.taskClient,
|
|
281
|
+
agentCache: state.agentCache,
|
|
282
|
+
blobStore: state.blobStore,
|
|
283
|
+
spendingPolicy: state.spendingPolicy,
|
|
284
|
+
networkConfig: state.network,
|
|
285
|
+
encryption: state.encryption,
|
|
286
|
+
authProvider: state.authProvider,
|
|
287
|
+
relayAuthProvider: state.relayAuthProvider,
|
|
288
|
+
x402Client: state.x402Client
|
|
289
|
+
};
|
|
290
|
+
defineLazy(base, "stakingClient", () => new StakingClient(state.suiClient, { packageId: state.network.packageId }));
|
|
291
|
+
defineLazy(base, "disputeClient", () => new DisputeClient(state.suiClient, { packageId: state.network.packageId }));
|
|
292
|
+
defineLazy(base, "marketplaceClient", () => new MarketplaceClient(state.suiClient, state.network));
|
|
293
|
+
defineLazy(base, "relayRegistryClient", () => new RelayRegistryClient(state.suiClient, { packageId: state.network.packageId }));
|
|
294
|
+
defineLazy(base, "paymentRailSelector", () => new PaymentRailSelector());
|
|
295
|
+
defineLazy(base, "reputationPublisher", () => new ReputationEventPublisher(state.blobStore, state.authProvider));
|
|
296
|
+
defineLazy(base, "reputationStore", () => new ReputationStore(join(dataDir, "reputation.sqlite")));
|
|
297
|
+
return base;
|
|
298
|
+
}
|
|
299
|
+
function defineLazy(obj, key, factory) {
|
|
300
|
+
let cached;
|
|
301
|
+
Object.defineProperty(obj, key, {
|
|
302
|
+
configurable: true,
|
|
303
|
+
enumerable: true,
|
|
304
|
+
get() {
|
|
305
|
+
if (cached === void 0) {
|
|
306
|
+
cached = factory();
|
|
307
|
+
}
|
|
308
|
+
return cached;
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// src/index.ts
|
|
314
|
+
async function main() {
|
|
315
|
+
const configPath = getConfigPath();
|
|
316
|
+
const config = loadConfig(configPath);
|
|
317
|
+
if (config.daemon.logFile) {
|
|
318
|
+
await mkdir2(dirname2(config.daemon.logFile), { recursive: true });
|
|
319
|
+
}
|
|
320
|
+
const destination = config.daemon.logFile ? pino.destination(config.daemon.logFile) : void 0;
|
|
321
|
+
const logger = pino(
|
|
322
|
+
{
|
|
323
|
+
name: "@hivemind-os/collective-daemon",
|
|
324
|
+
level: config.daemon.logLevel
|
|
325
|
+
},
|
|
326
|
+
destination
|
|
327
|
+
);
|
|
328
|
+
const lifecycle = new DaemonLifecycle(config.daemon.pidFile);
|
|
329
|
+
if (await lifecycle.isRunning()) {
|
|
330
|
+
logger.info("Daemon is already running.");
|
|
331
|
+
process.exit(0);
|
|
332
|
+
}
|
|
333
|
+
let state;
|
|
334
|
+
let ipcServer;
|
|
335
|
+
let providerRuntime;
|
|
336
|
+
let setupPortal;
|
|
337
|
+
let portal;
|
|
338
|
+
let sessionMonitor;
|
|
339
|
+
let reauthPortalOpen = false;
|
|
340
|
+
try {
|
|
341
|
+
await lifecycle.acquireLock();
|
|
342
|
+
const identityContext = await createDaemonIdentityContext(config);
|
|
343
|
+
const zkloginProvider = config.auth.mode === "zklogin" ? identityContext.authProvider : void 0;
|
|
344
|
+
sessionMonitor = zkloginProvider ? new SessionMonitor({
|
|
345
|
+
authProvider: zkloginProvider,
|
|
346
|
+
logger
|
|
347
|
+
}) : void 0;
|
|
348
|
+
if (zkloginProvider && !zkloginProvider.isAuthenticated()) {
|
|
349
|
+
setupPortal = new PortalServer({
|
|
350
|
+
config,
|
|
351
|
+
configPath,
|
|
352
|
+
authProvider: zkloginProvider,
|
|
353
|
+
logger
|
|
354
|
+
});
|
|
355
|
+
const portalUrl = await setupPortal.start();
|
|
356
|
+
logger.info({ portalUrl }, "Waiting for zkLogin onboarding");
|
|
357
|
+
await openPortalUrl(portalUrl, logger, "continue onboarding");
|
|
358
|
+
await setupPortal.waitForAuth();
|
|
359
|
+
await setupPortal.stop();
|
|
360
|
+
setupPortal = void 0;
|
|
361
|
+
}
|
|
362
|
+
const daemonState = await DaemonState.create(config, identityContext);
|
|
363
|
+
state = daemonState;
|
|
364
|
+
daemonState.setProviderRunning(false);
|
|
365
|
+
logger.info({ did: daemonState.did }, "Daemon state initialized");
|
|
366
|
+
const getAuthStatus = () => sessionMonitor?.getStatus() ?? createFallbackAuthStatus(daemonState);
|
|
367
|
+
const openReauthPortal = async (force = false) => {
|
|
368
|
+
const portalUrl = portal?.getReauthUrl() ?? null;
|
|
369
|
+
if (!portalUrl) {
|
|
370
|
+
return {
|
|
371
|
+
portalUrl: null,
|
|
372
|
+
browserOpened: false,
|
|
373
|
+
status: getAuthStatus()
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
if (!force && reauthPortalOpen) {
|
|
377
|
+
return {
|
|
378
|
+
portalUrl,
|
|
379
|
+
browserOpened: false,
|
|
380
|
+
status: getAuthStatus()
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
const browserOpened = await openPortalUrl(portalUrl, logger, "re-authenticate");
|
|
384
|
+
reauthPortalOpen ||= browserOpened;
|
|
385
|
+
return {
|
|
386
|
+
portalUrl,
|
|
387
|
+
browserOpened,
|
|
388
|
+
status: getAuthStatus()
|
|
389
|
+
};
|
|
390
|
+
};
|
|
391
|
+
if (zkloginProvider) {
|
|
392
|
+
portal = new PortalServer({
|
|
393
|
+
config,
|
|
394
|
+
configPath,
|
|
395
|
+
authProvider: zkloginProvider,
|
|
396
|
+
state: daemonState,
|
|
397
|
+
logger,
|
|
398
|
+
getAuthStatus
|
|
399
|
+
});
|
|
400
|
+
const portalUrl = await portal.start();
|
|
401
|
+
logger.info({ portalUrl }, "Portal server listening");
|
|
402
|
+
}
|
|
403
|
+
ipcServer = new IpcServer(config.daemon.ipcPath, daemonState, {
|
|
404
|
+
getAuthStatus,
|
|
405
|
+
triggerReauth: () => openReauthPortal(true)
|
|
406
|
+
});
|
|
407
|
+
ipcServer.toolContext = buildMeshToolContext(daemonState, config.daemon.dataDir);
|
|
408
|
+
await ipcServer.start();
|
|
409
|
+
logger.info({ ipcPath: config.daemon.ipcPath }, "IPC server listening");
|
|
410
|
+
if (sessionMonitor) {
|
|
411
|
+
sessionMonitor.on("session:expiring", (status) => {
|
|
412
|
+
ipcServer?.notifyAuthStatusChanged(status);
|
|
413
|
+
});
|
|
414
|
+
sessionMonitor.on("session:expired", async (status) => {
|
|
415
|
+
ipcServer?.notifyAuthStatusChanged(status);
|
|
416
|
+
await openReauthPortal(false);
|
|
417
|
+
});
|
|
418
|
+
sessionMonitor.on("session:refreshed", (status) => {
|
|
419
|
+
reauthPortalOpen = false;
|
|
420
|
+
ipcServer?.notifyAuthStatusChanged(status);
|
|
421
|
+
});
|
|
422
|
+
sessionMonitor.on("session:reauth_required", async (status) => {
|
|
423
|
+
ipcServer?.notifyAuthStatusChanged(status);
|
|
424
|
+
await openReauthPortal(false);
|
|
425
|
+
});
|
|
426
|
+
sessionMonitor.start();
|
|
427
|
+
}
|
|
428
|
+
const providerConfig = loadProviderConfig(config);
|
|
429
|
+
if (providerConfig?.enabled) {
|
|
430
|
+
const ipcRef = ipcServer;
|
|
431
|
+
providerRuntime = new ProviderRuntime({
|
|
432
|
+
state: daemonState,
|
|
433
|
+
providerConfig,
|
|
434
|
+
cursorDbPath: join2(config.daemon.dataDir, "provider-cursors.db"),
|
|
435
|
+
relayConfig: config.relay,
|
|
436
|
+
mcpSamplingFn: ipcRef ? async (appName, params) => {
|
|
437
|
+
const server = ipcRef.getMcpServerForApp(appName);
|
|
438
|
+
if (!server) {
|
|
439
|
+
throw new Error(`No MCP client connected with appName "${appName}"`);
|
|
440
|
+
}
|
|
441
|
+
return server.createMessage(params);
|
|
442
|
+
} : void 0,
|
|
443
|
+
broadcastNotification: ipcRef ? (method, params) => ipcRef.broadcastNotification(method, params) : void 0
|
|
444
|
+
});
|
|
445
|
+
await providerRuntime.start();
|
|
446
|
+
daemonState.setProviderRunning(true);
|
|
447
|
+
logger.info("Provider runtime started");
|
|
448
|
+
}
|
|
449
|
+
lifecycle.setupSignalHandlers(async () => {
|
|
450
|
+
logger.info("Shutting down...");
|
|
451
|
+
sessionMonitor?.stop();
|
|
452
|
+
state?.setProviderRunning(false);
|
|
453
|
+
await providerRuntime?.stop();
|
|
454
|
+
await ipcServer?.stop();
|
|
455
|
+
await portal?.stop();
|
|
456
|
+
await state?.shutdown();
|
|
457
|
+
await lifecycle.releaseLock();
|
|
458
|
+
logger.info("Daemon stopped");
|
|
459
|
+
});
|
|
460
|
+
} catch (error) {
|
|
461
|
+
sessionMonitor?.stop();
|
|
462
|
+
state?.setProviderRunning(false);
|
|
463
|
+
await cleanupWithLogging(logger, "provider runtime", () => providerRuntime?.stop());
|
|
464
|
+
await cleanupWithLogging(logger, "IPC server", () => ipcServer?.stop());
|
|
465
|
+
await cleanupWithLogging(logger, "setup portal server", () => setupPortal?.stop());
|
|
466
|
+
await cleanupWithLogging(logger, "portal server", () => portal?.stop());
|
|
467
|
+
await cleanupWithLogging(logger, "daemon state", () => state?.shutdown());
|
|
468
|
+
await cleanupWithLogging(logger, "daemon lock", () => lifecycle.releaseLock());
|
|
469
|
+
throw error;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
async function cleanupWithLogging(logger, label, cleanup) {
|
|
473
|
+
try {
|
|
474
|
+
await cleanup();
|
|
475
|
+
} catch (error) {
|
|
476
|
+
logger.warn({ err: error }, `Failed to clean up ${label}.`);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
function createFallbackAuthStatus(state) {
|
|
480
|
+
const authenticated = state.authProvider.isAuthenticated();
|
|
481
|
+
return {
|
|
482
|
+
authMode: state.authProvider.mode,
|
|
483
|
+
authenticated,
|
|
484
|
+
state: authenticated ? "authenticated" : "reauth_required",
|
|
485
|
+
address: authenticated ? state.address : null,
|
|
486
|
+
expiresAt: null,
|
|
487
|
+
expiresInMs: null,
|
|
488
|
+
refreshAvailable: false,
|
|
489
|
+
lastError: null,
|
|
490
|
+
updatedAt: Date.now()
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
async function openPortalUrl(portalUrl, logger, action) {
|
|
494
|
+
if (isHeadlessEnvironment()) {
|
|
495
|
+
logger.warn({ portalUrl }, `Headless environment detected. Open the portal URL manually to ${action}.`);
|
|
496
|
+
return false;
|
|
497
|
+
}
|
|
498
|
+
try {
|
|
499
|
+
await open(portalUrl);
|
|
500
|
+
return true;
|
|
501
|
+
} catch (error) {
|
|
502
|
+
logger.warn({ err: error, portalUrl }, "Failed to open browser automatically.");
|
|
503
|
+
logger.info({ portalUrl }, `Open the portal URL manually to ${action}.`);
|
|
504
|
+
return false;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
function isHeadlessEnvironment() {
|
|
508
|
+
if (process.env.COLLECTIVE_HEADLESS === "1" || process.env.CI === "true") {
|
|
509
|
+
return true;
|
|
510
|
+
}
|
|
511
|
+
if (process.env.SSH_CONNECTION || process.env.SSH_TTY) {
|
|
512
|
+
return true;
|
|
513
|
+
}
|
|
514
|
+
return process.platform === "linux" && !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY;
|
|
515
|
+
}
|
|
516
|
+
main().catch((error) => {
|
|
517
|
+
console.error("Fatal:", error);
|
|
518
|
+
process.exit(1);
|
|
519
|
+
});
|
|
520
|
+
export {
|
|
521
|
+
main
|
|
522
|
+
};
|
|
523
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/auth/session-monitor.ts","../src/lifecycle.ts","../src/mcp/tool-context.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { mkdir } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\n\nimport pino from 'pino';\n\nimport open from 'open';\n\nimport type { DaemonAuthStatus, SessionMonitorAuthProvider } from './auth/session-monitor.js';\nimport { SessionMonitor } from './auth/session-monitor.js';\nimport { getConfigPath, loadConfig } from './config.js';\nimport { IpcServer } from './ipc/server.js';\nimport { DaemonLifecycle } from './lifecycle.js';\nimport { buildMeshToolContext } from './mcp/tool-context.js';\nimport { PortalServer, type PortalAuthProvider } from './portal/server.js';\nimport { loadProviderConfig, ProviderRuntime } from './provider/index.js';\nimport { createDaemonIdentityContext, DaemonState } from './state.js';\n\nexport async function main(): Promise<void> {\n const configPath = getConfigPath();\n const config = loadConfig(configPath);\n\n if (config.daemon.logFile) {\n await mkdir(dirname(config.daemon.logFile), { recursive: true });\n }\n\n const destination = config.daemon.logFile ? pino.destination(config.daemon.logFile) : undefined;\n const logger = pino(\n {\n name: '@hivemind-os/collective-daemon',\n level: config.daemon.logLevel,\n },\n destination,\n );\n const lifecycle = new DaemonLifecycle(config.daemon.pidFile);\n\n if (await lifecycle.isRunning()) {\n logger.info('Daemon is already running.');\n process.exit(0);\n }\n\n let state: DaemonState | undefined;\n let ipcServer: IpcServer | undefined;\n let providerRuntime: ProviderRuntime | undefined;\n let setupPortal: PortalServer | undefined;\n let portal: PortalServer | undefined;\n let sessionMonitor: SessionMonitor | undefined;\n let reauthPortalOpen = false;\n\n try {\n await lifecycle.acquireLock();\n\n const identityContext = await createDaemonIdentityContext(config);\n const zkloginProvider =\n config.auth.mode === 'zklogin' ? (identityContext.authProvider as PortalAuthProvider & SessionMonitorAuthProvider) : undefined;\n sessionMonitor = zkloginProvider\n ? new SessionMonitor({\n authProvider: zkloginProvider,\n logger,\n })\n : undefined;\n\n if (zkloginProvider && !zkloginProvider.isAuthenticated()) {\n setupPortal = new PortalServer({\n config,\n configPath,\n authProvider: zkloginProvider,\n logger,\n });\n const portalUrl = await setupPortal.start();\n logger.info({ portalUrl }, 'Waiting for zkLogin onboarding');\n await openPortalUrl(portalUrl, logger, 'continue onboarding');\n await setupPortal.waitForAuth();\n await setupPortal.stop();\n setupPortal = undefined;\n }\n\n const daemonState = await DaemonState.create(config, identityContext);\n state = daemonState;\n daemonState.setProviderRunning(false);\n logger.info({ did: daemonState.did }, 'Daemon state initialized');\n\n const getAuthStatus = () => sessionMonitor?.getStatus() ?? createFallbackAuthStatus(daemonState);\n\n const openReauthPortal = async (force = false) => {\n const portalUrl = portal?.getReauthUrl() ?? null;\n if (!portalUrl) {\n return {\n portalUrl: null,\n browserOpened: false,\n status: getAuthStatus(),\n };\n }\n\n if (!force && reauthPortalOpen) {\n return {\n portalUrl,\n browserOpened: false,\n status: getAuthStatus(),\n };\n }\n\n const browserOpened = await openPortalUrl(portalUrl, logger, 're-authenticate');\n reauthPortalOpen ||= browserOpened;\n return {\n portalUrl,\n browserOpened,\n status: getAuthStatus(),\n };\n };\n\n if (zkloginProvider) {\n portal = new PortalServer({\n config,\n configPath,\n authProvider: zkloginProvider,\n state: daemonState,\n logger,\n getAuthStatus,\n });\n const portalUrl = await portal.start();\n logger.info({ portalUrl }, 'Portal server listening');\n }\n\n ipcServer = new IpcServer(config.daemon.ipcPath, daemonState, {\n getAuthStatus,\n triggerReauth: () => openReauthPortal(true),\n });\n ipcServer.toolContext = buildMeshToolContext(daemonState, config.daemon.dataDir);\n await ipcServer.start();\n logger.info({ ipcPath: config.daemon.ipcPath }, 'IPC server listening');\n\n if (sessionMonitor) {\n sessionMonitor.on('session:expiring', (status) => {\n ipcServer?.notifyAuthStatusChanged(status);\n });\n sessionMonitor.on('session:expired', async (status) => {\n ipcServer?.notifyAuthStatusChanged(status);\n await openReauthPortal(false);\n });\n sessionMonitor.on('session:refreshed', (status) => {\n reauthPortalOpen = false;\n ipcServer?.notifyAuthStatusChanged(status);\n });\n sessionMonitor.on('session:reauth_required', async (status) => {\n ipcServer?.notifyAuthStatusChanged(status);\n await openReauthPortal(false);\n });\n sessionMonitor.start();\n }\n\n const providerConfig = loadProviderConfig(config);\n if (providerConfig?.enabled) {\n const ipcRef = ipcServer;\n providerRuntime = new ProviderRuntime({\n state: daemonState,\n providerConfig,\n cursorDbPath: join(config.daemon.dataDir, 'provider-cursors.db'),\n relayConfig: config.relay,\n mcpSamplingFn: ipcRef\n ? async (appName, params) => {\n const server = ipcRef.getMcpServerForApp(appName);\n if (!server) {\n throw new Error(`No MCP client connected with appName \"${appName}\"`);\n }\n return server.createMessage(params);\n }\n : undefined,\n broadcastNotification: ipcRef\n ? (method, params) => ipcRef.broadcastNotification(method, params)\n : undefined,\n });\n await providerRuntime.start();\n daemonState.setProviderRunning(true);\n logger.info('Provider runtime started');\n }\n\n lifecycle.setupSignalHandlers(async () => {\n logger.info('Shutting down...');\n sessionMonitor?.stop();\n state?.setProviderRunning(false);\n await providerRuntime?.stop();\n await ipcServer?.stop();\n await portal?.stop();\n await state?.shutdown();\n await lifecycle.releaseLock();\n logger.info('Daemon stopped');\n });\n } catch (error) {\n sessionMonitor?.stop();\n state?.setProviderRunning(false);\n await cleanupWithLogging(logger, 'provider runtime', () => providerRuntime?.stop());\n await cleanupWithLogging(logger, 'IPC server', () => ipcServer?.stop());\n await cleanupWithLogging(logger, 'setup portal server', () => setupPortal?.stop());\n await cleanupWithLogging(logger, 'portal server', () => portal?.stop());\n await cleanupWithLogging(logger, 'daemon state', () => state?.shutdown());\n await cleanupWithLogging(logger, 'daemon lock', () => lifecycle.releaseLock());\n throw error;\n }\n}\n\nasync function cleanupWithLogging(\n logger: { warn: (bindings: { err: unknown }, message: string) => void },\n label: string,\n cleanup: () => Promise<void> | undefined,\n): Promise<void> {\n try {\n await cleanup();\n } catch (error) {\n logger.warn({ err: error }, `Failed to clean up ${label}.`);\n }\n}\n\nfunction createFallbackAuthStatus(state: DaemonState): DaemonAuthStatus {\n const authenticated = state.authProvider.isAuthenticated();\n return {\n authMode: state.authProvider.mode,\n authenticated,\n state: authenticated ? 'authenticated' : 'reauth_required',\n address: authenticated ? state.address : null,\n expiresAt: null,\n expiresInMs: null,\n refreshAvailable: false,\n lastError: null,\n updatedAt: Date.now(),\n };\n}\n\nasync function openPortalUrl(\n portalUrl: string,\n logger: {\n info: (bindings: { portalUrl: string }, message: string) => void;\n warn: (bindings: { portalUrl: string; err?: unknown }, message: string) => void;\n },\n action: string,\n): Promise<boolean> {\n if (isHeadlessEnvironment()) {\n logger.warn({ portalUrl }, `Headless environment detected. Open the portal URL manually to ${action}.`);\n return false;\n }\n\n try {\n await open(portalUrl);\n return true;\n } catch (error) {\n logger.warn({ err: error, portalUrl }, 'Failed to open browser automatically.');\n logger.info({ portalUrl }, `Open the portal URL manually to ${action}.`);\n return false;\n }\n}\n\nfunction isHeadlessEnvironment(): boolean {\n if (process.env.COLLECTIVE_HEADLESS === '1' || process.env.CI === 'true') {\n return true;\n }\n\n if (process.env.SSH_CONNECTION || process.env.SSH_TTY) {\n return true;\n }\n\n return process.platform === 'linux' && !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY;\n}\n\nmain().catch((error) => {\n console.error('Fatal:', error);\n process.exit(1);\n});\n","import { EventEmitter } from 'node:events';\n\nimport type { AuthMode, StoredZkLoginSession } from '@hivemind-os/collective-core';\n\nexport type DaemonAuthState = 'authenticated' | 'expiring' | 'expired' | 'reauth_required';\n\nexport interface DaemonAuthStatus {\n authMode: AuthMode;\n authenticated: boolean;\n state: DaemonAuthState;\n address: string | null;\n expiresAt: number | null;\n expiresInMs: number | null;\n refreshAvailable: boolean;\n lastError: string | null;\n updatedAt: number;\n}\n\nexport interface SessionMonitorAuthProvider {\n mode: 'zklogin';\n isAuthenticated(): boolean;\n getSession(): StoredZkLoginSession | null;\n getSessionExpiryMs(session?: StoredZkLoginSession | null): number | null;\n refreshSessionIfNeeded(\n currentEpoch?: number,\n options?: { force?: boolean; invalidateOnFailure?: boolean; throwOnFailure?: boolean },\n ): Promise<StoredZkLoginSession | null>;\n clearSession(session?: StoredZkLoginSession | null): Promise<void>;\n}\n\nexport interface SessionMonitorOptions {\n authProvider: SessionMonitorAuthProvider;\n checkIntervalMs?: number;\n warningWindowMs?: number;\n logger?: {\n debug?: (payload: unknown, message?: string) => void;\n info?: (payload: unknown, message?: string) => void;\n warn?: (payload: unknown, message?: string) => void;\n };\n}\n\ntype SessionMonitorEvents = {\n 'session:expiring': [DaemonAuthStatus];\n 'session:expired': [DaemonAuthStatus];\n 'session:refreshed': [DaemonAuthStatus];\n 'session:reauth_required': [DaemonAuthStatus];\n};\n\nconst DEFAULT_CHECK_INTERVAL_MS = 60_000;\nconst DEFAULT_WARNING_WINDOW_MS = 5 * 60 * 1000;\n\nexport class SessionMonitor extends EventEmitter {\n private readonly checkIntervalMs: number;\n private readonly warningWindowMs: number;\n private readonly logger;\n private interval?: ReturnType<typeof setInterval>;\n private checkInFlight?: Promise<DaemonAuthStatus>;\n private status: DaemonAuthStatus;\n\n constructor(private readonly options: SessionMonitorOptions) {\n super();\n this.checkIntervalMs = options.checkIntervalMs ?? DEFAULT_CHECK_INTERVAL_MS;\n this.warningWindowMs = options.warningWindowMs ?? DEFAULT_WARNING_WINDOW_MS;\n this.logger = options.logger;\n this.status = this.createStatus(null, 'reauth_required');\n }\n\n override on<EventName extends keyof SessionMonitorEvents>(\n eventName: EventName,\n listener: (...args: SessionMonitorEvents[EventName]) => void,\n ): this {\n return super.on(eventName, listener);\n }\n\n override emit<EventName extends keyof SessionMonitorEvents>(eventName: EventName, ...args: SessionMonitorEvents[EventName]): boolean {\n return super.emit(eventName, ...args);\n }\n\n start(): void {\n if (this.interval) {\n return;\n }\n\n void this.checkNow();\n this.interval = setInterval(() => {\n void this.checkNow();\n }, this.checkIntervalMs);\n }\n\n stop(): void {\n if (!this.interval) {\n return;\n }\n\n clearInterval(this.interval);\n this.interval = undefined;\n }\n\n getStatus(): DaemonAuthStatus {\n return { ...this.status };\n }\n\n async checkNow(): Promise<DaemonAuthStatus> {\n if (this.checkInFlight) {\n return await this.checkInFlight;\n }\n\n this.checkInFlight = this.evaluate().finally(() => {\n this.checkInFlight = undefined;\n });\n return await this.checkInFlight;\n }\n\n private async evaluate(): Promise<DaemonAuthStatus> {\n const previous = this.status;\n const session = this.options.authProvider.getSession();\n if (!session || !this.options.authProvider.isAuthenticated()) {\n const status = this.updateStatus(this.createStatus(session, 'reauth_required'));\n if (previous.state !== status.state || previous.address !== status.address) {\n this.emit('session:reauth_required', { ...status });\n }\n return status;\n }\n\n const expiresAt = this.options.authProvider.getSessionExpiryMs(session);\n const now = Date.now();\n const expiresInMs = expiresAt === null ? null : expiresAt - now;\n\n if (expiresInMs !== null && expiresInMs <= 0) {\n const expiredStatus = this.updateStatus(this.createStatus(session, 'expired', null, expiresAt, expiresInMs));\n if (previous.state !== expiredStatus.state || previous.expiresAt !== expiredStatus.expiresAt) {\n this.emit('session:expired', { ...expiredStatus });\n }\n await this.options.authProvider.clearSession(session);\n const reauthStatus = this.updateStatus(\n this.createStatus(null, 'reauth_required', 'Authentication expired. Please re-authenticate via the daemon portal.'),\n );\n this.emit('session:reauth_required', { ...reauthStatus });\n this.logger?.warn?.({ expiresAt }, 'zkLogin session expired.');\n return reauthStatus;\n }\n\n if (expiresInMs !== null && expiresInMs <= this.warningWindowMs) {\n const expiringStatus = this.updateStatus(this.createStatus(session, 'expiring', null, expiresAt, expiresInMs));\n if (previous.state !== expiringStatus.state || previous.expiresAt !== expiringStatus.expiresAt) {\n this.emit('session:expiring', { ...expiringStatus });\n }\n\n try {\n const refreshed = await this.options.authProvider.refreshSessionIfNeeded(undefined, {\n force: true,\n invalidateOnFailure: true,\n throwOnFailure: true,\n });\n if (!refreshed) {\n const reauthStatus = this.updateStatus(\n this.createStatus(null, 'reauth_required', 'Authentication expired. Please re-authenticate via the daemon portal.'),\n );\n this.emit('session:reauth_required', { ...reauthStatus });\n return reauthStatus;\n }\n\n const refreshedStatus = this.updateStatus(this.createStatus(refreshed, 'authenticated'));\n this.emit('session:refreshed', { ...refreshedStatus });\n this.logger?.info?.({ expiresAt: refreshedStatus.expiresAt }, 'zkLogin session refreshed.');\n return refreshedStatus;\n } catch (error) {\n const detail = error instanceof Error && error.message ? error.message : 'Authentication expired. Please re-authenticate via the daemon portal.';\n const reauthStatus = this.updateStatus(this.createStatus(null, 'reauth_required', detail));\n this.emit('session:reauth_required', { ...reauthStatus });\n this.logger?.warn?.({ err: error }, 'zkLogin session refresh failed.');\n return reauthStatus;\n }\n }\n\n const refreshed = await this.options.authProvider.refreshSessionIfNeeded();\n if (!refreshed) {\n const reauthStatus = this.updateStatus(\n this.createStatus(null, 'reauth_required', 'Authentication expired. Please re-authenticate via the daemon portal.'),\n );\n if (previous.state !== reauthStatus.state || previous.address !== reauthStatus.address) {\n this.emit('session:reauth_required', { ...reauthStatus });\n }\n return reauthStatus;\n }\n\n if (refreshed.jwt !== session.jwt || refreshed.updatedAt !== session.updatedAt) {\n const refreshedStatus = this.updateStatus(this.createStatus(refreshed, 'authenticated'));\n this.emit('session:refreshed', { ...refreshedStatus });\n return refreshedStatus;\n }\n\n return this.updateStatus(this.createStatus(refreshed, 'authenticated'));\n }\n\n private createStatus(\n session: StoredZkLoginSession | null,\n state: DaemonAuthState,\n lastError: string | null = null,\n expiresAt = session ? this.options.authProvider.getSessionExpiryMs(session) : null,\n expiresInMs = expiresAt === null ? null : expiresAt - Date.now(),\n ): DaemonAuthStatus {\n return {\n authMode: this.options.authProvider.mode,\n authenticated: state === 'authenticated' || state === 'expiring',\n state,\n address: session?.address ?? null,\n expiresAt,\n expiresInMs,\n refreshAvailable: Boolean(session?.refreshToken),\n lastError,\n updatedAt: Date.now(),\n };\n }\n\n private updateStatus(nextStatus: DaemonAuthStatus): DaemonAuthStatus {\n this.status = nextStatus;\n return nextStatus;\n }\n}\n","import { chmod, mkdir, readFile, rm, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\n\nexport class DaemonLifecycle {\n constructor(private readonly pidFilePath: string) {}\n\n async acquireLock(): Promise<void> {\n await mkdir(dirname(this.pidFilePath), { recursive: true, mode: 0o700 });\n\n try {\n await writePrivateFile(this.pidFilePath, `${process.pid}\\n`);\n return;\n } catch (error) {\n if (!isErrnoException(error, 'EEXIST')) {\n throw error;\n }\n }\n\n if (await this.isRunning()) {\n throw new Error(`Daemon is already running (pid file: ${this.pidFilePath}).`);\n }\n\n await rm(this.pidFilePath, { force: true });\n await writePrivateFile(this.pidFilePath, `${process.pid}\\n`);\n }\n\n async isRunning(): Promise<boolean> {\n try {\n const contents = await readFile(this.pidFilePath, 'utf8');\n const pid = Number.parseInt(contents.trim(), 10);\n if (!Number.isInteger(pid) || pid <= 0) {\n return false;\n }\n\n if (isProcessRunning(pid)) {\n return true;\n }\n\n await rm(this.pidFilePath, { force: true });\n return false;\n } catch (error) {\n if (isErrnoException(error, 'ENOENT')) {\n return false;\n }\n\n throw error;\n }\n }\n\n async releaseLock(): Promise<void> {\n await rm(this.pidFilePath, { force: true });\n }\n\n setupSignalHandlers(onShutdown: () => Promise<void>): void {\n let shuttingDown = false;\n\n const handleSignal = (signal: NodeJS.Signals) => {\n if (shuttingDown) {\n return;\n }\n\n shuttingDown = true;\n void (async () => {\n try {\n await onShutdown();\n process.exit(0);\n } catch (error) {\n console.error(`Failed to shut down cleanly after ${signal}:`, error);\n process.exit(1);\n }\n })();\n };\n\n for (const signal of ['SIGINT', 'SIGTERM'] as const) {\n process.once(signal, () => {\n handleSignal(signal);\n });\n }\n }\n}\n\nasync function writePrivateFile(path: string, contents: string): Promise<void> {\n await writeFile(path, contents, { encoding: 'utf8', flag: 'wx', mode: 0o600 });\n await chmod(path, 0o600);\n}\n\nfunction isProcessRunning(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n return !isErrnoException(error, 'ESRCH');\n }\n}\n\nfunction isErrnoException(error: unknown, code: string): error is NodeJS.ErrnoException {\n return error instanceof Error && 'code' in error && error.code === code;\n}\n","import { join } from 'node:path';\n\nimport {\n DisputeClient,\n MarketplaceClient,\n PaymentRailSelector,\n RelayRegistryClient,\n ReputationEventPublisher,\n ReputationStore,\n StakingClient,\n} from '@hivemind-os/collective-core';\nimport type { MeshToolContext } from '@hivemind-os/collective-mcp-server';\n\nimport type { DaemonState } from '../state.js';\n\n/**\n * Build a {@link MeshToolContext} from daemon state so the\n * `@hivemind-os/collective-mcp-server` tool handlers can run inside the daemon.\n *\n * Optional clients are lazily instantiated on first access to avoid\n * allocating resources (SQLite databases, objects) that may never be used.\n */\nexport function buildMeshToolContext(state: DaemonState, dataDir: string): MeshToolContext {\n const base: MeshToolContext = {\n did: state.did,\n keypair: state.keypair,\n suiClient: state.suiClient,\n registryClient: state.registryClient,\n taskClient: state.taskClient,\n agentCache: state.agentCache,\n blobStore: state.blobStore,\n spendingPolicy: state.spendingPolicy,\n networkConfig: state.network,\n encryption: state.encryption,\n authProvider: state.authProvider,\n relayAuthProvider: state.relayAuthProvider,\n x402Client: state.x402Client,\n };\n\n // Lazy getters for optional clients — instantiated on first access\n defineLazy(base, 'stakingClient', () => new StakingClient(state.suiClient, { packageId: state.network.packageId }));\n defineLazy(base, 'disputeClient', () => new DisputeClient(state.suiClient, { packageId: state.network.packageId }));\n defineLazy(base, 'marketplaceClient', () => new MarketplaceClient(state.suiClient, state.network));\n defineLazy(base, 'relayRegistryClient', () => new RelayRegistryClient(state.suiClient, { packageId: state.network.packageId }));\n defineLazy(base, 'paymentRailSelector', () => new PaymentRailSelector());\n defineLazy(base, 'reputationPublisher', () => new ReputationEventPublisher(state.blobStore, state.authProvider));\n defineLazy(base, 'reputationStore', () => new ReputationStore(join(dataDir, 'reputation.sqlite')));\n\n return base;\n}\n\nfunction defineLazy<T extends object, K extends keyof T>(obj: T, key: K, factory: () => T[K]): void {\n let cached: T[K] | undefined;\n Object.defineProperty(obj, key, {\n configurable: true,\n enumerable: true,\n get() {\n if (cached === undefined) {\n cached = factory();\n }\n return cached;\n },\n });\n}\n"],"mappings":"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","names":["mkdir","dirname","join","refreshed","mkdir","dirname","join"]}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { D as DaemonAuthStatus } from '../session-monitor-P9hNAFw4.js';
|
|
2
|
+
import { DaemonStatusBase, DaemonState } from '../state.js';
|
|
3
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
4
|
+
import { MeshToolContext } from '@hivemind-os/collective-mcp-server';
|
|
5
|
+
import { C as ClientValidationResult, P as PipeSecurityStatus } from '../config-SuloXL2_.js';
|
|
6
|
+
import '@hivemind-os/collective-core';
|
|
7
|
+
import '@hivemind-os/collective-types';
|
|
8
|
+
import '@mysten/sui/cryptography';
|
|
9
|
+
import '@mysten/sui/keypairs/ed25519';
|
|
10
|
+
import 'node:fs';
|
|
11
|
+
|
|
12
|
+
interface ConnectedApp {
|
|
13
|
+
connectionId: string;
|
|
14
|
+
appName: string;
|
|
15
|
+
appPid: number;
|
|
16
|
+
profile?: string;
|
|
17
|
+
connectedAt: number;
|
|
18
|
+
}
|
|
19
|
+
interface ConnectedAppMetadata {
|
|
20
|
+
appName: string;
|
|
21
|
+
appPid: number;
|
|
22
|
+
profile?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface DaemonStatusSnapshot extends DaemonStatusBase {
|
|
26
|
+
connectedApps: ConnectedApp[];
|
|
27
|
+
}
|
|
28
|
+
interface IpcServerOptions {
|
|
29
|
+
validateClient?: (metadata: ConnectedAppMetadata) => Promise<ClientValidationResult>;
|
|
30
|
+
verifyPipeSecurity?: (ipcPath: string) => Promise<PipeSecurityStatus>;
|
|
31
|
+
getAuthStatus?: () => DaemonAuthStatus;
|
|
32
|
+
triggerReauth?: () => Promise<{
|
|
33
|
+
portalUrl: string | null;
|
|
34
|
+
browserOpened: boolean;
|
|
35
|
+
status: DaemonAuthStatus;
|
|
36
|
+
}>;
|
|
37
|
+
}
|
|
38
|
+
declare class IpcServer {
|
|
39
|
+
private readonly ipcPath;
|
|
40
|
+
private readonly state;
|
|
41
|
+
private readonly options;
|
|
42
|
+
private server?;
|
|
43
|
+
private readonly connections;
|
|
44
|
+
private readonly connectionRegistry;
|
|
45
|
+
toolContext?: MeshToolContext;
|
|
46
|
+
constructor(ipcPath: string, state: DaemonState, options?: IpcServerOptions);
|
|
47
|
+
start(): Promise<void>;
|
|
48
|
+
stop(): Promise<void>;
|
|
49
|
+
getConnectedApps(): ConnectedApp[];
|
|
50
|
+
getStatus(): DaemonStatusSnapshot;
|
|
51
|
+
getAuthStatus(): DaemonAuthStatus;
|
|
52
|
+
notifyAuthStatusChanged(status?: DaemonAuthStatus): void;
|
|
53
|
+
/**
|
|
54
|
+
* Broadcast a notification to all connected MCP sessions.
|
|
55
|
+
* Used for provider inbound task notifications and other system-wide events.
|
|
56
|
+
*/
|
|
57
|
+
broadcastNotification(method: string, params?: unknown): void;
|
|
58
|
+
/**
|
|
59
|
+
* Look up the low-level MCP Server for a connected app by name.
|
|
60
|
+
* Throws if multiple connections match (ambiguous).
|
|
61
|
+
* Returns undefined if no match is found.
|
|
62
|
+
*/
|
|
63
|
+
getMcpServerForApp(appName: string): Server | undefined;
|
|
64
|
+
private handleConnection;
|
|
65
|
+
private logPipeSecurity;
|
|
66
|
+
private validateClient;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export { type DaemonStatusSnapshot, IpcServer, type IpcServerOptions };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|