@hivemind-os/collective-cli 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/index.js ADDED
@@ -0,0 +1,2379 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { pathToFileURL } from "url";
5
+ import { SessionExpiredError } from "@hivemind-os/collective-core";
6
+
7
+ // src/commands/config.ts
8
+ import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
9
+ import { homedir } from "os";
10
+ import { dirname, join, resolve } from "path";
11
+ import { getDefaultIpcPath as getDaemonDefaultIpcPath } from "@hivemind-os/collective-daemon/config";
12
+ import { PaymentRail, NETWORK_PRESETS, getNetworkPreset } from "@hivemind-os/collective-types";
13
+ import yaml from "js-yaml";
14
+
15
+ // src/utils/output.ts
16
+ var COLORS = {
17
+ green: "\x1B[32m",
18
+ red: "\x1B[31m",
19
+ blue: "\x1B[34m",
20
+ yellow: "\x1B[33m",
21
+ reset: "\x1B[0m"
22
+ };
23
+ function success(message) {
24
+ console.log(formatMessage("\u2713", message, COLORS.green));
25
+ }
26
+ function error(message) {
27
+ console.error(formatMessage("\u2717", message, COLORS.red));
28
+ }
29
+ function info(message) {
30
+ console.log(formatMessage("\u2139", message, COLORS.blue));
31
+ }
32
+ function warn(message) {
33
+ console.warn(formatMessage("\u26A0", message, COLORS.yellow));
34
+ }
35
+ function table(headers, rows) {
36
+ console.log(formatTable(headers, rows));
37
+ }
38
+ function formatTable(headers, rows) {
39
+ const widths = headers.map((header, index) => {
40
+ const rowWidth = Math.max(...rows.map((row) => (row[index] ?? "").length), 0);
41
+ return Math.max(header.length, rowWidth);
42
+ });
43
+ const renderRow = (row) => row.map((cell, index) => (cell ?? "").padEnd(widths[index] ?? 0, " ")).join(" | ");
44
+ return [renderRow(headers), widths.map((width) => "-".repeat(width)).join("-+-"), ...rows.map(renderRow)].join("\n");
45
+ }
46
+ function formatMessage(symbol, message, color) {
47
+ const prefix = shouldUseColor() ? `${color}${symbol}${COLORS.reset}` : symbol;
48
+ return `${prefix} ${message}`;
49
+ }
50
+ function shouldUseColor() {
51
+ return !process.env.NO_COLOR && Boolean(process.stdout.isTTY);
52
+ }
53
+
54
+ // src/commands/config.ts
55
+ var LOG_LEVELS = /* @__PURE__ */ new Set(["debug", "info", "warn", "error"]);
56
+ async function handleConfig(args) {
57
+ const [subcommand, ...rest] = args;
58
+ if (!subcommand) {
59
+ console.log(yaml.dump(redactConfig(serializeConfig(loadMeshConfig())), { lineWidth: 120 }));
60
+ return 0;
61
+ }
62
+ if (subcommand === "path") {
63
+ console.log(getConfigPath());
64
+ return 0;
65
+ }
66
+ if (subcommand === "set") {
67
+ const key = rest[0];
68
+ const rawValue = rest.slice(1).join(" ");
69
+ if (!key || !rawValue) {
70
+ throw new Error("Usage: mesh config set <key> <value>");
71
+ }
72
+ const config = loadMeshConfig();
73
+ setNestedValue(config, key, parseConfigValue(rawValue));
74
+ saveMeshConfig(config);
75
+ success(`Updated ${key}`);
76
+ return 0;
77
+ }
78
+ throw new Error("Usage: mesh config [path|set <key> <value>]");
79
+ }
80
+ function getMeshDataDir() {
81
+ return normalizePath(process.env.COLLECTIVE_DATA_DIR ?? join(homedir(), ".hivemind-os/collective"));
82
+ }
83
+ function getConfigPath(configPath) {
84
+ return normalizePath(configPath ?? join(getMeshDataDir(), "config.yaml"));
85
+ }
86
+ function buildDefaultConfig(dataDir = getMeshDataDir()) {
87
+ const resolvedDataDir = normalizePath(dataDir);
88
+ const networkName = process.env.COLLECTIVE_NETWORK;
89
+ const preset = networkName ? getNetworkPreset(networkName) : NETWORK_PRESETS.testnet;
90
+ const defaultNetwork = preset ?? NETWORK_PRESETS.testnet;
91
+ return {
92
+ network: {
93
+ rpcUrl: process.env.COLLECTIVE_RPC_URL ?? defaultNetwork.rpcUrl,
94
+ faucetUrl: defaultNetwork.faucetUrl,
95
+ packageId: process.env.COLLECTIVE_PACKAGE_ID ?? defaultNetwork.packageId,
96
+ registryId: process.env.COLLECTIVE_REGISTRY_ID ?? defaultNetwork.registryId
97
+ },
98
+ identity: {
99
+ dataDir: join(resolvedDataDir, "identity")
100
+ },
101
+ spending: {
102
+ defaultRail: PaymentRail.SUI_ESCROW,
103
+ limits: [{ amount: 1000000000n, interval: "day", currency: "MIST" }]
104
+ },
105
+ daemon: {
106
+ ipcPath: getDaemonDefaultIpcPath(resolvedDataDir),
107
+ dataDir: resolvedDataDir,
108
+ pidFile: join(resolvedDataDir, "daemon.pid"),
109
+ logLevel: normalizeLogLevel(process.env.COLLECTIVE_LOG_LEVEL, "info"),
110
+ logFile: join(resolvedDataDir, "daemon.log")
111
+ },
112
+ blobstore: {
113
+ type: "filesystem",
114
+ baseDir: join(resolvedDataDir, "blobs")
115
+ },
116
+ indexer: {
117
+ enabled: Boolean(process.env.COLLECTIVE_INDEXER_URL),
118
+ url: process.env.COLLECTIVE_INDEXER_URL
119
+ }
120
+ };
121
+ }
122
+ function loadMeshConfig(configPath) {
123
+ const resolvedConfigPath = getConfigPath(configPath);
124
+ const parsed = loadConfigFile(resolvedConfigPath);
125
+ const baseDataDir = normalizePath(
126
+ process.env.COLLECTIVE_DATA_DIR ?? readString(getNestedValue(parsed, "daemon", "dataDir")) ?? dirname(resolvedConfigPath)
127
+ );
128
+ const defaults = buildDefaultConfig(baseDataDir);
129
+ const hasExplicitIpcPath = readString(getNestedValue(parsed, "daemon", "ipcPath")) !== void 0;
130
+ const config = applyEnvironmentOverrides(mergeConfig(defaults, parsed), { hasExplicitIpcPath });
131
+ validateConfig(config);
132
+ if (!existsSync(resolvedConfigPath)) {
133
+ saveMeshConfig(config, resolvedConfigPath);
134
+ } else {
135
+ enforcePrivateFilePermissions(resolvedConfigPath);
136
+ }
137
+ return config;
138
+ }
139
+ function saveMeshConfig(config, configPath = getConfigPath()) {
140
+ const resolvedConfigPath = getConfigPath(configPath);
141
+ mkdirSync(dirname(resolvedConfigPath), { recursive: true, mode: 448 });
142
+ writePrivateConfigFile(resolvedConfigPath, yaml.dump(serializeConfig(config), { lineWidth: 120 }));
143
+ return resolvedConfigPath;
144
+ }
145
+ function writePrivateConfigFile(configPath, contents) {
146
+ writeFileSync(configPath, contents, { encoding: "utf8", mode: 384 });
147
+ enforcePrivateFilePermissions(configPath);
148
+ }
149
+ function enforcePrivateFilePermissions(path) {
150
+ chmodSync(path, 384);
151
+ }
152
+ function serializeConfig(config) {
153
+ return serializeValue(config);
154
+ }
155
+ function redactConfig(value) {
156
+ if (Array.isArray(value)) {
157
+ return value.map((entry) => redactConfig(entry));
158
+ }
159
+ if (value && typeof value === "object") {
160
+ return Object.fromEntries(
161
+ Object.entries(value).map(([key, entry]) => [
162
+ key,
163
+ /(secret|token|password|private)/i.test(key) ? "<redacted>" : redactConfig(entry)
164
+ ])
165
+ );
166
+ }
167
+ return value;
168
+ }
169
+ function loadConfigFile(configPath) {
170
+ if (!existsSync(configPath)) {
171
+ return {};
172
+ }
173
+ const loaded = yaml.load(readFileSync(configPath, "utf8"));
174
+ return isRecord(loaded) ? loaded : {};
175
+ }
176
+ function mergeConfig(defaults, parsed) {
177
+ const network = isRecord(parsed.network) ? parsed.network : {};
178
+ const identity = isRecord(parsed.identity) ? parsed.identity : {};
179
+ const daemon = isRecord(parsed.daemon) ? parsed.daemon : {};
180
+ const blobstore = isRecord(parsed.blobstore) ? parsed.blobstore : {};
181
+ const indexer = isRecord(parsed.indexer) ? parsed.indexer : {};
182
+ return {
183
+ network: {
184
+ rpcUrl: readString(network.rpcUrl) ?? defaults.network.rpcUrl,
185
+ faucetUrl: readString(network.faucetUrl) ?? defaults.network.faucetUrl,
186
+ packageId: readHexString(network.packageId) ?? defaults.network.packageId,
187
+ registryId: readHexString(network.registryId) ?? defaults.network.registryId
188
+ },
189
+ identity: {
190
+ dataDir: normalizePath(readString(identity.dataDir) ?? defaults.identity.dataDir)
191
+ },
192
+ spending: normalizeSpendingPolicy(parsed.spending, defaults.spending),
193
+ daemon: {
194
+ ipcPath: readString(daemon.ipcPath) ?? defaults.daemon.ipcPath,
195
+ dataDir: normalizePath(readString(daemon.dataDir) ?? defaults.daemon.dataDir),
196
+ pidFile: normalizePath(readString(daemon.pidFile) ?? defaults.daemon.pidFile),
197
+ logLevel: normalizeLogLevel(daemon.logLevel, defaults.daemon.logLevel),
198
+ logFile: readString(daemon.logFile) ? normalizePath(readString(daemon.logFile)) : defaults.daemon.logFile
199
+ },
200
+ blobstore: {
201
+ type: "filesystem",
202
+ baseDir: normalizePath(readString(blobstore.baseDir) ?? defaults.blobstore.baseDir)
203
+ },
204
+ indexer: {
205
+ enabled: readBoolean(indexer.enabled) ?? defaults.indexer.enabled,
206
+ url: readString(indexer.url) ?? defaults.indexer.url
207
+ }
208
+ };
209
+ }
210
+ function applyEnvironmentOverrides(config, options = { hasExplicitIpcPath: false }) {
211
+ const envDataDir = process.env.COLLECTIVE_DATA_DIR ? normalizePath(process.env.COLLECTIVE_DATA_DIR) : void 0;
212
+ const withDataDir = envDataDir ? {
213
+ ...config,
214
+ identity: { dataDir: join(envDataDir, "identity") },
215
+ daemon: {
216
+ ...config.daemon,
217
+ dataDir: envDataDir,
218
+ pidFile: join(envDataDir, "daemon.pid"),
219
+ ipcPath: options.hasExplicitIpcPath ? config.daemon.ipcPath : getDaemonDefaultIpcPath(envDataDir),
220
+ logFile: join(envDataDir, "daemon.log")
221
+ },
222
+ blobstore: {
223
+ type: "filesystem",
224
+ baseDir: join(envDataDir, "blobs")
225
+ }
226
+ } : config;
227
+ const networkName = process.env.COLLECTIVE_NETWORK;
228
+ const envPreset = networkName ? getNetworkPreset(networkName) : void 0;
229
+ const baseNetwork = envPreset ? { ...withDataDir.network, ...envPreset } : withDataDir.network;
230
+ return {
231
+ ...withDataDir,
232
+ network: {
233
+ ...baseNetwork,
234
+ rpcUrl: process.env.COLLECTIVE_RPC_URL ?? baseNetwork.rpcUrl,
235
+ packageId: process.env.COLLECTIVE_PACKAGE_ID ?? baseNetwork.packageId,
236
+ registryId: process.env.COLLECTIVE_REGISTRY_ID ?? baseNetwork.registryId
237
+ },
238
+ daemon: {
239
+ ...withDataDir.daemon,
240
+ logLevel: normalizeLogLevel(process.env.COLLECTIVE_LOG_LEVEL, withDataDir.daemon.logLevel)
241
+ },
242
+ indexer: {
243
+ enabled: process.env.COLLECTIVE_INDEXER_URL ? true : withDataDir.indexer.enabled,
244
+ url: process.env.COLLECTIVE_INDEXER_URL ?? withDataDir.indexer.url
245
+ }
246
+ };
247
+ }
248
+ function normalizeSpendingPolicy(value, defaults) {
249
+ if (!isRecord(value)) {
250
+ return defaults;
251
+ }
252
+ return {
253
+ defaultRail: normalizeRail(value.defaultRail) ?? defaults.defaultRail,
254
+ requireConfirmationAbove: value.requireConfirmationAbove === void 0 ? defaults.requireConfirmationAbove : parseBigInt(value.requireConfirmationAbove, "spending.requireConfirmationAbove"),
255
+ allowlist: Array.isArray(value.allowlist) ? value.allowlist.filter((entry) => typeof entry === "string") : defaults.allowlist,
256
+ denylist: Array.isArray(value.denylist) ? value.denylist.filter((entry) => typeof entry === "string") : defaults.denylist,
257
+ limits: Array.isArray(value.limits) && value.limits.length > 0 ? value.limits.map((limit, index) => normalizeSpendingLimit(limit, index)) : defaults.limits
258
+ };
259
+ }
260
+ function normalizeSpendingLimit(value, index) {
261
+ if (!isRecord(value)) {
262
+ throw new Error(`spending.limits[${index}] must be an object.`);
263
+ }
264
+ const interval = readString(value.interval);
265
+ if (!interval || !["transaction", "hour", "day", "month", "lifetime"].includes(interval)) {
266
+ throw new Error(`spending.limits[${index}].interval is invalid.`);
267
+ }
268
+ return {
269
+ amount: parseBigInt(value.amount, `spending.limits[${index}].amount`),
270
+ interval,
271
+ rail: normalizeRail(value.rail),
272
+ currency: readString(value.currency)?.toUpperCase(),
273
+ scope: readString(value.scope) ?? void 0
274
+ };
275
+ }
276
+ function validateConfig(config) {
277
+ if (!config.network.rpcUrl) {
278
+ throw new Error("network.rpcUrl is required.");
279
+ }
280
+ if (!config.identity.dataDir) {
281
+ throw new Error("identity.dataDir is required.");
282
+ }
283
+ if (!config.daemon.ipcPath || !config.daemon.dataDir || !config.daemon.pidFile) {
284
+ throw new Error("daemon configuration is incomplete.");
285
+ }
286
+ if (!LOG_LEVELS.has(config.daemon.logLevel)) {
287
+ throw new Error(`Invalid log level: ${config.daemon.logLevel}`);
288
+ }
289
+ if (!config.blobstore.baseDir) {
290
+ throw new Error("blobstore.baseDir is required.");
291
+ }
292
+ if (config.indexer.enabled && !config.indexer.url) {
293
+ throw new Error("indexer.url is required when indexer.enabled is true.");
294
+ }
295
+ }
296
+ function serializeValue(value) {
297
+ if (typeof value === "bigint") {
298
+ return value.toString();
299
+ }
300
+ if (Array.isArray(value)) {
301
+ return value.map((entry) => serializeValue(entry));
302
+ }
303
+ if (value && typeof value === "object") {
304
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, serializeValue(entry)]));
305
+ }
306
+ return value;
307
+ }
308
+ function normalizeLogLevel(value, fallback) {
309
+ return typeof value === "string" && LOG_LEVELS.has(value) ? value : fallback;
310
+ }
311
+ function normalizeRail(value) {
312
+ if (value === PaymentRail.SUI_ESCROW || value === PaymentRail.SUI_TRANSFER || value === PaymentRail.X402_BASE) {
313
+ return value;
314
+ }
315
+ return void 0;
316
+ }
317
+ function parseBigInt(value, field) {
318
+ if (typeof value === "bigint") {
319
+ return value;
320
+ }
321
+ if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) {
322
+ return BigInt(value);
323
+ }
324
+ if (typeof value === "string" && /^\d+$/.test(value.trim())) {
325
+ return BigInt(value.trim());
326
+ }
327
+ throw new Error(`${field} must be a non-negative integer.`);
328
+ }
329
+ function readString(value) {
330
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
331
+ }
332
+ function readBoolean(value) {
333
+ return typeof value === "boolean" ? value : void 0;
334
+ }
335
+ function readHexString(value) {
336
+ if (typeof value === "string" && value.trim()) {
337
+ return value.trim();
338
+ }
339
+ if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) {
340
+ return `0x${value.toString(16)}`;
341
+ }
342
+ return void 0;
343
+ }
344
+ function normalizePath(value) {
345
+ return resolve(expandHome(value));
346
+ }
347
+ function expandHome(value) {
348
+ if (value === "~") {
349
+ return homedir();
350
+ }
351
+ if (value.startsWith("~/") || value.startsWith("~\\")) {
352
+ return join(homedir(), value.slice(2));
353
+ }
354
+ return value;
355
+ }
356
+ function getNestedValue(record, ...keys) {
357
+ let current = record;
358
+ for (const key of keys) {
359
+ if (!isRecord(current)) {
360
+ return void 0;
361
+ }
362
+ current = current[key];
363
+ }
364
+ return current;
365
+ }
366
+ function parseConfigValue(rawValue) {
367
+ const parsed = yaml.load(rawValue);
368
+ return parsed === void 0 ? rawValue : parsed;
369
+ }
370
+ function setNestedValue(target, keyPath, value) {
371
+ const keys = keyPath.split(".").filter(Boolean);
372
+ if (keys.length === 0) {
373
+ throw new Error("Config key is required.");
374
+ }
375
+ let current = target;
376
+ for (const key of keys.slice(0, -1)) {
377
+ const existing = current[key];
378
+ if (!isRecord(existing)) {
379
+ current[key] = {};
380
+ }
381
+ current = current[key];
382
+ }
383
+ current[keys[keys.length - 1]] = value;
384
+ }
385
+ function isRecord(value) {
386
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
387
+ }
388
+
389
+ // src/commands/analytics.ts
390
+ async function handleAnalytics(subcommand, args = [], deps = {}) {
391
+ switch (subcommand) {
392
+ case "summary":
393
+ return await showAnalyticsSummary(deps);
394
+ case "top-providers":
395
+ return await showTopProviders(args, deps);
396
+ case "task-volume":
397
+ return await showTaskVolume(args, deps);
398
+ default:
399
+ throw new Error("Usage: mesh analytics <summary|top-providers|task-volume>");
400
+ }
401
+ }
402
+ async function showAnalyticsSummary(deps) {
403
+ const data = await queryIndexer(deps, `query AnalyticsSummary {
404
+ analytics {
405
+ totalAgents
406
+ activeAgents
407
+ totalTasks
408
+ completedTasks
409
+ disputedTasks
410
+ totalVolumeMist
411
+ marketplace {
412
+ averageBidCount
413
+ acceptanceRate
414
+ }
415
+ }
416
+ }`);
417
+ info("Agentic Mesh analytics summary");
418
+ table(
419
+ ["Metric", "Value"],
420
+ [
421
+ ["Total Agents", String(data.analytics.totalAgents)],
422
+ ["Active Agents", String(data.analytics.activeAgents)],
423
+ ["Total Tasks", String(data.analytics.totalTasks)],
424
+ ["Completed Tasks", String(data.analytics.completedTasks)],
425
+ ["Disputed Tasks", String(data.analytics.disputedTasks)],
426
+ ["Total Volume (MIST)", data.analytics.totalVolumeMist],
427
+ ["Average Bid Count", data.analytics.marketplace.averageBidCount.toFixed(2)],
428
+ ["Acceptance Rate", `${(data.analytics.marketplace.acceptanceRate * 100).toFixed(1)}%`]
429
+ ]
430
+ );
431
+ return 0;
432
+ }
433
+ async function showTopProviders(args, deps) {
434
+ const limit = readNumericFlag(args, "--limit") ?? 10;
435
+ const sortBy = (readStringFlag(args, "--sort-by") ?? "COMPLETED_TASKS").toUpperCase();
436
+ const data = await queryIndexer(deps, `query TopProviders($limit: Int, $sortBy: ProviderSortField) {
437
+ topProviders(limit: $limit, sortBy: $sortBy) {
438
+ name
439
+ did
440
+ completedTasks
441
+ earningsMist
442
+ successRate
443
+ reputation
444
+ }
445
+ }`, { limit, sortBy });
446
+ info(`Top ${data.topProviders.length} providers`);
447
+ table(
448
+ ["Name", "DID", "Completed", "Earnings (MIST)", "Success Rate", "Reputation"],
449
+ data.topProviders.map((provider) => [
450
+ provider.name,
451
+ provider.did,
452
+ String(provider.completedTasks),
453
+ provider.earningsMist,
454
+ `${(provider.successRate * 100).toFixed(1)}%`,
455
+ provider.reputation.toFixed(2)
456
+ ])
457
+ );
458
+ return 0;
459
+ }
460
+ async function showTaskVolume(args, deps) {
461
+ const period = (readStringFlag(args, "--period") ?? "DAY").toUpperCase();
462
+ const buckets = readNumericFlag(args, "--buckets") ?? 14;
463
+ const data = await queryIndexer(
464
+ deps,
465
+ `query TaskVolume($period: TimePeriod!, $buckets: Int) {
466
+ taskVolume(period: $period, buckets: $buckets) {
467
+ label
468
+ count
469
+ volumeMist
470
+ }
471
+ }`,
472
+ { period, buckets }
473
+ );
474
+ info(`Task volume by ${period.toLowerCase()}`);
475
+ table(
476
+ ["Bucket", "Tasks", "Volume (MIST)"],
477
+ data.taskVolume.map((bucket) => [bucket.label, String(bucket.count), bucket.volumeMist])
478
+ );
479
+ return 0;
480
+ }
481
+ async function queryIndexer(deps, query, variables) {
482
+ const config = (deps.loadConfig ?? loadMeshConfig)();
483
+ if (!config.indexer.url) {
484
+ throw new Error("indexer.url must be configured before using analytics commands.");
485
+ }
486
+ const fetchImpl = deps.fetchImpl ?? globalThis.fetch;
487
+ const response = await fetchImpl(config.indexer.url, {
488
+ method: "POST",
489
+ headers: {
490
+ "content-type": "application/json"
491
+ },
492
+ body: JSON.stringify({ query, variables })
493
+ });
494
+ if (!response.ok) {
495
+ throw new Error(`Indexer query failed with status ${response.status}.`);
496
+ }
497
+ const payload = await response.json();
498
+ if (payload.errors?.length) {
499
+ throw new Error(payload.errors.map((entry) => entry.message ?? "Unknown GraphQL error").join("; "));
500
+ }
501
+ if (!payload.data) {
502
+ throw new Error("Indexer query returned no data.");
503
+ }
504
+ return payload.data;
505
+ }
506
+ function readStringFlag(args, name) {
507
+ const index = args.indexOf(name);
508
+ if (index < 0) {
509
+ return void 0;
510
+ }
511
+ const value = args[index + 1]?.trim();
512
+ if (!value) {
513
+ throw new Error(`Missing value for ${name}.`);
514
+ }
515
+ return value;
516
+ }
517
+ function readNumericFlag(args, name) {
518
+ const value = readStringFlag(args, name);
519
+ if (!value) {
520
+ return void 0;
521
+ }
522
+ const parsed = Number(value);
523
+ if (!Number.isFinite(parsed) || parsed <= 0) {
524
+ throw new Error(`${name} must be a positive number.`);
525
+ }
526
+ return Math.floor(parsed);
527
+ }
528
+
529
+ // src/utils/daemon-client.ts
530
+ import net from "net";
531
+ var DaemonClient = class _DaemonClient {
532
+ constructor(socket) {
533
+ this.socket = socket;
534
+ socket.setEncoding("utf8");
535
+ socket.on("data", (chunk) => {
536
+ this.buffer += chunk.toString();
537
+ this.drainBuffer();
538
+ });
539
+ socket.on("error", (error2) => {
540
+ this.rejectPending(error2 instanceof Error ? error2 : new Error(String(error2)));
541
+ });
542
+ socket.on("close", () => {
543
+ this.rejectPending(new Error("Daemon IPC connection closed."));
544
+ });
545
+ }
546
+ socket;
547
+ buffer = "";
548
+ pending = /* @__PURE__ */ new Map();
549
+ nextId = 0;
550
+ static async connect(ipcPath) {
551
+ const socket = await new Promise((resolvePromise, reject) => {
552
+ const client = net.connect(ipcPath, () => {
553
+ client.off("error", reject);
554
+ resolvePromise(client);
555
+ });
556
+ client.once("error", reject);
557
+ });
558
+ const daemonClient = new _DaemonClient(socket);
559
+ await daemonClient.initialize();
560
+ return daemonClient;
561
+ }
562
+ async getStatus() {
563
+ return await this.callTool("collective_status", {});
564
+ }
565
+ async getAuthStatus() {
566
+ return (await this.request("auth.status")).result;
567
+ }
568
+ async triggerReauth() {
569
+ return (await this.request("auth.reauth")).result;
570
+ }
571
+ async close() {
572
+ if (this.socket.destroyed) {
573
+ return;
574
+ }
575
+ await new Promise((resolvePromise) => {
576
+ this.socket.once("close", () => {
577
+ resolvePromise();
578
+ });
579
+ this.socket.end();
580
+ setTimeout(() => {
581
+ if (!this.socket.destroyed) {
582
+ this.socket.destroy();
583
+ }
584
+ }, 25);
585
+ });
586
+ }
587
+ async initialize() {
588
+ await this.request("shim_hello", {
589
+ appName: "mesh-cli",
590
+ pid: process.pid,
591
+ profile: process.env.USERPROFILE ?? process.env.HOME
592
+ });
593
+ await this.request("initialize", {
594
+ protocolVersion: "2025-03-26",
595
+ capabilities: {},
596
+ clientInfo: {
597
+ name: "mesh-cli",
598
+ version: "0.1.0"
599
+ }
600
+ });
601
+ this.socket.write(`${JSON.stringify({ jsonrpc: "2.0", method: "notifications/initialized" })}
602
+ `);
603
+ }
604
+ async callTool(name, args) {
605
+ const response = await this.request("tools/call", {
606
+ name,
607
+ arguments: args
608
+ });
609
+ const result = asRecord(response.result);
610
+ return result.structuredContent ?? result;
611
+ }
612
+ request(method, params) {
613
+ const id = `mesh-cli-${++this.nextId}`;
614
+ const message = {
615
+ jsonrpc: "2.0",
616
+ id,
617
+ method,
618
+ params
619
+ };
620
+ return new Promise((resolvePromise, reject) => {
621
+ this.pending.set(id, { resolve: resolvePromise, reject });
622
+ this.socket.write(`${JSON.stringify(message)}
623
+ `);
624
+ }).then((response) => {
625
+ if (response.error) {
626
+ throw new Error(response.error.message);
627
+ }
628
+ return response;
629
+ });
630
+ }
631
+ drainBuffer() {
632
+ let newlineIndex = this.buffer.indexOf("\n");
633
+ while (newlineIndex >= 0) {
634
+ const line = this.buffer.slice(0, newlineIndex).trim();
635
+ this.buffer = this.buffer.slice(newlineIndex + 1);
636
+ if (line) {
637
+ const message = JSON.parse(line);
638
+ if ("id" in message && message.id !== null) {
639
+ const pending = this.pending.get(message.id);
640
+ if (pending) {
641
+ this.pending.delete(message.id);
642
+ pending.resolve(message);
643
+ }
644
+ }
645
+ }
646
+ newlineIndex = this.buffer.indexOf("\n");
647
+ }
648
+ }
649
+ rejectPending(error2) {
650
+ for (const [id, pending] of this.pending) {
651
+ this.pending.delete(id);
652
+ pending.reject(error2);
653
+ }
654
+ }
655
+ };
656
+ async function getDaemonStatus(ipcPath) {
657
+ const client = await DaemonClient.connect(ipcPath);
658
+ try {
659
+ return await client.getStatus();
660
+ } finally {
661
+ await client.close();
662
+ }
663
+ }
664
+ async function getDaemonAuthStatus(ipcPath) {
665
+ const client = await DaemonClient.connect(ipcPath);
666
+ try {
667
+ return await client.getAuthStatus();
668
+ } finally {
669
+ await client.close();
670
+ }
671
+ }
672
+ async function requestDaemonReauth(ipcPath) {
673
+ const client = await DaemonClient.connect(ipcPath);
674
+ try {
675
+ return await client.triggerReauth();
676
+ } finally {
677
+ await client.close();
678
+ }
679
+ }
680
+ function asRecord(value) {
681
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
682
+ throw new Error("Unexpected daemon response payload.");
683
+ }
684
+ return value;
685
+ }
686
+
687
+ // src/commands/auth.ts
688
+ var defaultDeps = {
689
+ getAuthStatus: getDaemonAuthStatus,
690
+ triggerReauth: requestDaemonReauth
691
+ };
692
+ async function handleAuth(subcommand, _args = [], deps = defaultDeps) {
693
+ switch (subcommand) {
694
+ case "status":
695
+ return await showAuthStatus(deps);
696
+ case "reauth":
697
+ return await triggerReauth(deps);
698
+ default:
699
+ throw new Error("Usage: mesh auth <status|reauth>");
700
+ }
701
+ }
702
+ async function showAuthStatus(deps) {
703
+ const status = await deps.getAuthStatus(loadMeshConfig().daemon.ipcPath);
704
+ printAuthStatus(status);
705
+ return status.authenticated ? 0 : 1;
706
+ }
707
+ async function triggerReauth(deps) {
708
+ const result = await deps.triggerReauth(loadMeshConfig().daemon.ipcPath);
709
+ printAuthStatus(result.status);
710
+ if (result.portalUrl) {
711
+ if (result.browserOpened) {
712
+ success(`Opened re-auth portal: ${result.portalUrl}`);
713
+ } else {
714
+ warn(`Open the re-auth portal manually: ${result.portalUrl}`);
715
+ }
716
+ } else {
717
+ info("This daemon auth mode does not require browser re-authentication.");
718
+ }
719
+ return result.status.authenticated ? 0 : 1;
720
+ }
721
+ function printAuthStatus(status) {
722
+ const expires = formatExpiry(status.expiresAt);
723
+ const stateLabel = status.authenticated ? status.state : `${status.state} (action required)`;
724
+ console.log(`Auth Mode: ${status.authMode}`);
725
+ console.log(`State: ${stateLabel}`);
726
+ console.log(`Address: ${status.address ?? "-"}`);
727
+ console.log(`Expires: ${expires}`);
728
+ console.log(`Refresh Available: ${status.refreshAvailable ? "yes" : "no"}`);
729
+ if (status.lastError) {
730
+ console.log(`Last Error: ${status.lastError}`);
731
+ }
732
+ }
733
+ function formatExpiry(expiresAt) {
734
+ if (expiresAt === null) {
735
+ return "unknown";
736
+ }
737
+ return new Date(expiresAt).toISOString();
738
+ }
739
+
740
+ // src/commands/connect.ts
741
+ import { spawn, spawnSync } from "child_process";
742
+ import { readFileSync as readFileSync2 } from "fs";
743
+ import { createRequire } from "module";
744
+ import { dirname as dirname2, resolve as resolve2 } from "path";
745
+ var require2 = createRequire(import.meta.url);
746
+ async function handleConnect(args) {
747
+ const shimCommand = resolveShimCommand();
748
+ if (!shimCommand) {
749
+ warn("@hivemind-os/collective-shim is not available in this environment.");
750
+ info("Build or install the shim package, then configure your MCP app to run `mesh connect`.");
751
+ info("In the meantime, start the background service with `mesh daemon start`.");
752
+ return 1;
753
+ }
754
+ return await new Promise((resolvePromise, reject) => {
755
+ const child = spawn(shimCommand.command, [...shimCommand.args, ...args], {
756
+ stdio: "inherit",
757
+ windowsHide: true
758
+ });
759
+ child.once("error", reject);
760
+ child.once("exit", (code) => {
761
+ resolvePromise(code ?? 0);
762
+ });
763
+ }).catch((caught) => {
764
+ error(caught instanceof Error ? caught.message : String(caught));
765
+ return 1;
766
+ });
767
+ }
768
+ function resolveShimCommand() {
769
+ try {
770
+ const packageJsonPath = require2.resolve("@hivemind-os/collective-shim/package.json");
771
+ const packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf8"));
772
+ const binField = typeof packageJson.bin === "string" ? packageJson.bin : packageJson.bin?.["mesh-shim"] ?? Object.values(packageJson.bin ?? {})[0];
773
+ if (!binField) {
774
+ return void 0;
775
+ }
776
+ const entryPath = resolve2(dirname2(packageJsonPath), binField);
777
+ return {
778
+ command: process.execPath,
779
+ args: [entryPath]
780
+ };
781
+ } catch {
782
+ const onPath = process.platform === "win32" ? findOnPath("mesh-shim.cmd") ?? findOnPath("mesh-shim") : findOnPath("mesh-shim");
783
+ return onPath ? { command: onPath, args: [] } : void 0;
784
+ }
785
+ }
786
+ function findOnPath(command) {
787
+ const checker = process.platform === "win32" ? "where.exe" : "which";
788
+ const result = spawnSync(checker, [command], { encoding: "utf8", windowsHide: true });
789
+ if (result.status !== 0) {
790
+ return void 0;
791
+ }
792
+ return result.stdout.split(/\r?\n/).map((entry) => entry.trim()).find(Boolean);
793
+ }
794
+
795
+ // src/commands/daemon.ts
796
+ import { spawn as spawn2 } from "child_process";
797
+ import { createRequire as createRequire2 } from "module";
798
+ import { existsSync as existsSync2, readFileSync as readFileSync3, rmSync } from "fs";
799
+ import { dirname as dirname3, resolve as resolve3 } from "path";
800
+ var require3 = createRequire2(import.meta.url);
801
+ var defaultDeps2 = {
802
+ spawnProcess: (command, args, options) => spawn2(command, args, options),
803
+ resolveDaemonCommand,
804
+ getStatus: getDaemonStatus,
805
+ killProcess: (pid, signal) => {
806
+ process.kill(pid, signal);
807
+ },
808
+ isProcessRunning,
809
+ sleep: (ms) => new Promise((resolvePromise) => {
810
+ setTimeout(resolvePromise, ms);
811
+ })
812
+ };
813
+ async function handleDaemon(subcommand, args = [], deps = defaultDeps2) {
814
+ void args;
815
+ switch (subcommand) {
816
+ case "start":
817
+ return await startDaemon(deps);
818
+ case "stop":
819
+ return await stopDaemon(deps);
820
+ case "status":
821
+ return await statusDaemon(deps);
822
+ default:
823
+ throw new Error("Usage: mesh daemon <start|stop|status>");
824
+ }
825
+ }
826
+ async function startDaemon(deps) {
827
+ const config = loadMeshConfig();
828
+ const pid = readPid(config.daemon.pidFile);
829
+ if (pid && deps.isProcessRunning(pid)) {
830
+ info("Daemon is already running.");
831
+ return await statusDaemon(deps);
832
+ }
833
+ if (pid && !deps.isProcessRunning(pid)) {
834
+ rmSync(config.daemon.pidFile, { force: true });
835
+ }
836
+ const daemonCommand = await deps.resolveDaemonCommand();
837
+ const child = deps.spawnProcess(daemonCommand.command, daemonCommand.args, {
838
+ detached: true,
839
+ stdio: "ignore",
840
+ windowsHide: true,
841
+ env: process.env
842
+ });
843
+ child.unref();
844
+ const ready = await waitForReady(config.daemon.ipcPath, deps);
845
+ if (!ready) {
846
+ error("Daemon did not become ready in time.");
847
+ return 1;
848
+ }
849
+ success(`Daemon started${child.pid ? ` (pid ${child.pid})` : ""}.`);
850
+ const status = await deps.getStatus(config.daemon.ipcPath);
851
+ printStatus(status);
852
+ return 0;
853
+ }
854
+ async function stopDaemon(deps) {
855
+ const config = loadMeshConfig();
856
+ const pid = readPid(config.daemon.pidFile);
857
+ if (!pid) {
858
+ info("Daemon is not running.");
859
+ return 1;
860
+ }
861
+ if (!deps.isProcessRunning(pid)) {
862
+ rmSync(config.daemon.pidFile, { force: true });
863
+ info("Daemon is not running.");
864
+ return 1;
865
+ }
866
+ deps.killProcess(pid, "SIGTERM");
867
+ for (let attempt = 0; attempt < 30; attempt += 1) {
868
+ await deps.sleep(100);
869
+ if (!deps.isProcessRunning(pid)) {
870
+ rmSync(config.daemon.pidFile, { force: true });
871
+ success("Daemon stopped.");
872
+ return 0;
873
+ }
874
+ }
875
+ deps.killProcess(pid, "SIGKILL");
876
+ for (let attempt = 0; attempt < 10; attempt += 1) {
877
+ await deps.sleep(100);
878
+ if (!deps.isProcessRunning(pid)) {
879
+ rmSync(config.daemon.pidFile, { force: true });
880
+ success("Daemon stopped.");
881
+ return 0;
882
+ }
883
+ }
884
+ error("Unable to stop the daemon process.");
885
+ return 1;
886
+ }
887
+ async function statusDaemon(deps) {
888
+ const config = loadMeshConfig();
889
+ const pid = readPid(config.daemon.pidFile);
890
+ if (!pid || !deps.isProcessRunning(pid)) {
891
+ if (pid && !deps.isProcessRunning(pid)) {
892
+ rmSync(config.daemon.pidFile, { force: true });
893
+ }
894
+ info("Daemon is not running.");
895
+ return 1;
896
+ }
897
+ try {
898
+ const status = await deps.getStatus(config.daemon.ipcPath);
899
+ success("Daemon is running.");
900
+ printStatus(status);
901
+ return 0;
902
+ } catch (caught) {
903
+ warn("Daemon process exists, but IPC status could not be fetched.");
904
+ console.log(`PID: ${pid}`);
905
+ console.log(`PID file: ${config.daemon.pidFile}`);
906
+ console.log(`Reason: ${caught instanceof Error ? caught.message : String(caught)}`);
907
+ return 1;
908
+ }
909
+ }
910
+ async function waitForReady(ipcPath, deps) {
911
+ for (let attempt = 0; attempt < 50; attempt += 1) {
912
+ try {
913
+ await deps.getStatus(ipcPath);
914
+ return true;
915
+ } catch {
916
+ await deps.sleep(100);
917
+ }
918
+ }
919
+ return false;
920
+ }
921
+ function printStatus(status) {
922
+ console.log(`DID: ${status.did}`);
923
+ console.log(`Address: ${status.address}`);
924
+ console.log(`Uptime: ${formatDuration(status.uptimeMs)}`);
925
+ console.log(`Connected Apps: ${status.connectedApps.length}`);
926
+ if (status.connectedApps.length > 0) {
927
+ table(
928
+ ["App", "PID", "Profile", "Connected"],
929
+ status.connectedApps.map((app) => [
930
+ app.appName ?? "-",
931
+ app.pid?.toString() ?? "-",
932
+ app.profile ?? "-",
933
+ new Date(app.connectedAt).toISOString()
934
+ ])
935
+ );
936
+ }
937
+ }
938
+ async function resolveDaemonCommand() {
939
+ try {
940
+ const packageJsonPath = require3.resolve("@hivemind-os/collective-daemon/package.json");
941
+ const packageJson = JSON.parse(readFileSync3(packageJsonPath, "utf8"));
942
+ const entryPath = resolve3(dirname3(packageJsonPath), packageJson.main ?? "dist/index.js");
943
+ return {
944
+ command: process.execPath,
945
+ args: [entryPath]
946
+ };
947
+ } catch {
948
+ const fallback = resolve3(process.cwd(), "packages", "daemon", "dist", "index.js");
949
+ if (existsSync2(fallback)) {
950
+ return {
951
+ command: process.execPath,
952
+ args: [fallback]
953
+ };
954
+ }
955
+ throw new Error("Unable to locate @hivemind-os/collective-daemon. Run pnpm install && pnpm run build first.");
956
+ }
957
+ }
958
+ function readPid(pidFile) {
959
+ if (!existsSync2(pidFile)) {
960
+ return void 0;
961
+ }
962
+ const pid = Number.parseInt(readFileSync3(pidFile, "utf8").trim(), 10);
963
+ return Number.isInteger(pid) && pid > 0 ? pid : void 0;
964
+ }
965
+ function isProcessRunning(pid) {
966
+ try {
967
+ process.kill(pid, 0);
968
+ return true;
969
+ } catch (caught) {
970
+ return caught.code !== "ESRCH";
971
+ }
972
+ }
973
+ function formatDuration(ms) {
974
+ const totalSeconds = Math.max(0, Math.floor(ms / 1e3));
975
+ const hours = Math.floor(totalSeconds / 3600);
976
+ const minutes = Math.floor(totalSeconds % 3600 / 60);
977
+ const seconds = totalSeconds % 60;
978
+ const parts = [];
979
+ if (hours > 0) {
980
+ parts.push(`${hours}h`);
981
+ }
982
+ if (minutes > 0 || hours > 0) {
983
+ parts.push(`${minutes}m`);
984
+ }
985
+ parts.push(`${seconds}s`);
986
+ return parts.join(" ");
987
+ }
988
+
989
+ // src/commands/discover.ts
990
+ import { MeshSuiClient as MeshSuiClient2, RegistryClient } from "@hivemind-os/collective-core";
991
+
992
+ // src/commands/wallet.ts
993
+ import { createDID, loadOrCreateKeypair, MeshSuiClient } from "@hivemind-os/collective-core";
994
+ import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519";
995
+ async function handleWallet(subcommand, args = []) {
996
+ void args;
997
+ switch (subcommand) {
998
+ case "balance":
999
+ return await showBalance();
1000
+ case "fund":
1001
+ return await fundWallet();
1002
+ case "address":
1003
+ return await showAddress();
1004
+ default:
1005
+ throw new Error("Usage: mesh wallet <balance|fund|address>");
1006
+ }
1007
+ }
1008
+ function formatMistToSui(balanceMist) {
1009
+ const whole = balanceMist / 1000000000n;
1010
+ const fraction = balanceMist % 1000000000n;
1011
+ if (fraction === 0n) {
1012
+ return whole.toString();
1013
+ }
1014
+ const fractionText = fraction.toString().padStart(9, "0").replace(/0+$/, "");
1015
+ return `${whole.toString()}.${fractionText}`;
1016
+ }
1017
+ function parseSuiToMist(input) {
1018
+ const trimmed = input.trim();
1019
+ if (!/^\d+(?:\.\d{1,9})?$/.test(trimmed)) {
1020
+ throw new Error(`Invalid SUI amount: ${input}`);
1021
+ }
1022
+ const [whole, fraction = ""] = trimmed.split(".");
1023
+ return BigInt(whole) * 1000000000n + BigInt(fraction.padEnd(9, "0"));
1024
+ }
1025
+ async function showBalance() {
1026
+ const { config, address } = await loadWalletContext();
1027
+ const suiClient = new MeshSuiClient(config.network);
1028
+ const balanceMist = await suiClient.getBalance(address);
1029
+ success(`Wallet balance for ${address}`);
1030
+ console.log(`MIST: ${balanceMist.toString()}`);
1031
+ console.log(`SUI: ${formatMistToSui(balanceMist)}`);
1032
+ return 0;
1033
+ }
1034
+ async function fundWallet() {
1035
+ const { config, address, did } = await loadWalletContext();
1036
+ info(`Requesting faucet funds for ${address}`);
1037
+ const faucetUrls = [config.network.faucetUrl, `${config.network.faucetUrl.replace(/\/$/, "")}/gas`].filter(Boolean);
1038
+ let funded = false;
1039
+ for (const faucetUrl of faucetUrls) {
1040
+ try {
1041
+ const response = await fetch(faucetUrl, {
1042
+ method: "POST",
1043
+ headers: { "content-type": "application/json" },
1044
+ body: JSON.stringify({
1045
+ FixedAmountRequest: {
1046
+ recipient: address
1047
+ }
1048
+ })
1049
+ });
1050
+ if (response.ok) {
1051
+ funded = true;
1052
+ break;
1053
+ }
1054
+ } catch {
1055
+ }
1056
+ }
1057
+ if (funded) {
1058
+ success("Faucet request submitted.");
1059
+ } else {
1060
+ warn("Automatic faucet request failed. Use your configured faucet or wallet UI to fund this address manually.");
1061
+ }
1062
+ console.log(`DID: ${did}`);
1063
+ console.log(`Address: ${address}`);
1064
+ console.log(`Faucet: ${config.network.faucetUrl}`);
1065
+ return funded ? 0 : 1;
1066
+ }
1067
+ async function showAddress() {
1068
+ const { address } = await loadWalletContext();
1069
+ console.log(address);
1070
+ return 0;
1071
+ }
1072
+ async function loadWalletContext() {
1073
+ const config = loadMeshConfig();
1074
+ const identity = await loadOrCreateKeypair(config.identity.dataDir);
1075
+ const did = createDID(identity.publicKey);
1076
+ const keypair = Ed25519Keypair.fromSecretKey(identity.secretKey);
1077
+ return {
1078
+ config,
1079
+ did,
1080
+ address: keypair.getPublicKey().toSuiAddress()
1081
+ };
1082
+ }
1083
+
1084
+ // src/commands/discover.ts
1085
+ async function handleDiscover(args) {
1086
+ const capability = args[0]?.trim();
1087
+ if (!capability) {
1088
+ throw new Error("Usage: mesh discover <capability>");
1089
+ }
1090
+ const config = loadMeshConfig();
1091
+ if (!config.network.packageId || !config.network.registryId) {
1092
+ throw new Error("network.packageId and network.registryId must be configured before discovery.");
1093
+ }
1094
+ const registryClient = new RegistryClient(new MeshSuiClient2(config.network), config.network);
1095
+ const agents = await registryClient.discoverByCapability(capability);
1096
+ info(`Found ${agents.length} provider(s) for ${capability}`);
1097
+ table(
1098
+ ["Name", "DID", "Price (SUI)", "Endpoint"],
1099
+ agents.map((agent) => {
1100
+ const matched = agent.capabilities.find((entry) => entry.name.toLowerCase() === capability.toLowerCase());
1101
+ return [
1102
+ agent.name,
1103
+ agent.did,
1104
+ matched ? formatMistToSui(matched.pricing.amount) : "-",
1105
+ agent.endpoint ?? "-"
1106
+ ];
1107
+ })
1108
+ );
1109
+ return 0;
1110
+ }
1111
+
1112
+ // src/commands/dispute.ts
1113
+ import { readFile } from "fs/promises";
1114
+ import { DEFAULT_WALRUS_AGGREGATOR_URL, DEFAULT_WALRUS_PUBLISHER_URL, DisputeClient, MeshSuiClient as MeshSuiClient3, WalrusBlobStore, loadOrCreateKeypair as loadOrCreateKeypair2 } from "@hivemind-os/collective-core";
1115
+ import { DisputeStatus } from "@hivemind-os/collective-types";
1116
+ import { Ed25519Keypair as Ed25519Keypair2 } from "@mysten/sui/keypairs/ed25519";
1117
+ async function handleDispute(subcommand, args = [], deps = {}) {
1118
+ switch (subcommand) {
1119
+ case "open":
1120
+ return await openDispute(args, deps);
1121
+ case "respond":
1122
+ return await respondToDispute(args, deps);
1123
+ case "accept":
1124
+ return await acceptResolution(args, deps);
1125
+ case "status":
1126
+ return await showStatus(args, deps);
1127
+ default:
1128
+ throw new Error("Usage: mesh dispute <open|respond|accept|status>");
1129
+ }
1130
+ }
1131
+ async function openDispute(args, deps) {
1132
+ const taskId = args[0];
1133
+ if (!taskId) {
1134
+ throw new Error("Usage: mesh dispute open <task-id> --split-mist <mist> (--evidence <text> | --evidence-file <path> | --evidence-blob-id <id>) [--arbitrator <address>]");
1135
+ }
1136
+ const proposedSplitMist = readMistFlag(args, "--split-mist");
1137
+ const arbitratorAddress = readOptionalFlag(args, "--arbitrator");
1138
+ const evidenceBlobId = await resolveEvidenceBlobId(args, deps);
1139
+ const { client, keypair } = loadDisputeContext(deps);
1140
+ const result = await client.openDispute({
1141
+ taskId,
1142
+ evidenceBlobId,
1143
+ proposedSplitMist,
1144
+ arbitratorAddress,
1145
+ signer: keypair
1146
+ });
1147
+ success(`Opened dispute ${result.disputeId}`);
1148
+ console.log(`Task ID: ${taskId}`);
1149
+ console.log(`Evidence Blob: ${evidenceBlobId}`);
1150
+ console.log(`Tx Digest: ${result.txDigest}`);
1151
+ return 0;
1152
+ }
1153
+ async function respondToDispute(args, deps) {
1154
+ const disputeId = args[0];
1155
+ if (!disputeId) {
1156
+ throw new Error("Usage: mesh dispute respond <dispute-id> --split-mist <mist> (--evidence <text> | --evidence-file <path> | --evidence-blob-id <id>)");
1157
+ }
1158
+ const proposedSplitMist = readMistFlag(args, "--split-mist");
1159
+ const evidenceBlobId = await resolveEvidenceBlobId(args, deps);
1160
+ const { client, keypair } = loadDisputeContext(deps);
1161
+ const result = await client.respondToDispute({
1162
+ disputeId,
1163
+ evidenceBlobId,
1164
+ proposedSplitMist,
1165
+ signer: keypair
1166
+ });
1167
+ success(`Responded to dispute ${disputeId}`);
1168
+ console.log(`Evidence Blob: ${evidenceBlobId}`);
1169
+ console.log(`Tx Digest: ${result.txDigest}`);
1170
+ return 0;
1171
+ }
1172
+ async function acceptResolution(args, deps) {
1173
+ const disputeId = args[0];
1174
+ const taskId = args[1];
1175
+ if (!disputeId || !taskId) {
1176
+ throw new Error("Usage: mesh dispute accept <dispute-id> <task-id>");
1177
+ }
1178
+ const { client, keypair } = loadDisputeContext(deps);
1179
+ const result = await client.acceptResolution({ disputeId, taskId, signer: keypair });
1180
+ success(`Resolved dispute ${disputeId}`);
1181
+ console.log(`Requester Amount (SUI): ${formatMistToSui(result.requesterAmount)}`);
1182
+ console.log(`Provider Amount (SUI): ${formatMistToSui(result.providerAmount)}`);
1183
+ console.log(`Tx Digest: ${result.txDigest}`);
1184
+ return 0;
1185
+ }
1186
+ async function showStatus(args, deps) {
1187
+ const { client } = loadDisputeContext(deps);
1188
+ if (args[0] === "--task") {
1189
+ const taskId = readRequiredFlagValue(args, "--task");
1190
+ const dispute2 = await client.getDisputeByTask(taskId);
1191
+ if (!dispute2) {
1192
+ throw new Error(`No dispute found for task ${taskId}.`);
1193
+ }
1194
+ return renderDisputeStatus(dispute2);
1195
+ }
1196
+ const disputeId = args[0]?.trim();
1197
+ if (!disputeId) {
1198
+ throw new Error("Usage: mesh dispute status <dispute-id> | mesh dispute status --task <task-id>");
1199
+ }
1200
+ const dispute = await client.getDispute(disputeId);
1201
+ if (!dispute) {
1202
+ throw new Error(`Dispute ${disputeId} was not found.`);
1203
+ }
1204
+ return renderDisputeStatus(dispute);
1205
+ }
1206
+ function renderDisputeStatus(dispute) {
1207
+ info(`Dispute ${dispute.id}`);
1208
+ table(
1209
+ ["Field", "Value"],
1210
+ [
1211
+ ["Task", dispute.taskId],
1212
+ ["Status", DisputeStatus[dispute.status] ?? "UNKNOWN"],
1213
+ ["Requester", dispute.requester],
1214
+ ["Provider", dispute.provider],
1215
+ ["Escrow (SUI)", formatMistToSui(dispute.escrowAmount)],
1216
+ ["Requester Proposal (SUI)", formatMistToSui(dispute.requesterProposedSplit)],
1217
+ ["Provider Proposal (SUI)", formatMistToSui(dispute.providerProposedSplit)],
1218
+ ["Evidence", dispute.requesterEvidenceBlob],
1219
+ ["Counter Evidence", dispute.providerEvidenceBlob ?? "-"],
1220
+ ["Arbitrator", dispute.arbitrator ?? "-"],
1221
+ ["Opened", new Date(dispute.openedAt).toISOString()],
1222
+ ["Resolved", dispute.resolvedAt ? new Date(dispute.resolvedAt).toISOString() : "-"]
1223
+ ]
1224
+ );
1225
+ return 0;
1226
+ }
1227
+ function loadDisputeContext(deps) {
1228
+ const config = (deps.loadConfig ?? loadMeshConfig)();
1229
+ if (!config.network.packageId) {
1230
+ throw new Error("network.packageId must be configured before disputing tasks.");
1231
+ }
1232
+ const identity = (deps.loadKeypair ?? loadOrCreateKeypair2)(config.identity.dataDir);
1233
+ const keypair = Ed25519Keypair2.fromSecretKey(identity.secretKey);
1234
+ const client = deps.createClient?.(config) ?? new DisputeClient(new MeshSuiClient3(config.network), config.network);
1235
+ return { config, keypair, client };
1236
+ }
1237
+ async function resolveEvidenceBlobId(args, deps) {
1238
+ const directBlobId = readOptionalFlag(args, "--evidence-blob-id");
1239
+ const inlineEvidence = readOptionalFlag(args, "--evidence");
1240
+ const filePath = readOptionalFlag(args, "--evidence-file");
1241
+ const providedSources = [directBlobId, inlineEvidence, filePath].filter((value) => value !== void 0);
1242
+ if (providedSources.length !== 1) {
1243
+ throw new Error("Specify exactly one of --evidence, --evidence-file, or --evidence-blob-id.");
1244
+ }
1245
+ if (directBlobId) {
1246
+ return directBlobId;
1247
+ }
1248
+ const readEvidenceFile = deps.readEvidenceFile ?? (async (path) => await readFile(path, "utf8"));
1249
+ const contents = inlineEvidence ?? (filePath ? await readEvidenceFile(filePath) : void 0);
1250
+ if (!contents) {
1251
+ throw new Error("Evidence is required. Use --evidence, --evidence-file, or --evidence-blob-id.");
1252
+ }
1253
+ const blobStore = deps.createBlobStore?.() ?? new WalrusBlobStore({
1254
+ publisherUrl: process.env.COLLECTIVE_WALRUS_PUBLISHER_URL ?? DEFAULT_WALRUS_PUBLISHER_URL,
1255
+ aggregatorUrl: process.env.COLLECTIVE_WALRUS_AGGREGATOR_URL ?? DEFAULT_WALRUS_AGGREGATOR_URL
1256
+ });
1257
+ const stored = await blobStore.store(new TextEncoder().encode(contents));
1258
+ return stored.blobId;
1259
+ }
1260
+ function readMistFlag(args, flag) {
1261
+ const value = readOptionalFlag(args, flag);
1262
+ if (!value || !/^\d+$/.test(value.trim())) {
1263
+ throw new Error(`Missing or invalid ${flag}.`);
1264
+ }
1265
+ return BigInt(value.trim());
1266
+ }
1267
+ function readOptionalFlag(args, flag) {
1268
+ const index = args.indexOf(flag);
1269
+ if (index < 0) {
1270
+ return void 0;
1271
+ }
1272
+ const value = args[index + 1]?.trim();
1273
+ if (!value || value.startsWith("--")) {
1274
+ throw new Error(`Missing value for ${flag}.`);
1275
+ }
1276
+ return value;
1277
+ }
1278
+ function readRequiredFlagValue(args, flag) {
1279
+ const value = readOptionalFlag(args, flag);
1280
+ if (!value) {
1281
+ throw new Error(`Missing value for ${flag}.`);
1282
+ }
1283
+ return value;
1284
+ }
1285
+
1286
+ // src/commands/init.ts
1287
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
1288
+ import { homedir as homedir2 } from "os";
1289
+ import { createDID as createDID2, identityKeyExists, loadOrCreateKeypair as loadOrCreateKeypair3 } from "@hivemind-os/collective-core";
1290
+ import { Ed25519Keypair as Ed25519Keypair3 } from "@mysten/sui/keypairs/ed25519";
1291
+ async function handleInit(args) {
1292
+ void args;
1293
+ const dataDir = getMeshDataDir();
1294
+ const configPath = getConfigPath();
1295
+ const configExists = existsSync3(configPath);
1296
+ const defaultConfig = buildDefaultConfig(dataDir);
1297
+ const keyExists = await identityKeyExists(defaultConfig.identity.dataDir);
1298
+ mkdirSync2(dataDir, { recursive: true });
1299
+ mkdirSync2(defaultConfig.identity.dataDir, { recursive: true });
1300
+ success(`Created data directory: ${displayPath(dataDir)}`);
1301
+ const identity = await loadOrCreateKeypair3(defaultConfig.identity.dataDir);
1302
+ const did = createDID2(identity.publicKey);
1303
+ const address = Ed25519Keypair3.fromSecretKey(identity.secretKey).getPublicKey().toSuiAddress();
1304
+ success(keyExists ? "Loaded identity key" : "Generated identity key");
1305
+ console.log(` DID: ${did}`);
1306
+ console.log(` Sui Address: ${address}`);
1307
+ if (!configExists) {
1308
+ saveMeshConfig(defaultConfig, configPath);
1309
+ }
1310
+ success(`${configExists ? "Using existing config" : "Created config"}: ${displayPath(configPath)}`);
1311
+ console.log("");
1312
+ console.log("Next steps:");
1313
+ console.log(" 1. Fund your wallet: mesh wallet fund");
1314
+ console.log(" 2. Start the daemon: mesh daemon start");
1315
+ console.log(" 3. Configure your MCP app to use: mesh connect");
1316
+ return 0;
1317
+ }
1318
+ function displayPath(value) {
1319
+ const home = homedir2();
1320
+ return value.startsWith(home) ? `~${value.slice(home.length)}` : value;
1321
+ }
1322
+
1323
+ // src/commands/logs.ts
1324
+ import { createReadStream, existsSync as existsSync4, readFileSync as readFileSync4, watchFile } from "fs";
1325
+ async function handleLogs(args) {
1326
+ const lines = Number.parseInt(readFlag(args, "--lines") ?? "50", 10);
1327
+ const follow = args.includes("--follow");
1328
+ const config = loadMeshConfig();
1329
+ const logFile = config.daemon.logFile;
1330
+ if (!logFile || !existsSync4(logFile)) {
1331
+ throw new Error("Daemon log file does not exist yet. Start the daemon first.");
1332
+ }
1333
+ const contents = readFileSync4(logFile, "utf8");
1334
+ const selected = contents.split(/\r?\n/).slice(-Math.max(1, lines)).join("\n").trim();
1335
+ if (selected) {
1336
+ console.log(selected);
1337
+ }
1338
+ if (!follow) {
1339
+ return 0;
1340
+ }
1341
+ info(`Following ${logFile}`);
1342
+ watchFile(logFile, { interval: 500 }, (current, previous) => {
1343
+ if (current.size <= previous.size) {
1344
+ return;
1345
+ }
1346
+ const stream = createReadStream(logFile, {
1347
+ encoding: "utf8",
1348
+ start: previous.size,
1349
+ end: current.size
1350
+ });
1351
+ stream.on("data", (chunk) => {
1352
+ process.stdout.write(chunk);
1353
+ });
1354
+ });
1355
+ await new Promise(() => void 0);
1356
+ return 0;
1357
+ }
1358
+ function readFlag(args, flag) {
1359
+ const index = args.indexOf(flag);
1360
+ return index >= 0 ? args[index + 1] : void 0;
1361
+ }
1362
+
1363
+ // src/commands/marketplace.ts
1364
+ import { readFile as readFile2 } from "fs/promises";
1365
+ import {
1366
+ DEFAULT_WALRUS_AGGREGATOR_URL as DEFAULT_WALRUS_AGGREGATOR_URL2,
1367
+ DEFAULT_WALRUS_PUBLISHER_URL as DEFAULT_WALRUS_PUBLISHER_URL2,
1368
+ loadOrCreateKeypair as loadOrCreateKeypair4,
1369
+ MarketplaceClient,
1370
+ MeshSuiClient as MeshSuiClient4,
1371
+ WalrusBlobStore as WalrusBlobStore2
1372
+ } from "@hivemind-os/collective-core";
1373
+ import { Ed25519Keypair as Ed25519Keypair4 } from "@mysten/sui/keypairs/ed25519";
1374
+ async function handleMarketplace(subcommand, args = [], deps = {}) {
1375
+ switch (subcommand) {
1376
+ case "post":
1377
+ return await postMarketplaceTask(args, deps);
1378
+ case "browse":
1379
+ return await browseMarketplaceTasks(args, deps);
1380
+ case "bid":
1381
+ return await placeMarketplaceBid(args, deps);
1382
+ case "accept-bid":
1383
+ return await acceptMarketplaceBid(args, deps);
1384
+ default:
1385
+ throw new Error("Usage: mesh marketplace <post|browse|bid|accept-bid>");
1386
+ }
1387
+ }
1388
+ async function postMarketplaceTask(args, deps) {
1389
+ const capability = args[0];
1390
+ if (!capability) {
1391
+ throw new Error("Usage: mesh marketplace post <capability> --category <category> --price-mist <mist> (--input <text> | --input-file <path> | --input-blob-id <id>) [--agreement-hash <value>] [--dispute-window-ms <ms>] [--expiry-hours <hours>]");
1392
+ }
1393
+ const category = readRequiredFlag(args, "--category");
1394
+ const priceMist = readMistFlag2(args, "--price-mist");
1395
+ const inputBlobId = await resolveInputBlobId(args, deps);
1396
+ const agreementHash = readOptionalFlag2(args, "--agreement-hash");
1397
+ const disputeWindowMs = readOptionalInteger(args, "--dispute-window-ms") ?? 6e4;
1398
+ const expiryHours = readOptionalInteger(args, "--expiry-hours") ?? 24;
1399
+ const { client, keypair } = loadMarketplaceContext(deps);
1400
+ const result = await client.postOpenTask({
1401
+ capability,
1402
+ category,
1403
+ inputBlobId,
1404
+ agreementHash,
1405
+ priceMist,
1406
+ disputeWindowMs,
1407
+ expiryHours,
1408
+ signer: keypair
1409
+ });
1410
+ success(`Posted marketplace task ${result.taskId}`);
1411
+ console.log(`Category: ${category}`);
1412
+ console.log(`Input Blob: ${inputBlobId}`);
1413
+ console.log(`Tx Digest: ${result.txDigest}`);
1414
+ return 0;
1415
+ }
1416
+ async function browseMarketplaceTasks(args, deps) {
1417
+ const { client } = loadMarketplaceContext(deps);
1418
+ const tasks = await client.browseOpenTasks({
1419
+ category: readOptionalFlag2(args, "--category"),
1420
+ minPriceMist: readOptionalMist(args, "--min-price-mist"),
1421
+ maxPriceMist: readOptionalMist(args, "--max-price-mist"),
1422
+ limit: readOptionalInteger(args, "--limit") ?? 20
1423
+ });
1424
+ info(`Found ${tasks.length} open marketplace task(s).`);
1425
+ table(
1426
+ ["Task", "Category", "Capability", "Price (MIST)", "Requester"],
1427
+ tasks.map((task) => [task.id, task.category, task.capability, task.price.toString(), task.requester])
1428
+ );
1429
+ return 0;
1430
+ }
1431
+ async function placeMarketplaceBid(args, deps) {
1432
+ const taskId = args[0];
1433
+ if (!taskId) {
1434
+ throw new Error("Usage: mesh marketplace bid <task-id> --price-mist <mist> [--reputation-score <score>] [--evidence <text>]");
1435
+ }
1436
+ const { client, keypair } = loadMarketplaceContext(deps);
1437
+ const result = await client.placeBid({
1438
+ taskId,
1439
+ bidPriceMist: readMistFlag2(args, "--price-mist"),
1440
+ reputationScore: readOptionalMist(args, "--reputation-score"),
1441
+ evidenceBlob: readOptionalFlag2(args, "--evidence"),
1442
+ signer: keypair
1443
+ });
1444
+ success(`Placed bid ${result.bidId}`);
1445
+ console.log(`Task ID: ${taskId}`);
1446
+ console.log(`Reputation Score: ${result.reputationScore.toString()}`);
1447
+ console.log(`Tx Digest: ${result.txDigest}`);
1448
+ return 0;
1449
+ }
1450
+ async function acceptMarketplaceBid(args, deps) {
1451
+ const taskId = args[0];
1452
+ const bidId = args[1];
1453
+ if (!taskId || !bidId) {
1454
+ throw new Error("Usage: mesh marketplace accept-bid <task-id> <bid-id> [--keep-other-bids]");
1455
+ }
1456
+ const { client, keypair } = loadMarketplaceContext(deps);
1457
+ const result = await client.acceptBid({
1458
+ taskId,
1459
+ bidId,
1460
+ rejectCompeting: !args.includes("--keep-other-bids"),
1461
+ signer: keypair
1462
+ });
1463
+ success(`Accepted bid ${bidId}`);
1464
+ console.log(`Rejected competing bids: ${result.rejectedBidIds.length}`);
1465
+ console.log(`Tx Digest: ${result.txDigest}`);
1466
+ return 0;
1467
+ }
1468
+ function loadMarketplaceContext(deps) {
1469
+ const config = (deps.loadConfig ?? loadMeshConfig)();
1470
+ if (!config.network.packageId) {
1471
+ throw new Error("network.packageId must be configured before using marketplace commands.");
1472
+ }
1473
+ const identity = (deps.loadKeypair ?? loadOrCreateKeypair4)(config.identity.dataDir);
1474
+ const keypair = Ed25519Keypair4.fromSecretKey(identity.secretKey);
1475
+ const client = deps.createClient?.(config) ?? new MarketplaceClient(new MeshSuiClient4(config.network), config.network);
1476
+ return { config, keypair, client };
1477
+ }
1478
+ async function resolveInputBlobId(args, deps) {
1479
+ const directBlobId = readOptionalFlag2(args, "--input-blob-id");
1480
+ const inlineInput = readOptionalFlag2(args, "--input");
1481
+ const filePath = readOptionalFlag2(args, "--input-file");
1482
+ const providedSources = [directBlobId, inlineInput, filePath].filter((value) => value !== void 0);
1483
+ if (providedSources.length !== 1) {
1484
+ throw new Error("Specify exactly one of --input, --input-file, or --input-blob-id.");
1485
+ }
1486
+ if (directBlobId) {
1487
+ return directBlobId;
1488
+ }
1489
+ const readInputFile = deps.readInputFile ?? (async (path) => await readFile2(path, "utf8"));
1490
+ const contents = inlineInput ?? (filePath ? await readInputFile(filePath) : void 0);
1491
+ if (!contents) {
1492
+ throw new Error("Task input is required. Use --input, --input-file, or --input-blob-id.");
1493
+ }
1494
+ const blobStore = deps.createBlobStore?.() ?? new WalrusBlobStore2({
1495
+ publisherUrl: process.env.COLLECTIVE_WALRUS_PUBLISHER_URL ?? DEFAULT_WALRUS_PUBLISHER_URL2,
1496
+ aggregatorUrl: process.env.COLLECTIVE_WALRUS_AGGREGATOR_URL ?? DEFAULT_WALRUS_AGGREGATOR_URL2
1497
+ });
1498
+ const stored = await blobStore.store(new TextEncoder().encode(contents));
1499
+ return stored.blobId;
1500
+ }
1501
+ function readMistFlag2(args, flag) {
1502
+ const value = readOptionalFlag2(args, flag);
1503
+ if (!value || !/^\d+$/.test(value.trim())) {
1504
+ throw new Error(`Missing or invalid ${flag}.`);
1505
+ }
1506
+ return BigInt(value.trim());
1507
+ }
1508
+ function readOptionalMist(args, flag) {
1509
+ const value = readOptionalFlag2(args, flag);
1510
+ if (!value) {
1511
+ return void 0;
1512
+ }
1513
+ if (!/^\d+$/.test(value.trim())) {
1514
+ throw new Error(`Missing or invalid ${flag}.`);
1515
+ }
1516
+ return BigInt(value.trim());
1517
+ }
1518
+ function readOptionalInteger(args, flag) {
1519
+ const value = readOptionalFlag2(args, flag);
1520
+ if (!value) {
1521
+ return void 0;
1522
+ }
1523
+ const parsed = Number(value);
1524
+ if (!Number.isSafeInteger(parsed) || parsed < 0) {
1525
+ throw new Error(`Missing or invalid ${flag}.`);
1526
+ }
1527
+ return parsed;
1528
+ }
1529
+ function readRequiredFlag(args, flag) {
1530
+ const value = readOptionalFlag2(args, flag);
1531
+ if (!value) {
1532
+ throw new Error(`Missing required ${flag}.`);
1533
+ }
1534
+ return value;
1535
+ }
1536
+ function readOptionalFlag2(args, flag) {
1537
+ const index = args.indexOf(flag);
1538
+ if (index < 0) {
1539
+ return void 0;
1540
+ }
1541
+ const value = args[index + 1]?.trim();
1542
+ if (!value || value.startsWith("--")) {
1543
+ throw new Error(`Missing value for ${flag}.`);
1544
+ }
1545
+ return value;
1546
+ }
1547
+
1548
+ // src/commands/metering.ts
1549
+ import { loadConfig as loadDaemonConfig } from "@hivemind-os/collective-daemon/config";
1550
+ import { DaemonState } from "@hivemind-os/collective-daemon/state";
1551
+ import {
1552
+ runMeshMeteredExecute,
1553
+ runMeshVerifyResult
1554
+ } from "@hivemind-os/collective-mcp-server";
1555
+ import { MeshSuiClient as MeshSuiClient5, TaskClient } from "@hivemind-os/collective-core";
1556
+ import { PaymentScheme, TaskStatus } from "@hivemind-os/collective-types";
1557
+ async function handleMetering(subcommand, args = [], deps = {}) {
1558
+ switch (subcommand) {
1559
+ case "execute":
1560
+ return await handleMeteringExecute(args, deps);
1561
+ case "verify":
1562
+ return await handleMeteringVerify(args, deps);
1563
+ case "status":
1564
+ return await handleMeteringStatus(args);
1565
+ default:
1566
+ throw new Error("Usage: mesh metering <execute|verify|status>");
1567
+ }
1568
+ }
1569
+ async function handleMeteringExecute(args, deps) {
1570
+ const capability = readRequiredFlag2(args, "--capability");
1571
+ const input = readRequiredFlag2(args, "--input");
1572
+ const maxPriceMist = readRequiredInteger(args, "--max-price-mist");
1573
+ const unitPriceMist = readRequiredInteger(args, "--unit-price-mist");
1574
+ const providerDid = readOptionalFlag3(args, "--provider-did");
1575
+ const timeoutSeconds = readOptionalInteger2(args, "--timeout-seconds");
1576
+ const config = deps.loadConfig?.() ?? loadDaemonConfig();
1577
+ const state = await (deps.createState?.(config) ?? DaemonState.create(config));
1578
+ try {
1579
+ const result = await (deps.runMeteredExecute ?? runMeshMeteredExecute)({
1580
+ capability,
1581
+ input,
1582
+ provider_did: providerDid,
1583
+ max_price_mist: maxPriceMist,
1584
+ unit_price_mist: unitPriceMist,
1585
+ timeout_seconds: timeoutSeconds
1586
+ }, toMeshToolContext(state));
1587
+ success(`Metered task ${result.task_id}`);
1588
+ table(
1589
+ ["Field", "Value"],
1590
+ [
1591
+ ["Provider", result.provider_did],
1592
+ ["Price (SUI)", formatMistToSui(BigInt(result.actual_price_mist))],
1593
+ ["Max Price (SUI)", formatMistToSui(BigInt(result.max_price_mist))],
1594
+ ["Unit Price (SUI)", formatMistToSui(BigInt(result.unit_price_mist))],
1595
+ ["Units", result.metered_units.toString()],
1596
+ ["Verified", result.verified ? "yes" : "no"]
1597
+ ]
1598
+ );
1599
+ console.log(result.result);
1600
+ return 0;
1601
+ } finally {
1602
+ await state.shutdown();
1603
+ }
1604
+ }
1605
+ async function handleMeteringVerify(args, deps) {
1606
+ const taskId = args[0]?.trim();
1607
+ if (!taskId) {
1608
+ throw new Error("Usage: mesh metering verify <task-id>");
1609
+ }
1610
+ const config = deps.loadConfig?.() ?? loadDaemonConfig();
1611
+ const state = await (deps.createState?.(config) ?? DaemonState.create(config));
1612
+ try {
1613
+ const result = await (deps.runVerify ?? runMeshVerifyResult)({ task_id: taskId }, toMeshToolContext(state));
1614
+ success(`Verification ${result.verified ? "passed" : "failed"} for ${result.task_id}`);
1615
+ table(
1616
+ ["Field", "Value"],
1617
+ [
1618
+ ["Verified", result.verified ? "yes" : "no"],
1619
+ ["Units", result.metered_units.toString()],
1620
+ ["Verification Hash", result.verification_hash ?? "-"]
1621
+ ]
1622
+ );
1623
+ return result.verified ? 0 : 1;
1624
+ } finally {
1625
+ await state.shutdown();
1626
+ }
1627
+ }
1628
+ async function handleMeteringStatus(args) {
1629
+ const taskId = args[0]?.trim();
1630
+ if (!taskId) {
1631
+ throw new Error("Usage: mesh metering status <task-id>");
1632
+ }
1633
+ const config = loadMeshConfig();
1634
+ const taskClient = new TaskClient(new MeshSuiClient5(config.network), config.network);
1635
+ const task = await taskClient.getTask(taskId);
1636
+ if (!task) {
1637
+ throw new Error(`Task ${taskId} was not found.`);
1638
+ }
1639
+ success(`Metered task ${task.id}`);
1640
+ table(
1641
+ ["Field", "Value"],
1642
+ [
1643
+ ["Status", TaskStatus[task.status] ?? "UNKNOWN"],
1644
+ ["Scheme", task.paymentScheme ? PaymentScheme[task.paymentScheme] : "EXACT"],
1645
+ ["Actual Price (SUI)", formatMistToSui(task.price)],
1646
+ ["Max Price (SUI)", formatMistToSui(task.maxPrice ?? task.price)],
1647
+ ["Unit Price (SUI)", formatMistToSui(task.unitPrice ?? 0n)],
1648
+ ["Units", task.meteredUnits?.toString() ?? "0"],
1649
+ ["Verification Hash", task.verificationHash ?? "-"],
1650
+ ["Provider", task.provider ?? "-"]
1651
+ ]
1652
+ );
1653
+ return 0;
1654
+ }
1655
+ function toMeshToolContext(state) {
1656
+ return {
1657
+ did: state.did,
1658
+ keypair: state.keypair,
1659
+ suiClient: state.suiClient,
1660
+ registryClient: state.registryClient,
1661
+ taskClient: state.taskClient,
1662
+ agentCache: state.agentCache,
1663
+ blobStore: state.blobStore,
1664
+ spendingPolicy: state.spendingPolicy,
1665
+ networkConfig: state.network,
1666
+ relayAuthProvider: state.relayAuthProvider,
1667
+ x402Client: state.x402Client
1668
+ };
1669
+ }
1670
+ function readRequiredFlag2(args, flag) {
1671
+ const value = readOptionalFlag3(args, flag);
1672
+ if (!value) {
1673
+ throw new Error("Usage: mesh metering execute --capability <cap> --input <text> --max-price-mist <mist> --unit-price-mist <mist> [--provider-did <did>] [--timeout-seconds <seconds>]");
1674
+ }
1675
+ return value;
1676
+ }
1677
+ function readRequiredInteger(args, flag) {
1678
+ const value = readOptionalInteger2(args, flag);
1679
+ if (value === void 0) {
1680
+ throw new Error(`Missing or invalid ${flag}.`);
1681
+ }
1682
+ return value;
1683
+ }
1684
+ function readOptionalInteger2(args, flag) {
1685
+ const value = readOptionalFlag3(args, flag);
1686
+ if (!value) {
1687
+ return void 0;
1688
+ }
1689
+ const parsed = Number(value);
1690
+ if (!Number.isSafeInteger(parsed) || parsed < 0) {
1691
+ throw new Error(`Missing or invalid ${flag}.`);
1692
+ }
1693
+ return parsed;
1694
+ }
1695
+ function readOptionalFlag3(args, flag) {
1696
+ const index = args.indexOf(flag);
1697
+ if (index < 0) {
1698
+ return void 0;
1699
+ }
1700
+ const value = args[index + 1]?.trim();
1701
+ if (!value || value.startsWith("--")) {
1702
+ throw new Error(`Missing value for ${flag}.`);
1703
+ }
1704
+ return value;
1705
+ }
1706
+
1707
+ // src/commands/multi-execute.ts
1708
+ import { loadConfig as loadDaemonConfig2 } from "@hivemind-os/collective-daemon/config";
1709
+ import { DaemonState as DaemonState2 } from "@hivemind-os/collective-daemon/state";
1710
+ import {
1711
+ runMeshMultiExecute
1712
+ } from "@hivemind-os/collective-mcp-server";
1713
+ import { AggregationMode, ProviderSelectionStrategy } from "@hivemind-os/collective-types";
1714
+ async function handleMultiExecute(args = [], deps = {}) {
1715
+ const capability = readRequiredFlag3(args, "--capability");
1716
+ const input = parseJsonInput(readRequiredFlag3(args, "--input"));
1717
+ const fanOutCount = readOptionalInteger3(args, "--fan-out");
1718
+ const strategy = readOptionalStrategy(args, "--strategy");
1719
+ const aggregation = readOptionalAggregation(args, "--aggregation");
1720
+ const maxPricePerProvider = readOptionalInteger3(args, "--max-price-per-provider");
1721
+ const timeout = readOptionalInteger3(args, "--timeout");
1722
+ const config = deps.loadConfig?.() ?? loadDaemonConfig2();
1723
+ const state = await (deps.createState?.(config) ?? DaemonState2.create(config));
1724
+ try {
1725
+ const result = await (deps.runMultiExecute ?? runMeshMultiExecute)({
1726
+ capability,
1727
+ input,
1728
+ fanOutCount,
1729
+ strategy,
1730
+ aggregation,
1731
+ maxPricePerProvider,
1732
+ timeout
1733
+ }, toMeshToolContext2(state));
1734
+ info(`Selected ${result.providers.length} provider(s) for ${result.capability}.`);
1735
+ table(
1736
+ ["Provider", "Price (MIST)", "Reputation", "Latency (ms)"],
1737
+ result.providers.map((provider) => [
1738
+ provider.did,
1739
+ provider.price_mist,
1740
+ provider.reputation.toFixed(2),
1741
+ provider.estimated_latency_ms?.toString() ?? "-"
1742
+ ])
1743
+ );
1744
+ table(
1745
+ ["Provider", "Status", "Duration (ms)", "Summary"],
1746
+ result.results.map((entry) => [
1747
+ entry.provider,
1748
+ entry.status,
1749
+ entry.duration_ms.toString(),
1750
+ entry.error ?? summarizeValue(entry.result)
1751
+ ])
1752
+ );
1753
+ success(`Total cost: ${result.total_cost_mist} MIST`);
1754
+ if (result.aggregated_result !== void 0) {
1755
+ console.log(JSON.stringify(result.aggregated_result, null, 2));
1756
+ }
1757
+ return 0;
1758
+ } finally {
1759
+ await state.shutdown();
1760
+ }
1761
+ }
1762
+ function toMeshToolContext2(state) {
1763
+ return {
1764
+ did: state.did,
1765
+ keypair: state.keypair,
1766
+ suiClient: state.suiClient,
1767
+ registryClient: state.registryClient,
1768
+ taskClient: state.taskClient,
1769
+ agentCache: state.agentCache,
1770
+ blobStore: state.blobStore,
1771
+ spendingPolicy: state.spendingPolicy,
1772
+ networkConfig: state.network,
1773
+ relayAuthProvider: state.relayAuthProvider,
1774
+ x402Client: state.x402Client
1775
+ };
1776
+ }
1777
+ function summarizeValue(value) {
1778
+ if (value === void 0) {
1779
+ return "-";
1780
+ }
1781
+ if (typeof value === "string") {
1782
+ return value;
1783
+ }
1784
+ return JSON.stringify(value);
1785
+ }
1786
+ function parseJsonInput(value) {
1787
+ try {
1788
+ return JSON.parse(value);
1789
+ } catch {
1790
+ throw new Error("Invalid --input JSON.");
1791
+ }
1792
+ }
1793
+ function readOptionalStrategy(args, flag) {
1794
+ const value = readOptionalFlag4(args, flag);
1795
+ if (!value) {
1796
+ return void 0;
1797
+ }
1798
+ if (Object.values(ProviderSelectionStrategy).includes(value)) {
1799
+ return value;
1800
+ }
1801
+ throw new Error(`Invalid ${flag}.`);
1802
+ }
1803
+ function readOptionalAggregation(args, flag) {
1804
+ const value = readOptionalFlag4(args, flag);
1805
+ if (!value) {
1806
+ return void 0;
1807
+ }
1808
+ if (Object.values(AggregationMode).includes(value)) {
1809
+ return value;
1810
+ }
1811
+ throw new Error(`Invalid ${flag}.`);
1812
+ }
1813
+ function readOptionalInteger3(args, flag) {
1814
+ const value = readOptionalFlag4(args, flag);
1815
+ if (!value) {
1816
+ return void 0;
1817
+ }
1818
+ const parsed = Number(value);
1819
+ if (!Number.isSafeInteger(parsed) || parsed < 0) {
1820
+ throw new Error(`Missing or invalid ${flag}.`);
1821
+ }
1822
+ return parsed;
1823
+ }
1824
+ function readRequiredFlag3(args, flag) {
1825
+ const value = readOptionalFlag4(args, flag);
1826
+ if (!value) {
1827
+ throw new Error("Usage: mesh multi-execute --capability <cap> --input <json> [--fan-out <n>] [--strategy <strategy>] [--aggregation <mode>] [--max-price-per-provider <mist>] [--timeout <ms>]");
1828
+ }
1829
+ return value;
1830
+ }
1831
+ function readOptionalFlag4(args, flag) {
1832
+ const index = args.indexOf(flag);
1833
+ if (index < 0) {
1834
+ return void 0;
1835
+ }
1836
+ const value = args[index + 1]?.trim();
1837
+ if (!value || value.startsWith("--")) {
1838
+ throw new Error(`Missing value for ${flag}.`);
1839
+ }
1840
+ return value;
1841
+ }
1842
+
1843
+ // src/commands/policy.ts
1844
+ import { PaymentRail as PaymentRail2 } from "@hivemind-os/collective-types";
1845
+ async function handlePolicy(subcommand, args = []) {
1846
+ if (subcommand !== "set") {
1847
+ throw new Error("Usage: mesh policy set [--daily <amount_sui>] [--per-task <amount_sui>]");
1848
+ }
1849
+ const daily = readFlag2(args, "--daily");
1850
+ const perTask = readFlag2(args, "--per-task");
1851
+ if (!daily && !perTask) {
1852
+ throw new Error("Provide at least one policy flag: --daily or --per-task");
1853
+ }
1854
+ const config = loadMeshConfig();
1855
+ if (daily) {
1856
+ upsertLimit(config, "day", parseSuiToMist(daily));
1857
+ }
1858
+ if (perTask) {
1859
+ upsertLimit(config, "transaction", parseSuiToMist(perTask));
1860
+ }
1861
+ saveMeshConfig(config);
1862
+ success("Updated spending policy.");
1863
+ return 0;
1864
+ }
1865
+ function upsertLimit(config, interval, amount) {
1866
+ const existing = config.spending.limits.find((limit) => limit.interval === interval);
1867
+ if (existing) {
1868
+ existing.amount = amount;
1869
+ existing.rail = PaymentRail2.SUI_ESCROW;
1870
+ return;
1871
+ }
1872
+ config.spending.limits.push({
1873
+ amount,
1874
+ interval,
1875
+ rail: PaymentRail2.SUI_ESCROW
1876
+ });
1877
+ }
1878
+ function readFlag2(args, flag) {
1879
+ const index = args.indexOf(flag);
1880
+ return index >= 0 ? args[index + 1] : void 0;
1881
+ }
1882
+
1883
+ // src/commands/register.ts
1884
+ import { readFileSync as readFileSync5 } from "fs";
1885
+ import { resolve as resolve4 } from "path";
1886
+ import { createDID as createDID3, ed25519ToX25519, loadOrCreateKeypair as loadOrCreateKeypair5, MeshSuiClient as MeshSuiClient6, RegistryClient as RegistryClient2 } from "@hivemind-os/collective-core";
1887
+ import { PaymentRail as PaymentRail3 } from "@hivemind-os/collective-types";
1888
+ import { Ed25519Keypair as Ed25519Keypair5 } from "@mysten/sui/keypairs/ed25519";
1889
+ import yaml2 from "js-yaml";
1890
+ async function handleRegister(args) {
1891
+ const definition = loadProviderDefinition(args);
1892
+ const config = loadMeshConfig();
1893
+ assertNetworkConfigured(config.network);
1894
+ const identity = await loadOrCreateKeypair5(config.identity.dataDir);
1895
+ const did = createDID3(identity.publicKey);
1896
+ const keypair = Ed25519Keypair5.fromSecretKey(identity.secretKey);
1897
+ const encryptionKeyPair = ed25519ToX25519(identity.secretKey);
1898
+ const suiClient = new MeshSuiClient6(config.network);
1899
+ const registryClient = new RegistryClient2(suiClient, config.network);
1900
+ const result = await registryClient.registerAgent({
1901
+ name: definition.name,
1902
+ did,
1903
+ description: definition.description,
1904
+ capabilities: definition.capabilities,
1905
+ endpoint: `mesh://agent/${did}`,
1906
+ encryptionPublicKey: encryptionKeyPair.publicKey,
1907
+ keypair
1908
+ });
1909
+ success("Provider registered on Agentic Mesh.");
1910
+ console.log(`Agent Card ID: ${result.agentCardId}`);
1911
+ console.log(`DID: ${did}`);
1912
+ console.log(`Tx Digest: ${result.txDigest}`);
1913
+ return 0;
1914
+ }
1915
+ function loadProviderDefinition(args) {
1916
+ const configFlagIndex = args.indexOf("--config");
1917
+ if (configFlagIndex >= 0) {
1918
+ const configPath = args[configFlagIndex + 1];
1919
+ if (!configPath) {
1920
+ throw new Error("Usage: mesh register --config <path>");
1921
+ }
1922
+ return parseProviderConfigFile(resolve4(configPath));
1923
+ }
1924
+ const name = readFlag3(args, "--name");
1925
+ const description = readFlag3(args, "--description") ?? `${name ?? "Agent"} provider`;
1926
+ const capabilityFlags = readFlags(args, "--capability");
1927
+ if (!name || capabilityFlags.length === 0) {
1928
+ throw new Error('Usage: mesh register --name <name> --capability "name:description:version:price_mist"');
1929
+ }
1930
+ return {
1931
+ name,
1932
+ description,
1933
+ capabilities: capabilityFlags.map(parseInlineCapability)
1934
+ };
1935
+ }
1936
+ function parseProviderConfigFile(path) {
1937
+ const loaded = yaml2.load(readFileSync5(path, "utf8"));
1938
+ if (!loaded || typeof loaded !== "object" || Array.isArray(loaded)) {
1939
+ throw new Error(`Invalid provider config: ${path}`);
1940
+ }
1941
+ const record = loaded;
1942
+ const name = asString(record.name);
1943
+ const description = asString(record.description) ?? `${name ?? "Agent"} provider`;
1944
+ const capabilitiesRaw = Array.isArray(record.capabilities) ? record.capabilities : [];
1945
+ const capabilities = capabilitiesRaw.map((entry, index) => parseCapabilityRecord(entry, index));
1946
+ if (!name || capabilities.length === 0) {
1947
+ throw new Error("Provider config must include name and at least one capability.");
1948
+ }
1949
+ return { name, description, capabilities };
1950
+ }
1951
+ function parseCapabilityRecord(value, index) {
1952
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1953
+ throw new Error(`capabilities[${index}] must be an object.`);
1954
+ }
1955
+ const record = value;
1956
+ const pricing = record.pricing && typeof record.pricing === "object" && !Array.isArray(record.pricing) ? record.pricing : void 0;
1957
+ const amount = pricing?.amount ?? record.priceMist ?? record.price_mist ?? record.price;
1958
+ const name = asString(record.name);
1959
+ const description = asString(record.description);
1960
+ const version = asString(record.version);
1961
+ if (!name || !description || !version || amount === void 0) {
1962
+ throw new Error(`capabilities[${index}] is missing required fields.`);
1963
+ }
1964
+ return buildCapability(name, description, version, amount);
1965
+ }
1966
+ function parseInlineCapability(value) {
1967
+ const parts = value.split(":");
1968
+ if (parts.length < 4) {
1969
+ throw new Error(`Invalid capability format: ${value}`);
1970
+ }
1971
+ const [name, description, version, ...priceParts] = parts;
1972
+ return buildCapability(name, description, version, priceParts.join(":"));
1973
+ }
1974
+ function buildCapability(name, description, version, amount) {
1975
+ return {
1976
+ name,
1977
+ description,
1978
+ version,
1979
+ pricing: {
1980
+ rail: PaymentRail3.SUI_ESCROW,
1981
+ amount: parseMistAmount(amount),
1982
+ currency: "MIST"
1983
+ }
1984
+ };
1985
+ }
1986
+ function parseMistAmount(value) {
1987
+ if (typeof value === "bigint") {
1988
+ return value;
1989
+ }
1990
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
1991
+ return BigInt(Math.floor(value));
1992
+ }
1993
+ if (typeof value === "string" && /^\d+$/.test(value.trim())) {
1994
+ return BigInt(value.trim());
1995
+ }
1996
+ throw new Error(`Invalid MIST amount: ${String(value)}`);
1997
+ }
1998
+ function readFlag3(args, flag) {
1999
+ const index = args.indexOf(flag);
2000
+ return index >= 0 ? args[index + 1] : void 0;
2001
+ }
2002
+ function readFlags(args, flag) {
2003
+ const values = [];
2004
+ for (let index = 0; index < args.length; index += 1) {
2005
+ if (args[index] === flag && args[index + 1]) {
2006
+ values.push(args[index + 1]);
2007
+ }
2008
+ }
2009
+ return values;
2010
+ }
2011
+ function assertNetworkConfigured(network) {
2012
+ if (!network.packageId || !network.registryId) {
2013
+ throw new Error("network.packageId and network.registryId must be configured before registering.");
2014
+ }
2015
+ }
2016
+ function asString(value) {
2017
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
2018
+ }
2019
+
2020
+ // src/commands/relay-registry.ts
2021
+ import { loadOrCreateKeypair as loadOrCreateKeypair6, MeshSuiClient as MeshSuiClient7, RelayRegistryClient } from "@hivemind-os/collective-core";
2022
+ import { Ed25519Keypair as Ed25519Keypair6 } from "@mysten/sui/keypairs/ed25519";
2023
+ async function handleRelayRegistry(subcommand, args = [], deps = {}) {
2024
+ switch (subcommand) {
2025
+ case "register":
2026
+ return await registerRelay(args, deps);
2027
+ case "list":
2028
+ return await listRelays(deps);
2029
+ case "heartbeat":
2030
+ return await heartbeatRelay(args, deps);
2031
+ case "deactivate":
2032
+ return await deactivateRelay(args, deps);
2033
+ default:
2034
+ throw new Error("Usage: mesh relay <register|list|heartbeat|deactivate>");
2035
+ }
2036
+ }
2037
+ async function registerRelay(args, deps) {
2038
+ const endpoint = readRequiredFlag4(args, "--endpoint");
2039
+ const stakeId = readRequiredFlag4(args, "--stake-id");
2040
+ const region = readRequiredFlag4(args, "--region");
2041
+ const fee = Number(readRequiredFlag4(args, "--fee"));
2042
+ if (!Number.isInteger(fee) || fee < 0 || fee > 1e4) {
2043
+ throw new Error("Usage: mesh relay register --endpoint <url> --stake-id <id> --region <region> --fee <bps> [--capabilities a,b]");
2044
+ }
2045
+ const capabilities = readCapabilities(args);
2046
+ const { client, keypair } = loadRelayContext(deps);
2047
+ const result = await client.registerRelay({
2048
+ endpoint,
2049
+ stakeId,
2050
+ region,
2051
+ routingFeeBps: fee,
2052
+ capabilities,
2053
+ signer: keypair
2054
+ });
2055
+ success("Relay registered.");
2056
+ console.log(`Relay ID: ${result.relayId}`);
2057
+ console.log(`Tx Digest: ${result.txDigest}`);
2058
+ console.log(`Capabilities: ${capabilities.join(", ")}`);
2059
+ return 0;
2060
+ }
2061
+ async function listRelays(deps) {
2062
+ const { client } = loadRelayContext(deps);
2063
+ const relays = await client.listRelays();
2064
+ info(`Found ${relays.length} active relay(s).`);
2065
+ table(
2066
+ ["Relay ID", "Region", "Fee (bps)", "Stake (SUI)", "Routed", "Fees Earned (SUI)", "Endpoint"],
2067
+ relays.map((relay) => summarizeRelay(relay))
2068
+ );
2069
+ return 0;
2070
+ }
2071
+ async function heartbeatRelay(args, deps) {
2072
+ const relayId = readRequiredFlag4(args, "--relay-id");
2073
+ const { client, keypair } = loadRelayContext(deps);
2074
+ const result = await client.heartbeat({ relayId, signer: keypair });
2075
+ success("Relay heartbeat submitted.");
2076
+ console.log(`Last Heartbeat: ${new Date(result.lastHeartbeat).toISOString()}`);
2077
+ console.log(`Tx Digest: ${result.txDigest}`);
2078
+ return 0;
2079
+ }
2080
+ async function deactivateRelay(args, deps) {
2081
+ const relayId = readRequiredFlag4(args, "--relay-id");
2082
+ const { client, keypair } = loadRelayContext(deps);
2083
+ const result = await client.deactivateRelay({ relayId, signer: keypair });
2084
+ success("Relay deactivated.");
2085
+ console.log(`Tx Digest: ${result.txDigest}`);
2086
+ return 0;
2087
+ }
2088
+ function loadRelayContext(deps) {
2089
+ const config = (deps.loadConfig ?? loadMeshConfig)();
2090
+ if (!config.network.packageId) {
2091
+ throw new Error("network.packageId must be configured before using relay registry commands.");
2092
+ }
2093
+ const identity = (deps.loadKeypair ?? loadOrCreateKeypair6)(config.identity.dataDir);
2094
+ const keypair = Ed25519Keypair6.fromSecretKey(identity.secretKey);
2095
+ const client = deps.createClient?.(config) ?? new RelayRegistryClient(new MeshSuiClient7(config.network), config.network);
2096
+ return { config, keypair, client };
2097
+ }
2098
+ function readRequiredFlag4(args, flag) {
2099
+ const index = args.indexOf(flag);
2100
+ const value = index >= 0 ? args[index + 1]?.trim() : "";
2101
+ if (!value) {
2102
+ throw new Error(`Missing required flag ${flag}.`);
2103
+ }
2104
+ return value;
2105
+ }
2106
+ function readCapabilities(args) {
2107
+ const index = args.indexOf("--capabilities");
2108
+ const value = index >= 0 ? args[index + 1] : void 0;
2109
+ if (!value) {
2110
+ return ["routing"];
2111
+ }
2112
+ const parsed = value.split(",").map((entry) => entry.trim()).filter(Boolean);
2113
+ return parsed.length > 0 ? parsed : ["routing"];
2114
+ }
2115
+ function summarizeRelay(relay) {
2116
+ return [
2117
+ relay.id,
2118
+ relay.region,
2119
+ relay.routingFeeBps.toString(),
2120
+ relay.stakeAmountMist !== void 0 ? formatMistToSui(relay.stakeAmountMist) : "-",
2121
+ relay.totalRouted.toString(),
2122
+ formatMistToSui(relay.totalFeesEarnedMist),
2123
+ relay.endpoint
2124
+ ];
2125
+ }
2126
+
2127
+ // src/commands/stake.ts
2128
+ import { loadOrCreateKeypair as loadOrCreateKeypair7, MeshSuiClient as MeshSuiClient8, StakingClient, STAKING_COOLDOWN_MS } from "@hivemind-os/collective-core";
2129
+ import { Ed25519Keypair as Ed25519Keypair7 } from "@mysten/sui/keypairs/ed25519";
2130
+ async function handleStake(subcommand, args = [], deps = {}) {
2131
+ switch (subcommand) {
2132
+ case "deposit":
2133
+ return await depositStake(args, deps);
2134
+ case "status":
2135
+ return await showStakeStatus(deps);
2136
+ case "withdraw":
2137
+ return await withdrawStake(args, deps);
2138
+ default:
2139
+ throw new Error("Usage: mesh stake <deposit|status|withdraw>");
2140
+ }
2141
+ }
2142
+ async function depositStake(args, deps) {
2143
+ const amount = args[0];
2144
+ if (!amount) {
2145
+ throw new Error("Usage: mesh stake deposit <amount-sui> [--type agent|relay]");
2146
+ }
2147
+ const stakeType = readStakeType(args.slice(1));
2148
+ const amountMist = parseSuiToMist(amount);
2149
+ const { client, keypair } = loadStakeContext(deps);
2150
+ const result = await client.depositStake({ amountMist, stakeType, signer: keypair });
2151
+ success(`Deposited ${amount} SUI as ${stakeType} stake.`);
2152
+ console.log(`Stake ID: ${result.stakeId}`);
2153
+ console.log(`Tx Digest: ${result.txDigest}`);
2154
+ return 0;
2155
+ }
2156
+ async function showStakeStatus(deps) {
2157
+ const { client, keypair } = loadStakeContext(deps);
2158
+ const owner = keypair.getPublicKey().toSuiAddress();
2159
+ const stake = await client.getStakeByOwner(owner);
2160
+ if (!stake) {
2161
+ info("No stake position found for this wallet.");
2162
+ return 0;
2163
+ }
2164
+ const cooldownEndsAt = stake.deactivatedAt > 0 ? stake.deactivatedAt + STAKING_COOLDOWN_MS : 0;
2165
+ success(`Stake position ${stake.id}`);
2166
+ table(
2167
+ ["Field", "Value"],
2168
+ [
2169
+ ["Owner", stake.owner],
2170
+ ["Type", stake.stakeType],
2171
+ ["Balance (SUI)", formatMistToSui(stake.balanceMist)],
2172
+ ["Balance (MIST)", stake.balanceMist.toString()],
2173
+ ["Active", String(stake.isActive ?? false)],
2174
+ ["Meets Minimum", String(stake.meetsMinium ?? false)],
2175
+ ["Slashed (SUI)", formatMistToSui(stake.slashedAmount)],
2176
+ ["Staked At", new Date(stake.stakedAt).toISOString()],
2177
+ ["Deactivated At", stake.deactivatedAt > 0 ? new Date(stake.deactivatedAt).toISOString() : "-"],
2178
+ ["Cooldown Ends", cooldownEndsAt > 0 ? new Date(cooldownEndsAt).toISOString() : "-"]
2179
+ ]
2180
+ );
2181
+ return 0;
2182
+ }
2183
+ async function withdrawStake(args, deps) {
2184
+ void args;
2185
+ const { client, keypair } = loadStakeContext(deps);
2186
+ const owner = keypair.getPublicKey().toSuiAddress();
2187
+ const stake = await client.getStakeByOwner(owner);
2188
+ if (!stake) {
2189
+ throw new Error("No stake position found for this wallet.");
2190
+ }
2191
+ if (stake.deactivatedAt === 0) {
2192
+ const result2 = await client.startDeactivation({ stakeId: stake.id, signer: keypair });
2193
+ info("Stake deactivation started.");
2194
+ console.log(`Cooldown ends: ${new Date(result2.cooldownEndsAt).toISOString()}`);
2195
+ console.log(`Tx Digest: ${result2.txDigest}`);
2196
+ return 0;
2197
+ }
2198
+ const cooldownEndsAt = stake.deactivatedAt + STAKING_COOLDOWN_MS;
2199
+ if (Date.now() < cooldownEndsAt) {
2200
+ warn(`Cooldown still active until ${new Date(cooldownEndsAt).toISOString()}.`);
2201
+ return 1;
2202
+ }
2203
+ const result = await client.withdrawStake({ stakeId: stake.id, signer: keypair });
2204
+ success("Stake withdrawn.");
2205
+ console.log(`Returned (SUI): ${formatMistToSui(result.amountReturned)}`);
2206
+ console.log(`Returned (MIST): ${result.amountReturned.toString()}`);
2207
+ console.log(`Tx Digest: ${result.txDigest}`);
2208
+ return 0;
2209
+ }
2210
+ function loadStakeContext(deps) {
2211
+ const config = (deps.loadConfig ?? loadMeshConfig)();
2212
+ if (!config.network.packageId) {
2213
+ throw new Error("network.packageId must be configured before staking.");
2214
+ }
2215
+ const identity = (deps.loadKeypair ?? loadOrCreateKeypair7)(config.identity.dataDir);
2216
+ const keypair = Ed25519Keypair7.fromSecretKey(identity.secretKey);
2217
+ const client = deps.createClient?.(config) ?? new StakingClient(new MeshSuiClient8(config.network), config.network);
2218
+ return { config, keypair, client };
2219
+ }
2220
+ function readStakeType(args) {
2221
+ const typeFlagIndex = args.indexOf("--type");
2222
+ if (typeFlagIndex >= 0) {
2223
+ const value = args[typeFlagIndex + 1]?.trim().toLowerCase();
2224
+ if (value === "agent" || value === "relay") {
2225
+ return value;
2226
+ }
2227
+ throw new Error("Usage: mesh stake deposit <amount-sui> [--type agent|relay]");
2228
+ }
2229
+ return "agent";
2230
+ }
2231
+
2232
+ // src/commands/task.ts
2233
+ import { MeshSuiClient as MeshSuiClient9, TaskClient as TaskClient2 } from "@hivemind-os/collective-core";
2234
+ import { TaskStatus as TaskStatus2 } from "@hivemind-os/collective-types";
2235
+ async function handleTask(subcommand, args = []) {
2236
+ if (subcommand !== "status") {
2237
+ throw new Error("Usage: mesh task status <id>");
2238
+ }
2239
+ const taskId = args[0];
2240
+ if (!taskId) {
2241
+ throw new Error("Usage: mesh task status <id>");
2242
+ }
2243
+ const config = loadMeshConfig();
2244
+ const taskClient = new TaskClient2(new MeshSuiClient9(config.network), config.network);
2245
+ const task = await taskClient.getTask(taskId);
2246
+ if (!task) {
2247
+ throw new Error(`Task ${taskId} was not found.`);
2248
+ }
2249
+ success(`Task ${task.id}`);
2250
+ table(
2251
+ ["Field", "Value"],
2252
+ [
2253
+ ["Status", TaskStatus2[task.status] ?? "UNKNOWN"],
2254
+ ["Capability", task.capability],
2255
+ ["Category", task.category],
2256
+ ["Price (SUI)", formatMistToSui(task.price)],
2257
+ ["Requester", task.requester],
2258
+ ["Provider", task.provider ?? "-"],
2259
+ ["Result Blob", task.resultBlobId ?? "-"],
2260
+ ["Created", new Date(task.createdAt).toISOString()],
2261
+ ["Expires", new Date(task.expiresAt).toISOString()]
2262
+ ]
2263
+ );
2264
+ return 0;
2265
+ }
2266
+
2267
+ // src/index.ts
2268
+ var VERSION = "0.1.0";
2269
+ async function runCli(args = process.argv.slice(2)) {
2270
+ const command = args[0];
2271
+ const subcommand = args[1];
2272
+ switch (command) {
2273
+ case "init":
2274
+ return await handleInit(args.slice(1));
2275
+ case "connect":
2276
+ return await handleConnect(args.slice(1));
2277
+ case "daemon":
2278
+ return await handleDaemon(subcommand, args.slice(2));
2279
+ case "auth":
2280
+ return await handleAuth(subcommand, args.slice(2));
2281
+ case "register":
2282
+ return await handleRegister(args.slice(1));
2283
+ case "config":
2284
+ return await handleConfig(args.slice(1));
2285
+ case "analytics":
2286
+ return await handleAnalytics(subcommand, args.slice(2));
2287
+ case "policy":
2288
+ return await handlePolicy(subcommand, args.slice(2));
2289
+ case "wallet":
2290
+ return await handleWallet(subcommand, args.slice(2));
2291
+ case "discover":
2292
+ return await handleDiscover(args.slice(1));
2293
+ case "dispute":
2294
+ return await handleDispute(subcommand, args.slice(2));
2295
+ case "stake":
2296
+ return await handleStake(subcommand, args.slice(2));
2297
+ case "relay":
2298
+ return await handleRelayRegistry(subcommand, args.slice(2));
2299
+ case "task":
2300
+ return await handleTask(subcommand, args.slice(2));
2301
+ case "logs":
2302
+ return await handleLogs(args.slice(1));
2303
+ case "marketplace":
2304
+ return await handleMarketplace(subcommand, args.slice(2));
2305
+ case "metering":
2306
+ return await handleMetering(subcommand, args.slice(2));
2307
+ case "multi-execute":
2308
+ return await handleMultiExecute(args.slice(1));
2309
+ case "--help":
2310
+ case "-h":
2311
+ case "help":
2312
+ printHelp();
2313
+ return 0;
2314
+ case "--version":
2315
+ case "-v":
2316
+ printVersion();
2317
+ return 0;
2318
+ default:
2319
+ printHelp();
2320
+ return command ? 1 : 0;
2321
+ }
2322
+ }
2323
+ function printHelp() {
2324
+ console.log(`Agentic Mesh CLI
2325
+
2326
+ Usage:
2327
+ mesh <command> [options]
2328
+
2329
+ Commands:
2330
+ init First-time setup for your local mesh identity
2331
+ connect Start the MCP shim bridge
2332
+ daemon <cmd> Manage the background daemon (start|stop|status)
2333
+ auth <cmd> Inspect or refresh daemon auth (status|reauth)
2334
+ register Register this node as a provider
2335
+ config [subcmd] Show or update config values
2336
+ analytics <cmd> Query indexer analytics (summary|top-providers|task-volume)
2337
+ policy set Update spending limits
2338
+ wallet <cmd> Wallet tools (balance|fund|address)
2339
+ discover <cap> Find providers for a capability
2340
+ dispute <cmd> Manage disputes (open|respond|accept|status)
2341
+ marketplace <cmd> Marketplace tools (post|browse|bid|accept-bid)
2342
+ metering <cmd> Metered task tools (execute|verify|status)
2343
+ multi-execute Execute across multiple providers
2344
+ stake <cmd> Manage staking (deposit|status|withdraw)
2345
+ relay <cmd> Manage community relays (register|list|heartbeat|deactivate)
2346
+ task status <id> Inspect a task on Sui
2347
+ logs [--follow] Show daemon logs
2348
+ help Show this help text
2349
+ --version Print the CLI version`);
2350
+ }
2351
+ function printVersion() {
2352
+ console.log(VERSION);
2353
+ }
2354
+ async function main() {
2355
+ const exitCode = await runCli();
2356
+ process.exit(exitCode);
2357
+ }
2358
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
2359
+ main().catch((caught) => {
2360
+ const message = caught instanceof Error ? caught.message : String(caught);
2361
+ error(message);
2362
+ if (isAuthError(caught)) {
2363
+ info('Run "mesh auth status" to inspect the session or "mesh auth reauth" to open the daemon portal.');
2364
+ }
2365
+ process.exit(1);
2366
+ });
2367
+ }
2368
+ function isAuthError(errorToCheck) {
2369
+ if (errorToCheck instanceof SessionExpiredError) {
2370
+ return true;
2371
+ }
2372
+ return errorToCheck instanceof Error && /authentication expired|re-authenticate via the daemon portal/i.test(errorToCheck.message);
2373
+ }
2374
+ export {
2375
+ printHelp,
2376
+ printVersion,
2377
+ runCli
2378
+ };
2379
+ //# sourceMappingURL=index.js.map