claudemesh-cli 0.6.6 → 0.6.7
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 +561 -152
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -47374,6 +47374,49 @@ var TOOLS = [
|
|
|
47374
47374
|
}
|
|
47375
47375
|
}
|
|
47376
47376
|
},
|
|
47377
|
+
{
|
|
47378
|
+
name: "schedule_reminder",
|
|
47379
|
+
description: "Schedule a reminder message delivered back to yourself at a future time. The broker fires it as a push when the time arrives. Use to prompt yourself to check on something later.",
|
|
47380
|
+
inputSchema: {
|
|
47381
|
+
type: "object",
|
|
47382
|
+
properties: {
|
|
47383
|
+
message: { type: "string", description: "Reminder text" },
|
|
47384
|
+
deliver_at: { type: "number", description: "Unix timestamp (ms) when to deliver" },
|
|
47385
|
+
in_seconds: { type: "number", description: "Alternative to deliver_at: fire after N seconds" }
|
|
47386
|
+
},
|
|
47387
|
+
required: ["message"]
|
|
47388
|
+
}
|
|
47389
|
+
},
|
|
47390
|
+
{
|
|
47391
|
+
name: "send_later",
|
|
47392
|
+
description: "Send a message to a peer, @group, or broadcast (*) at a future time. The broker holds it and delivers when the time arrives.",
|
|
47393
|
+
inputSchema: {
|
|
47394
|
+
type: "object",
|
|
47395
|
+
properties: {
|
|
47396
|
+
to: { type: "string", description: "Recipient: display name, pubkey hex, @group, or *" },
|
|
47397
|
+
message: { type: "string", description: "Message text" },
|
|
47398
|
+
deliver_at: { type: "number", description: "Unix timestamp (ms) when to deliver" },
|
|
47399
|
+
in_seconds: { type: "number", description: "Alternative to deliver_at: fire after N seconds" }
|
|
47400
|
+
},
|
|
47401
|
+
required: ["to", "message"]
|
|
47402
|
+
}
|
|
47403
|
+
},
|
|
47404
|
+
{
|
|
47405
|
+
name: "list_scheduled",
|
|
47406
|
+
description: "List all your pending scheduled messages: id, recipient, preview, and delivery time.",
|
|
47407
|
+
inputSchema: { type: "object", properties: {} }
|
|
47408
|
+
},
|
|
47409
|
+
{
|
|
47410
|
+
name: "cancel_scheduled",
|
|
47411
|
+
description: "Cancel a pending scheduled message before it fires.",
|
|
47412
|
+
inputSchema: {
|
|
47413
|
+
type: "object",
|
|
47414
|
+
properties: {
|
|
47415
|
+
id: { type: "string", description: "Scheduled message ID" }
|
|
47416
|
+
},
|
|
47417
|
+
required: ["id"]
|
|
47418
|
+
}
|
|
47419
|
+
},
|
|
47377
47420
|
{
|
|
47378
47421
|
name: "mesh_info",
|
|
47379
47422
|
description: "Get a complete overview of the mesh: peers, groups, state, memory, files, tasks, streams, tables. Call on session start for full situational awareness.",
|
|
@@ -47740,6 +47783,42 @@ class BrokerClient {
|
|
|
47740
47783
|
return;
|
|
47741
47784
|
this.ws.send(JSON.stringify({ type: "forget", memoryId }));
|
|
47742
47785
|
}
|
|
47786
|
+
async scheduleMessage(to, message, deliverAt) {
|
|
47787
|
+
if (!this.ws || this.ws.readyState !== this.ws.OPEN)
|
|
47788
|
+
return null;
|
|
47789
|
+
return new Promise((resolve) => {
|
|
47790
|
+
const reqId = this.makeReqId();
|
|
47791
|
+
this.scheduledAckResolvers.set(reqId, { resolve, timer: setTimeout(() => {
|
|
47792
|
+
if (this.scheduledAckResolvers.delete(reqId))
|
|
47793
|
+
resolve(null);
|
|
47794
|
+
}, 8000) });
|
|
47795
|
+
this.ws.send(JSON.stringify({ type: "schedule", to, message, deliverAt, _reqId: reqId }));
|
|
47796
|
+
});
|
|
47797
|
+
}
|
|
47798
|
+
async listScheduled() {
|
|
47799
|
+
if (!this.ws || this.ws.readyState !== this.ws.OPEN)
|
|
47800
|
+
return [];
|
|
47801
|
+
return new Promise((resolve) => {
|
|
47802
|
+
const reqId = this.makeReqId();
|
|
47803
|
+
this.scheduledListResolvers.set(reqId, { resolve, timer: setTimeout(() => {
|
|
47804
|
+
if (this.scheduledListResolvers.delete(reqId))
|
|
47805
|
+
resolve([]);
|
|
47806
|
+
}, 5000) });
|
|
47807
|
+
this.ws.send(JSON.stringify({ type: "list_scheduled", _reqId: reqId }));
|
|
47808
|
+
});
|
|
47809
|
+
}
|
|
47810
|
+
async cancelScheduled(scheduledId) {
|
|
47811
|
+
if (!this.ws || this.ws.readyState !== this.ws.OPEN)
|
|
47812
|
+
return false;
|
|
47813
|
+
return new Promise((resolve) => {
|
|
47814
|
+
const reqId = this.makeReqId();
|
|
47815
|
+
this.cancelScheduledResolvers.set(reqId, { resolve, timer: setTimeout(() => {
|
|
47816
|
+
if (this.cancelScheduledResolvers.delete(reqId))
|
|
47817
|
+
resolve(false);
|
|
47818
|
+
}, 5000) });
|
|
47819
|
+
this.ws.send(JSON.stringify({ type: "cancel_scheduled", scheduledId, _reqId: reqId }));
|
|
47820
|
+
});
|
|
47821
|
+
}
|
|
47743
47822
|
messageStatusResolvers = new Map;
|
|
47744
47823
|
fileUrlResolvers = new Map;
|
|
47745
47824
|
fileListResolvers = new Map;
|
|
@@ -47757,6 +47836,9 @@ class BrokerClient {
|
|
|
47757
47836
|
streamCreatedResolvers = new Map;
|
|
47758
47837
|
streamListResolvers = new Map;
|
|
47759
47838
|
streamDataHandlers = new Set;
|
|
47839
|
+
scheduledAckResolvers = new Map;
|
|
47840
|
+
scheduledListResolvers = new Map;
|
|
47841
|
+
cancelScheduledResolvers = new Map;
|
|
47760
47842
|
async messageStatus(messageId) {
|
|
47761
47843
|
if (!this.ws || this.ws.readyState !== this.ws.OPEN)
|
|
47762
47844
|
return null;
|
|
@@ -48319,6 +48401,22 @@ class BrokerClient {
|
|
|
48319
48401
|
this.resolveFromMap(this.meshInfoResolvers, msgReqId, msg);
|
|
48320
48402
|
return;
|
|
48321
48403
|
}
|
|
48404
|
+
if (msg.type === "scheduled_ack") {
|
|
48405
|
+
this.resolveFromMap(this.scheduledAckResolvers, msgReqId, {
|
|
48406
|
+
scheduledId: String(msg.scheduledId ?? ""),
|
|
48407
|
+
deliverAt: Number(msg.deliverAt ?? 0)
|
|
48408
|
+
});
|
|
48409
|
+
return;
|
|
48410
|
+
}
|
|
48411
|
+
if (msg.type === "scheduled_list") {
|
|
48412
|
+
const messages = msg.messages ?? [];
|
|
48413
|
+
this.resolveFromMap(this.scheduledListResolvers, msgReqId, messages);
|
|
48414
|
+
return;
|
|
48415
|
+
}
|
|
48416
|
+
if (msg.type === "cancel_scheduled_ack") {
|
|
48417
|
+
this.resolveFromMap(this.cancelScheduledResolvers, msgReqId, Boolean(msg.ok));
|
|
48418
|
+
return;
|
|
48419
|
+
}
|
|
48322
48420
|
if (msg.type === "error") {
|
|
48323
48421
|
this.debug(`broker error: ${msg.code} ${msg.message}`);
|
|
48324
48422
|
const id = msg.id ? String(msg.id) : null;
|
|
@@ -48351,6 +48449,9 @@ class BrokerClient {
|
|
|
48351
48449
|
[this.contextResultsResolvers, []],
|
|
48352
48450
|
[this.contextListResolvers, []],
|
|
48353
48451
|
[this.streamListResolvers, []],
|
|
48452
|
+
[this.scheduledAckResolvers, null],
|
|
48453
|
+
[this.scheduledListResolvers, []],
|
|
48454
|
+
[this.cancelScheduledResolvers, false],
|
|
48354
48455
|
[this.messageStatusResolvers, null],
|
|
48355
48456
|
[this.grantFileAccessResolvers, false],
|
|
48356
48457
|
[this.collectionListResolvers, []],
|
|
@@ -48418,17 +48519,17 @@ async function ensureClient(mesh) {
|
|
|
48418
48519
|
const existing = clients.get(mesh.meshId);
|
|
48419
48520
|
if (existing)
|
|
48420
48521
|
return existing;
|
|
48421
|
-
const
|
|
48422
|
-
clients.set(mesh.meshId,
|
|
48522
|
+
const client2 = new BrokerClient(mesh, { debug: env.CLAUDEMESH_DEBUG, displayName: configDisplayName });
|
|
48523
|
+
clients.set(mesh.meshId, client2);
|
|
48423
48524
|
try {
|
|
48424
|
-
await
|
|
48525
|
+
await client2.connect();
|
|
48425
48526
|
for (const g of configGroups ?? []) {
|
|
48426
48527
|
try {
|
|
48427
|
-
await
|
|
48528
|
+
await client2.joinGroup(g.name, g.role);
|
|
48428
48529
|
} catch {}
|
|
48429
48530
|
}
|
|
48430
48531
|
} catch {}
|
|
48431
|
-
return
|
|
48532
|
+
return client2;
|
|
48432
48533
|
}
|
|
48433
48534
|
async function startClients(config2) {
|
|
48434
48535
|
configDisplayName = config2.displayName;
|
|
@@ -48511,12 +48612,12 @@ async function resolveClient(to) {
|
|
|
48511
48612
|
var peerNameCache = new Map;
|
|
48512
48613
|
var peerNameCacheAge = 0;
|
|
48513
48614
|
var CACHE_TTL_MS = 30000;
|
|
48514
|
-
async function resolvePeerName(
|
|
48615
|
+
async function resolvePeerName(client2, pubkey) {
|
|
48515
48616
|
const now = Date.now();
|
|
48516
48617
|
if (now - peerNameCacheAge > CACHE_TTL_MS) {
|
|
48517
48618
|
peerNameCache.clear();
|
|
48518
48619
|
try {
|
|
48519
|
-
const peers = await
|
|
48620
|
+
const peers = await client2.listPeers();
|
|
48520
48621
|
for (const p of peers)
|
|
48521
48622
|
peerNameCache.set(p.pubkey, p.displayName);
|
|
48522
48623
|
} catch {}
|
|
@@ -48666,15 +48767,15 @@ Your message mode is "${messageMode}".
|
|
|
48666
48767
|
const results = [];
|
|
48667
48768
|
const seen = new Set;
|
|
48668
48769
|
for (const target of targets) {
|
|
48669
|
-
const { client, targetSpec, error: error2 } = await resolveClient(target);
|
|
48670
|
-
if (!
|
|
48770
|
+
const { client: client2, targetSpec, error: error2 } = await resolveClient(target);
|
|
48771
|
+
if (!client2) {
|
|
48671
48772
|
results.push(`✗ ${target}: ${error2 ?? "no client resolved"}`);
|
|
48672
48773
|
continue;
|
|
48673
48774
|
}
|
|
48674
48775
|
if (seen.has(targetSpec))
|
|
48675
48776
|
continue;
|
|
48676
48777
|
seen.add(targetSpec);
|
|
48677
|
-
const result = await
|
|
48778
|
+
const result = await client2.send(targetSpec, message, priority ?? "next");
|
|
48678
48779
|
if (!result.ok) {
|
|
48679
48780
|
results.push(`✗ ${target}: ${result.error}`);
|
|
48680
48781
|
} else {
|
|
@@ -48795,19 +48896,19 @@ ${drained.join(`
|
|
|
48795
48896
|
const { key } = args ?? {};
|
|
48796
48897
|
if (!key)
|
|
48797
48898
|
return text("get_state: `key` required", true);
|
|
48798
|
-
const
|
|
48799
|
-
if (!
|
|
48899
|
+
const client2 = allClients()[0];
|
|
48900
|
+
if (!client2)
|
|
48800
48901
|
return text("get_state: not connected", true);
|
|
48801
|
-
const result = await
|
|
48902
|
+
const result = await client2.getState(key);
|
|
48802
48903
|
if (!result)
|
|
48803
48904
|
return text(`State "${key}" not found.`);
|
|
48804
48905
|
return text(`${key} = ${JSON.stringify(result.value)} (set by ${result.updatedBy} at ${result.updatedAt})`);
|
|
48805
48906
|
}
|
|
48806
48907
|
case "list_state": {
|
|
48807
|
-
const
|
|
48808
|
-
if (!
|
|
48908
|
+
const client2 = allClients()[0];
|
|
48909
|
+
if (!client2)
|
|
48809
48910
|
return text("list_state: not connected", true);
|
|
48810
|
-
const entries = await
|
|
48911
|
+
const entries = await client2.listState();
|
|
48811
48912
|
if (entries.length === 0)
|
|
48812
48913
|
return text("No shared state set.");
|
|
48813
48914
|
const lines = entries.map((e) => `- **${e.key}** = ${JSON.stringify(e.value)} (by ${e.updatedBy})`);
|
|
@@ -48818,20 +48919,20 @@ ${drained.join(`
|
|
|
48818
48919
|
const { content, tags } = args ?? {};
|
|
48819
48920
|
if (!content)
|
|
48820
48921
|
return text("remember: `content` required", true);
|
|
48821
|
-
const
|
|
48822
|
-
if (!
|
|
48922
|
+
const client2 = allClients()[0];
|
|
48923
|
+
if (!client2)
|
|
48823
48924
|
return text("remember: not connected", true);
|
|
48824
|
-
const id = await
|
|
48925
|
+
const id = await client2.remember(content, tags);
|
|
48825
48926
|
return text(`Remembered${id ? ` (${id})` : ""}: "${content.slice(0, 80)}${content.length > 80 ? "..." : ""}"`);
|
|
48826
48927
|
}
|
|
48827
48928
|
case "recall": {
|
|
48828
48929
|
const { query } = args ?? {};
|
|
48829
48930
|
if (!query)
|
|
48830
48931
|
return text("recall: `query` required", true);
|
|
48831
|
-
const
|
|
48832
|
-
if (!
|
|
48932
|
+
const client2 = allClients()[0];
|
|
48933
|
+
if (!client2)
|
|
48833
48934
|
return text("recall: not connected", true);
|
|
48834
|
-
const memories = await
|
|
48935
|
+
const memories = await client2.recall(query);
|
|
48835
48936
|
if (memories.length === 0)
|
|
48836
48937
|
return text(`No memories found for "${query}".`);
|
|
48837
48938
|
const lines = memories.map((m) => `- [${m.id.slice(0, 8)}] ${m.content} (by ${m.rememberedBy}, ${m.rememberedAt})`);
|
|
@@ -48843,12 +48944,63 @@ ${lines.join(`
|
|
|
48843
48944
|
const { id } = args ?? {};
|
|
48844
48945
|
if (!id)
|
|
48845
48946
|
return text("forget: `id` required", true);
|
|
48846
|
-
const
|
|
48847
|
-
if (!
|
|
48947
|
+
const client2 = allClients()[0];
|
|
48948
|
+
if (!client2)
|
|
48848
48949
|
return text("forget: not connected", true);
|
|
48849
|
-
await
|
|
48950
|
+
await client2.forget(id);
|
|
48850
48951
|
return text(`Forgotten: ${id}`);
|
|
48851
48952
|
}
|
|
48953
|
+
case "schedule_reminder":
|
|
48954
|
+
case "send_later": {
|
|
48955
|
+
const sArgs = args ?? {};
|
|
48956
|
+
if (!sArgs.message)
|
|
48957
|
+
return text(`${name}: \`message\` required`, true);
|
|
48958
|
+
const to = name === "schedule_reminder" ? "self" : sArgs.to ?? "";
|
|
48959
|
+
if (name === "send_later" && !to)
|
|
48960
|
+
return text("send_later: `to` required", true);
|
|
48961
|
+
let deliverAt;
|
|
48962
|
+
if (sArgs.deliver_at) {
|
|
48963
|
+
deliverAt = Number(sArgs.deliver_at);
|
|
48964
|
+
} else if (sArgs.in_seconds) {
|
|
48965
|
+
deliverAt = Date.now() + Number(sArgs.in_seconds) * 1000;
|
|
48966
|
+
} else {
|
|
48967
|
+
return text(`${name}: provide \`deliver_at\` (ms timestamp) or \`in_seconds\``, true);
|
|
48968
|
+
}
|
|
48969
|
+
let targetSpec = to;
|
|
48970
|
+
if (name === "send_later" && !to.startsWith("@") && to !== "*" && !/^[0-9a-f]{64}$/i.test(to) && to !== "self") {
|
|
48971
|
+
const peers = await client.listPeers();
|
|
48972
|
+
const match = peers.find((p) => p.displayName.toLowerCase() === to.toLowerCase());
|
|
48973
|
+
if (!match) {
|
|
48974
|
+
const names = peers.map((p) => p.displayName).join(", ");
|
|
48975
|
+
return text(`send_later: peer "${to}" not found. Online: ${names || "(none)"}`, true);
|
|
48976
|
+
}
|
|
48977
|
+
targetSpec = match.pubkey;
|
|
48978
|
+
}
|
|
48979
|
+
if (name === "schedule_reminder") {
|
|
48980
|
+
targetSpec = client.getSessionPubkey() ?? "*";
|
|
48981
|
+
}
|
|
48982
|
+
const result = await client.scheduleMessage(targetSpec, sArgs.message, deliverAt);
|
|
48983
|
+
if (!result)
|
|
48984
|
+
return text(`${name}: broker did not acknowledge — check connection`, true);
|
|
48985
|
+
const when = new Date(result.deliverAt).toISOString();
|
|
48986
|
+
return text(name === "schedule_reminder" ? `Reminder scheduled (${result.scheduledId.slice(0, 8)}): "${sArgs.message.slice(0, 60)}" at ${when}` : `Message to "${to}" scheduled (${result.scheduledId.slice(0, 8)}) for ${when}`);
|
|
48987
|
+
}
|
|
48988
|
+
case "list_scheduled": {
|
|
48989
|
+
const scheduled = await client.listScheduled();
|
|
48990
|
+
if (scheduled.length === 0)
|
|
48991
|
+
return text("No pending scheduled messages.");
|
|
48992
|
+
const lines = scheduled.map((m) => `- [${m.id.slice(0, 8)}] → ${m.to === client.getSessionPubkey() ? "self (reminder)" : m.to} at ${new Date(m.deliverAt).toISOString()}: "${m.message.slice(0, 60)}${m.message.length > 60 ? "…" : ""}"`);
|
|
48993
|
+
return text(`${scheduled.length} scheduled:
|
|
48994
|
+
${lines.join(`
|
|
48995
|
+
`)}`);
|
|
48996
|
+
}
|
|
48997
|
+
case "cancel_scheduled": {
|
|
48998
|
+
const { id: schedId } = args ?? {};
|
|
48999
|
+
if (!schedId)
|
|
49000
|
+
return text("cancel_scheduled: `id` required", true);
|
|
49001
|
+
const ok = await client.cancelScheduled(schedId);
|
|
49002
|
+
return text(ok ? `Cancelled: ${schedId}` : `Not found or already fired: ${schedId}`, !ok);
|
|
49003
|
+
}
|
|
48852
49004
|
case "share_file": {
|
|
48853
49005
|
const { path: filePath, name: fileName, tags, to: fileTo } = args ?? {};
|
|
48854
49006
|
if (!filePath)
|
|
@@ -48856,15 +49008,15 @@ ${lines.join(`
|
|
|
48856
49008
|
const { existsSync: existsSync2 } = await import("node:fs");
|
|
48857
49009
|
if (!existsSync2(filePath))
|
|
48858
49010
|
return text(`share_file: file not found: ${filePath}`, true);
|
|
48859
|
-
const
|
|
48860
|
-
if (!
|
|
49011
|
+
const client2 = allClients()[0];
|
|
49012
|
+
if (!client2)
|
|
48861
49013
|
return text("share_file: not connected", true);
|
|
48862
49014
|
if (fileTo) {
|
|
48863
49015
|
const { encryptFile: encryptFile2, sealKeyForPeer: sealKeyForPeer2 } = await Promise.resolve().then(() => (init_file_crypto(), exports_file_crypto));
|
|
48864
49016
|
const { readFileSync: readFileSync2, writeFileSync: writeFileSync2, mkdtempSync, unlinkSync, rmdirSync } = await import("node:fs");
|
|
48865
49017
|
const { tmpdir } = await import("node:os");
|
|
48866
49018
|
const { join: join2, basename } = await import("node:path");
|
|
48867
|
-
const peers = await
|
|
49019
|
+
const peers = await client2.listPeers();
|
|
48868
49020
|
const targetPeer = peers.find((p) => p.pubkey === fileTo || p.displayName === fileTo);
|
|
48869
49021
|
if (!targetPeer) {
|
|
48870
49022
|
return text(`share_file: peer not found: ${fileTo}`, true);
|
|
@@ -48872,7 +49024,7 @@ ${lines.join(`
|
|
|
48872
49024
|
const plaintext = readFileSync2(filePath);
|
|
48873
49025
|
const { ciphertext, nonce, key } = await encryptFile2(new Uint8Array(plaintext));
|
|
48874
49026
|
const sealedForTarget = await sealKeyForPeer2(key, targetPeer.pubkey);
|
|
48875
|
-
const myPubkey =
|
|
49027
|
+
const myPubkey = client2.getSessionPubkey();
|
|
48876
49028
|
const sealedForSelf = myPubkey ? await sealKeyForPeer2(key, myPubkey) : null;
|
|
48877
49029
|
const fileKeys = [
|
|
48878
49030
|
{ peerPubkey: targetPeer.pubkey, sealedKey: sealedForTarget },
|
|
@@ -48889,7 +49041,7 @@ ${lines.join(`
|
|
|
48889
49041
|
const tmpPath = join2(tmpDir, baseName);
|
|
48890
49042
|
writeFileSync2(tmpPath, combined);
|
|
48891
49043
|
try {
|
|
48892
|
-
const fileId = await
|
|
49044
|
+
const fileId = await client2.uploadFile(tmpPath, client2.meshId, client2.meshSlug, {
|
|
48893
49045
|
name: baseName,
|
|
48894
49046
|
tags,
|
|
48895
49047
|
persistent: true,
|
|
@@ -48910,7 +49062,7 @@ ${lines.join(`
|
|
|
48910
49062
|
}
|
|
48911
49063
|
}
|
|
48912
49064
|
try {
|
|
48913
|
-
const fileId = await
|
|
49065
|
+
const fileId = await client2.uploadFile(filePath, client2.meshId, client2.meshSlug, {
|
|
48914
49066
|
name: fileName,
|
|
48915
49067
|
tags,
|
|
48916
49068
|
persistent: true
|
|
@@ -48924,10 +49076,10 @@ ${lines.join(`
|
|
|
48924
49076
|
const { id, save_to } = args ?? {};
|
|
48925
49077
|
if (!id || !save_to)
|
|
48926
49078
|
return text("get_file: `id` and `save_to` required", true);
|
|
48927
|
-
const
|
|
48928
|
-
if (!
|
|
49079
|
+
const client2 = allClients()[0];
|
|
49080
|
+
if (!client2)
|
|
48929
49081
|
return text("get_file: not connected", true);
|
|
48930
|
-
const result = await
|
|
49082
|
+
const result = await client2.getFile(id);
|
|
48931
49083
|
if (!result)
|
|
48932
49084
|
return text(`get_file: file ${id} not found`, true);
|
|
48933
49085
|
if (result.encrypted) {
|
|
@@ -48935,8 +49087,8 @@ ${lines.join(`
|
|
|
48935
49087
|
return text("get_file: encrypted file — no decryption key available for your session", true);
|
|
48936
49088
|
const { openSealedKey: openSealedKey2, decryptFile: decryptFile2 } = await Promise.resolve().then(() => (init_file_crypto(), exports_file_crypto));
|
|
48937
49089
|
const { ensureSodium: ensureSodium2 } = await Promise.resolve().then(() => (init_keypair(), exports_keypair));
|
|
48938
|
-
const myPubkey =
|
|
48939
|
-
const mySecret =
|
|
49090
|
+
const myPubkey = client2.getSessionPubkey();
|
|
49091
|
+
const mySecret = client2.getSessionSecretKey();
|
|
48940
49092
|
if (!myPubkey || !mySecret) {
|
|
48941
49093
|
return text("get_file: no session keypair — cannot decrypt", true);
|
|
48942
49094
|
}
|
|
@@ -48971,10 +49123,10 @@ ${lines.join(`
|
|
|
48971
49123
|
}
|
|
48972
49124
|
case "list_files": {
|
|
48973
49125
|
const { query, from } = args ?? {};
|
|
48974
|
-
const
|
|
48975
|
-
if (!
|
|
49126
|
+
const client2 = allClients()[0];
|
|
49127
|
+
if (!client2)
|
|
48976
49128
|
return text("list_files: not connected", true);
|
|
48977
|
-
const files = await
|
|
49129
|
+
const files = await client2.listFiles(query, from);
|
|
48978
49130
|
if (files.length === 0)
|
|
48979
49131
|
return text("No files found.");
|
|
48980
49132
|
const lines = files.map((f) => `- **${f.name}** (${f.id.slice(0, 8)}…, ${f.size} bytes) by ${f.uploadedBy}${f.tags.length ? ` [${f.tags.join(", ")}]` : ""}`);
|
|
@@ -48985,10 +49137,10 @@ ${lines.join(`
|
|
|
48985
49137
|
const { id } = args ?? {};
|
|
48986
49138
|
if (!id)
|
|
48987
49139
|
return text("file_status: `id` required", true);
|
|
48988
|
-
const
|
|
48989
|
-
if (!
|
|
49140
|
+
const client2 = allClients()[0];
|
|
49141
|
+
if (!client2)
|
|
48990
49142
|
return text("file_status: not connected", true);
|
|
48991
|
-
const accesses = await
|
|
49143
|
+
const accesses = await client2.fileStatus(id);
|
|
48992
49144
|
if (accesses.length === 0)
|
|
48993
49145
|
return text("No one has accessed this file yet.");
|
|
48994
49146
|
const lines = accesses.map((a) => `- ${a.peerName} at ${a.accessedAt}`);
|
|
@@ -49000,30 +49152,30 @@ ${lines.join(`
|
|
|
49000
49152
|
const { id } = args ?? {};
|
|
49001
49153
|
if (!id)
|
|
49002
49154
|
return text("delete_file: `id` required", true);
|
|
49003
|
-
const
|
|
49004
|
-
if (!
|
|
49155
|
+
const client2 = allClients()[0];
|
|
49156
|
+
if (!client2)
|
|
49005
49157
|
return text("delete_file: not connected", true);
|
|
49006
|
-
await
|
|
49158
|
+
await client2.deleteFile(id);
|
|
49007
49159
|
return text(`Deleted: ${id}`);
|
|
49008
49160
|
}
|
|
49009
49161
|
case "vector_store": {
|
|
49010
49162
|
const { collection, text: storeText, metadata } = args ?? {};
|
|
49011
49163
|
if (!collection || !storeText)
|
|
49012
49164
|
return text("vector_store: `collection` and `text` required", true);
|
|
49013
|
-
const
|
|
49014
|
-
if (!
|
|
49165
|
+
const client2 = allClients()[0];
|
|
49166
|
+
if (!client2)
|
|
49015
49167
|
return text("vector_store: not connected", true);
|
|
49016
|
-
const id = await
|
|
49168
|
+
const id = await client2.vectorStore(collection, storeText, metadata);
|
|
49017
49169
|
return text(`Stored in ${collection}${id ? ` (${id})` : ""}`);
|
|
49018
49170
|
}
|
|
49019
49171
|
case "vector_search": {
|
|
49020
49172
|
const { collection, query, limit } = args ?? {};
|
|
49021
49173
|
if (!collection || !query)
|
|
49022
49174
|
return text("vector_search: `collection` and `query` required", true);
|
|
49023
|
-
const
|
|
49024
|
-
if (!
|
|
49175
|
+
const client2 = allClients()[0];
|
|
49176
|
+
if (!client2)
|
|
49025
49177
|
return text("vector_search: not connected", true);
|
|
49026
|
-
const results = await
|
|
49178
|
+
const results = await client2.vectorSearch(collection, query, limit);
|
|
49027
49179
|
if (results.length === 0)
|
|
49028
49180
|
return text(`No results in ${collection} for "${query}".`);
|
|
49029
49181
|
const lines = results.map((r) => `- [${r.id.slice(0, 8)}…] (score: ${r.score.toFixed(3)}) ${r.text.slice(0, 120)}${r.text.length > 120 ? "…" : ""}`);
|
|
@@ -49035,17 +49187,17 @@ ${lines.join(`
|
|
|
49035
49187
|
const { collection, id } = args ?? {};
|
|
49036
49188
|
if (!collection || !id)
|
|
49037
49189
|
return text("vector_delete: `collection` and `id` required", true);
|
|
49038
|
-
const
|
|
49039
|
-
if (!
|
|
49190
|
+
const client2 = allClients()[0];
|
|
49191
|
+
if (!client2)
|
|
49040
49192
|
return text("vector_delete: not connected", true);
|
|
49041
|
-
await
|
|
49193
|
+
await client2.vectorDelete(collection, id);
|
|
49042
49194
|
return text(`Deleted ${id} from ${collection}`);
|
|
49043
49195
|
}
|
|
49044
49196
|
case "list_collections": {
|
|
49045
|
-
const
|
|
49046
|
-
if (!
|
|
49197
|
+
const client2 = allClients()[0];
|
|
49198
|
+
if (!client2)
|
|
49047
49199
|
return text("list_collections: not connected", true);
|
|
49048
|
-
const collections = await
|
|
49200
|
+
const collections = await client2.listCollections();
|
|
49049
49201
|
if (collections.length === 0)
|
|
49050
49202
|
return text("No vector collections.");
|
|
49051
49203
|
return text(`Collections:
|
|
@@ -49056,10 +49208,10 @@ ${collections.map((c) => `- ${c}`).join(`
|
|
|
49056
49208
|
const { cypher } = args ?? {};
|
|
49057
49209
|
if (!cypher)
|
|
49058
49210
|
return text("graph_query: `cypher` required", true);
|
|
49059
|
-
const
|
|
49060
|
-
if (!
|
|
49211
|
+
const client2 = allClients()[0];
|
|
49212
|
+
if (!client2)
|
|
49061
49213
|
return text("graph_query: not connected", true);
|
|
49062
|
-
const rows = await
|
|
49214
|
+
const rows = await client2.graphQuery(cypher);
|
|
49063
49215
|
if (rows.length === 0)
|
|
49064
49216
|
return text("No results.");
|
|
49065
49217
|
return text(JSON.stringify(rows, null, 2));
|
|
@@ -49068,30 +49220,30 @@ ${collections.map((c) => `- ${c}`).join(`
|
|
|
49068
49220
|
const { cypher } = args ?? {};
|
|
49069
49221
|
if (!cypher)
|
|
49070
49222
|
return text("graph_execute: `cypher` required", true);
|
|
49071
|
-
const
|
|
49072
|
-
if (!
|
|
49223
|
+
const client2 = allClients()[0];
|
|
49224
|
+
if (!client2)
|
|
49073
49225
|
return text("graph_execute: not connected", true);
|
|
49074
|
-
const rows = await
|
|
49226
|
+
const rows = await client2.graphExecute(cypher);
|
|
49075
49227
|
return text(rows.length > 0 ? JSON.stringify(rows, null, 2) : "Executed successfully.");
|
|
49076
49228
|
}
|
|
49077
49229
|
case "share_context": {
|
|
49078
49230
|
const { summary, files_read, key_findings, tags } = args ?? {};
|
|
49079
49231
|
if (!summary)
|
|
49080
49232
|
return text("share_context: `summary` required", true);
|
|
49081
|
-
const
|
|
49082
|
-
if (!
|
|
49233
|
+
const client2 = allClients()[0];
|
|
49234
|
+
if (!client2)
|
|
49083
49235
|
return text("share_context: not connected", true);
|
|
49084
|
-
await
|
|
49236
|
+
await client2.shareContext(summary, files_read, key_findings, tags);
|
|
49085
49237
|
return text(`Context shared: "${summary.slice(0, 80)}${summary.length > 80 ? "…" : ""}"`);
|
|
49086
49238
|
}
|
|
49087
49239
|
case "get_context": {
|
|
49088
49240
|
const { query } = args ?? {};
|
|
49089
49241
|
if (!query)
|
|
49090
49242
|
return text("get_context: `query` required", true);
|
|
49091
|
-
const
|
|
49092
|
-
if (!
|
|
49243
|
+
const client2 = allClients()[0];
|
|
49244
|
+
if (!client2)
|
|
49093
49245
|
return text("get_context: not connected", true);
|
|
49094
|
-
const contexts = await
|
|
49246
|
+
const contexts = await client2.getContext(query);
|
|
49095
49247
|
if (contexts.length === 0)
|
|
49096
49248
|
return text(`No context found for "${query}".`);
|
|
49097
49249
|
const lines = contexts.map((c) => {
|
|
@@ -49106,10 +49258,10 @@ ${lines.join(`
|
|
|
49106
49258
|
`)}`);
|
|
49107
49259
|
}
|
|
49108
49260
|
case "list_contexts": {
|
|
49109
|
-
const
|
|
49110
|
-
if (!
|
|
49261
|
+
const client2 = allClients()[0];
|
|
49262
|
+
if (!client2)
|
|
49111
49263
|
return text("list_contexts: not connected", true);
|
|
49112
|
-
const contexts = await
|
|
49264
|
+
const contexts = await client2.listContexts();
|
|
49113
49265
|
if (contexts.length === 0)
|
|
49114
49266
|
return text("No peer contexts shared yet.");
|
|
49115
49267
|
const lines = contexts.map((c) => `- **${c.peerName}**: ${c.summary}${c.tags.length ? ` [${c.tags.join(", ")}]` : ""}`);
|
|
@@ -49121,38 +49273,38 @@ ${lines.join(`
|
|
|
49121
49273
|
const { title, assignee, priority, tags } = args ?? {};
|
|
49122
49274
|
if (!title)
|
|
49123
49275
|
return text("create_task: `title` required", true);
|
|
49124
|
-
const
|
|
49125
|
-
if (!
|
|
49276
|
+
const client2 = allClients()[0];
|
|
49277
|
+
if (!client2)
|
|
49126
49278
|
return text("create_task: not connected", true);
|
|
49127
|
-
const id = await
|
|
49279
|
+
const id = await client2.createTask(title, assignee, priority, tags);
|
|
49128
49280
|
return text(`Task created${id ? ` (${id})` : ""}: "${title}"${assignee ? ` → ${assignee}` : ""}`);
|
|
49129
49281
|
}
|
|
49130
49282
|
case "claim_task": {
|
|
49131
49283
|
const { id } = args ?? {};
|
|
49132
49284
|
if (!id)
|
|
49133
49285
|
return text("claim_task: `id` required", true);
|
|
49134
|
-
const
|
|
49135
|
-
if (!
|
|
49286
|
+
const client2 = allClients()[0];
|
|
49287
|
+
if (!client2)
|
|
49136
49288
|
return text("claim_task: not connected", true);
|
|
49137
|
-
await
|
|
49289
|
+
await client2.claimTask(id);
|
|
49138
49290
|
return text(`Claimed task: ${id}`);
|
|
49139
49291
|
}
|
|
49140
49292
|
case "complete_task": {
|
|
49141
49293
|
const { id, result } = args ?? {};
|
|
49142
49294
|
if (!id)
|
|
49143
49295
|
return text("complete_task: `id` required", true);
|
|
49144
|
-
const
|
|
49145
|
-
if (!
|
|
49296
|
+
const client2 = allClients()[0];
|
|
49297
|
+
if (!client2)
|
|
49146
49298
|
return text("complete_task: not connected", true);
|
|
49147
|
-
await
|
|
49299
|
+
await client2.completeTask(id, result);
|
|
49148
49300
|
return text(`Completed task: ${id}${result ? ` — ${result}` : ""}`);
|
|
49149
49301
|
}
|
|
49150
49302
|
case "list_tasks": {
|
|
49151
49303
|
const { status, assignee } = args ?? {};
|
|
49152
|
-
const
|
|
49153
|
-
if (!
|
|
49304
|
+
const client2 = allClients()[0];
|
|
49305
|
+
if (!client2)
|
|
49154
49306
|
return text("list_tasks: not connected", true);
|
|
49155
|
-
const tasks = await
|
|
49307
|
+
const tasks = await client2.listTasks(status, assignee);
|
|
49156
49308
|
if (tasks.length === 0)
|
|
49157
49309
|
return text("No tasks found.");
|
|
49158
49310
|
const lines = tasks.map((t) => `- [${t.id.slice(0, 8)}…] **${t.title}** (${t.status}, ${t.priority}) ${t.assignee ? `→ ${t.assignee}` : "unassigned"} (by ${t.createdBy})`);
|
|
@@ -49164,10 +49316,10 @@ ${lines.join(`
|
|
|
49164
49316
|
const { sql: querySql } = args ?? {};
|
|
49165
49317
|
if (!querySql)
|
|
49166
49318
|
return text("mesh_query: `sql` required", true);
|
|
49167
|
-
const
|
|
49168
|
-
if (!
|
|
49319
|
+
const client2 = allClients()[0];
|
|
49320
|
+
if (!client2)
|
|
49169
49321
|
return text("mesh_query: not connected", true);
|
|
49170
|
-
const result = await
|
|
49322
|
+
const result = await client2.meshQuery(querySql);
|
|
49171
49323
|
if (!result)
|
|
49172
49324
|
return text("mesh_query: query failed or timed out", true);
|
|
49173
49325
|
if (result.rows.length === 0)
|
|
@@ -49185,17 +49337,17 @@ ${rows.join(`
|
|
|
49185
49337
|
const { sql: execSql } = args ?? {};
|
|
49186
49338
|
if (!execSql)
|
|
49187
49339
|
return text("mesh_execute: `sql` required", true);
|
|
49188
|
-
const
|
|
49189
|
-
if (!
|
|
49340
|
+
const client2 = allClients()[0];
|
|
49341
|
+
if (!client2)
|
|
49190
49342
|
return text("mesh_execute: not connected", true);
|
|
49191
|
-
await
|
|
49343
|
+
await client2.meshExecute(execSql);
|
|
49192
49344
|
return text(`Executed.`);
|
|
49193
49345
|
}
|
|
49194
49346
|
case "mesh_schema": {
|
|
49195
|
-
const
|
|
49196
|
-
if (!
|
|
49347
|
+
const client2 = allClients()[0];
|
|
49348
|
+
if (!client2)
|
|
49197
49349
|
return text("mesh_schema: not connected", true);
|
|
49198
|
-
const tables = await
|
|
49350
|
+
const tables = await client2.meshSchema();
|
|
49199
49351
|
if (!tables || tables.length === 0)
|
|
49200
49352
|
return text("No tables in mesh database.");
|
|
49201
49353
|
const lines = tables.map((t) => `**${t.name}**: ${t.columns.map((c) => `${c.name} (${c.type}${c.nullable ? ", nullable" : ""})`).join(", ")}`);
|
|
@@ -49206,37 +49358,37 @@ ${rows.join(`
|
|
|
49206
49358
|
const { name: streamName } = args ?? {};
|
|
49207
49359
|
if (!streamName)
|
|
49208
49360
|
return text("create_stream: `name` required", true);
|
|
49209
|
-
const
|
|
49210
|
-
if (!
|
|
49361
|
+
const client2 = allClients()[0];
|
|
49362
|
+
if (!client2)
|
|
49211
49363
|
return text("create_stream: not connected", true);
|
|
49212
|
-
const streamId = await
|
|
49364
|
+
const streamId = await client2.createStream(streamName);
|
|
49213
49365
|
return text(`Stream created: ${streamName}${streamId ? ` (${streamId})` : ""}`);
|
|
49214
49366
|
}
|
|
49215
49367
|
case "publish": {
|
|
49216
49368
|
const { stream: pubStream, data: pubData } = args ?? {};
|
|
49217
49369
|
if (!pubStream)
|
|
49218
49370
|
return text("publish: `stream` required", true);
|
|
49219
|
-
const
|
|
49220
|
-
if (!
|
|
49371
|
+
const client2 = allClients()[0];
|
|
49372
|
+
if (!client2)
|
|
49221
49373
|
return text("publish: not connected", true);
|
|
49222
|
-
await
|
|
49374
|
+
await client2.publish(pubStream, pubData);
|
|
49223
49375
|
return text(`Published to ${pubStream}.`);
|
|
49224
49376
|
}
|
|
49225
49377
|
case "subscribe": {
|
|
49226
49378
|
const { stream: subStream } = args ?? {};
|
|
49227
49379
|
if (!subStream)
|
|
49228
49380
|
return text("subscribe: `stream` required", true);
|
|
49229
|
-
const
|
|
49230
|
-
if (!
|
|
49381
|
+
const client2 = allClients()[0];
|
|
49382
|
+
if (!client2)
|
|
49231
49383
|
return text("subscribe: not connected", true);
|
|
49232
|
-
await
|
|
49384
|
+
await client2.subscribe(subStream);
|
|
49233
49385
|
return text(`Subscribed to ${subStream}. Data pushes will arrive as channel notifications.`);
|
|
49234
49386
|
}
|
|
49235
49387
|
case "list_streams": {
|
|
49236
|
-
const
|
|
49237
|
-
if (!
|
|
49388
|
+
const client2 = allClients()[0];
|
|
49389
|
+
if (!client2)
|
|
49238
49390
|
return text("list_streams: not connected", true);
|
|
49239
|
-
const streams = await
|
|
49391
|
+
const streams = await client2.listStreams();
|
|
49240
49392
|
if (streams.length === 0)
|
|
49241
49393
|
return text("No active streams.");
|
|
49242
49394
|
const lines = streams.map((s) => `- **${s.name}** (${s.id.slice(0, 8)}…) by ${s.createdBy}, ${s.subscriberCount} subscriber(s)`);
|
|
@@ -49244,10 +49396,10 @@ ${rows.join(`
|
|
|
49244
49396
|
`));
|
|
49245
49397
|
}
|
|
49246
49398
|
case "mesh_info": {
|
|
49247
|
-
const
|
|
49248
|
-
if (!
|
|
49399
|
+
const client2 = allClients()[0];
|
|
49400
|
+
if (!client2)
|
|
49249
49401
|
return text("mesh_info: not connected", true);
|
|
49250
|
-
const info = await
|
|
49402
|
+
const info = await client2.meshInfo();
|
|
49251
49403
|
if (!info)
|
|
49252
49404
|
return text("mesh_info: timed out", true);
|
|
49253
49405
|
const lines = [
|
|
@@ -49269,21 +49421,21 @@ ${rows.join(`
|
|
|
49269
49421
|
case "ping_mesh": {
|
|
49270
49422
|
const { priorities: pingPriorities } = args ?? {};
|
|
49271
49423
|
const toTest = pingPriorities ?? ["now", "next"];
|
|
49272
|
-
const
|
|
49273
|
-
if (!
|
|
49424
|
+
const client2 = allClients()[0];
|
|
49425
|
+
if (!client2)
|
|
49274
49426
|
return text("ping_mesh: not connected", true);
|
|
49275
49427
|
const results = [];
|
|
49276
|
-
results.push(`WS status: ${
|
|
49277
|
-
results.push(`Mesh: ${
|
|
49278
|
-
const peers = await
|
|
49428
|
+
results.push(`WS status: ${client2.status}`);
|
|
49429
|
+
results.push(`Mesh: ${client2.meshSlug}`);
|
|
49430
|
+
const peers = await client2.listPeers();
|
|
49279
49431
|
const selfPeer = peers.find((p) => p.displayName === myName);
|
|
49280
49432
|
results.push(`Your status: ${selfPeer?.status ?? "not found in peer list"}`);
|
|
49281
49433
|
results.push(`Peers online: ${peers.length}`);
|
|
49282
|
-
results.push(`Push buffer: ${
|
|
49434
|
+
results.push(`Push buffer: ${client2.pushHistory.length} buffered`);
|
|
49283
49435
|
for (const prio of toTest) {
|
|
49284
49436
|
const sendTime = Date.now();
|
|
49285
49437
|
const target = peers.find((p) => p.displayName !== myName);
|
|
49286
|
-
const sendResult = await
|
|
49438
|
+
const sendResult = await client2.send(target?.pubkey ?? "*", `__ping__ ${prio} from ${myName} at ${new Date().toISOString()}`, prio);
|
|
49287
49439
|
const ackTime = Date.now();
|
|
49288
49440
|
if (!sendResult.ok) {
|
|
49289
49441
|
results.push(`[${prio}] SEND FAILED: ${sendResult.error}`);
|
|
@@ -49306,14 +49458,14 @@ ${rows.join(`
|
|
|
49306
49458
|
const { fileId, to: grantTo } = args ?? {};
|
|
49307
49459
|
if (!fileId || !grantTo)
|
|
49308
49460
|
return text("grant_file_access: `fileId` and `to` required", true);
|
|
49309
|
-
const
|
|
49310
|
-
if (!
|
|
49461
|
+
const client2 = allClients()[0];
|
|
49462
|
+
if (!client2)
|
|
49311
49463
|
return text("grant_file_access: not connected", true);
|
|
49312
|
-
const peers = await
|
|
49464
|
+
const peers = await client2.listPeers();
|
|
49313
49465
|
const targetPeer = peers.find((p) => p.pubkey === grantTo || p.displayName === grantTo);
|
|
49314
49466
|
if (!targetPeer)
|
|
49315
49467
|
return text(`grant_file_access: peer not found: ${grantTo}`, true);
|
|
49316
|
-
const result = await
|
|
49468
|
+
const result = await client2.getFile(fileId);
|
|
49317
49469
|
if (!result)
|
|
49318
49470
|
return text("grant_file_access: file not found", true);
|
|
49319
49471
|
if (!result.encrypted)
|
|
@@ -49321,15 +49473,15 @@ ${rows.join(`
|
|
|
49321
49473
|
if (!result.sealedKey)
|
|
49322
49474
|
return text("grant_file_access: no key available (are you the owner?)", true);
|
|
49323
49475
|
const { openSealedKey: openSealedKey2, sealKeyForPeer: sealKeyForPeer2 } = await Promise.resolve().then(() => (init_file_crypto(), exports_file_crypto));
|
|
49324
|
-
const myPubkey =
|
|
49325
|
-
const mySecret =
|
|
49476
|
+
const myPubkey = client2.getSessionPubkey();
|
|
49477
|
+
const mySecret = client2.getSessionSecretKey();
|
|
49326
49478
|
if (!myPubkey || !mySecret)
|
|
49327
49479
|
return text("grant_file_access: no session keypair", true);
|
|
49328
49480
|
const kf = await openSealedKey2(result.sealedKey, myPubkey, mySecret);
|
|
49329
49481
|
if (!kf)
|
|
49330
49482
|
return text("grant_file_access: cannot decrypt your own key", true);
|
|
49331
49483
|
const sealedForPeer = await sealKeyForPeer2(kf, targetPeer.pubkey);
|
|
49332
|
-
const ok = await
|
|
49484
|
+
const ok = await client2.grantFileAccess(fileId, targetPeer.pubkey, sealedForPeer);
|
|
49333
49485
|
if (!ok)
|
|
49334
49486
|
return text("grant_file_access: broker did not confirm", true);
|
|
49335
49487
|
return text(`Access granted: ${targetPeer.displayName} can now download file ${fileId}`);
|
|
@@ -49341,12 +49493,12 @@ ${rows.join(`
|
|
|
49341
49493
|
await startClients(config2);
|
|
49342
49494
|
const transport = new StdioServerTransport;
|
|
49343
49495
|
await server.connect(transport);
|
|
49344
|
-
for (const
|
|
49345
|
-
|
|
49496
|
+
for (const client2 of allClients()) {
|
|
49497
|
+
client2.onPush(async (msg) => {
|
|
49346
49498
|
if (messageMode === "off")
|
|
49347
49499
|
return;
|
|
49348
49500
|
const fromPubkey = msg.senderPubkey || "";
|
|
49349
|
-
const fromName = fromPubkey ? await resolvePeerName(
|
|
49501
|
+
const fromName = fromPubkey ? await resolvePeerName(client2, fromPubkey) : "unknown";
|
|
49350
49502
|
if (messageMode === "inbox") {
|
|
49351
49503
|
try {
|
|
49352
49504
|
await server.notification({
|
|
@@ -49368,8 +49520,8 @@ ${rows.join(`
|
|
|
49368
49520
|
meta: {
|
|
49369
49521
|
from_id: fromPubkey,
|
|
49370
49522
|
from_name: fromName,
|
|
49371
|
-
mesh_slug:
|
|
49372
|
-
mesh_id:
|
|
49523
|
+
mesh_slug: client2.meshSlug,
|
|
49524
|
+
mesh_id: client2.meshId,
|
|
49373
49525
|
priority: msg.priority,
|
|
49374
49526
|
sent_at: msg.createdAt,
|
|
49375
49527
|
delivered_at: msg.receivedAt,
|
|
@@ -49384,7 +49536,7 @@ ${rows.join(`
|
|
|
49384
49536
|
`);
|
|
49385
49537
|
}
|
|
49386
49538
|
});
|
|
49387
|
-
|
|
49539
|
+
client2.onStreamData(async (evt) => {
|
|
49388
49540
|
try {
|
|
49389
49541
|
await server.notification({
|
|
49390
49542
|
method: "notifications/claude/channel",
|
|
@@ -49399,7 +49551,7 @@ ${rows.join(`
|
|
|
49399
49551
|
});
|
|
49400
49552
|
} catch {}
|
|
49401
49553
|
});
|
|
49402
|
-
|
|
49554
|
+
client2.onStateChange(async (change) => {
|
|
49403
49555
|
try {
|
|
49404
49556
|
await server.notification({
|
|
49405
49557
|
method: "notifications/claude/channel",
|
|
@@ -49416,17 +49568,17 @@ ${rows.join(`
|
|
|
49416
49568
|
});
|
|
49417
49569
|
}
|
|
49418
49570
|
setTimeout(async () => {
|
|
49419
|
-
const
|
|
49420
|
-
if (!
|
|
49571
|
+
const client2 = allClients()[0];
|
|
49572
|
+
if (!client2 || client2.status !== "open")
|
|
49421
49573
|
return;
|
|
49422
49574
|
try {
|
|
49423
|
-
const peers = await
|
|
49575
|
+
const peers = await client2.listPeers();
|
|
49424
49576
|
const peerNames = peers.filter((p) => p.displayName !== myName).map((p) => p.displayName).join(", ") || "none";
|
|
49425
49577
|
await server.notification({
|
|
49426
49578
|
method: "notifications/claude/channel",
|
|
49427
49579
|
params: {
|
|
49428
|
-
content: `[system] Connected as ${myName} to mesh ${
|
|
49429
|
-
meta: { kind: "welcome", mesh_slug:
|
|
49580
|
+
content: `[system] Connected as ${myName} to mesh ${client2.meshSlug}. ${peers.length} peer(s) online: ${peerNames}. Call mesh_info for full details or set_summary to announce yourself.`,
|
|
49581
|
+
meta: { kind: "welcome", mesh_slug: client2.meshSlug }
|
|
49430
49582
|
}
|
|
49431
49583
|
});
|
|
49432
49584
|
} catch {}
|
|
@@ -50401,7 +50553,7 @@ init_config();
|
|
|
50401
50553
|
// package.json
|
|
50402
50554
|
var package_default = {
|
|
50403
50555
|
name: "claudemesh-cli",
|
|
50404
|
-
version: "0.6.
|
|
50556
|
+
version: "0.6.7",
|
|
50405
50557
|
description: "Claude Code MCP client for claudemesh — peer mesh messaging between Claude sessions.",
|
|
50406
50558
|
keywords: [
|
|
50407
50559
|
"claude-code",
|
|
@@ -50834,13 +50986,13 @@ Joined: ${config2.meshes.map((m) => m.slug).join(", ")}`);
|
|
|
50834
50986
|
process.exit(1);
|
|
50835
50987
|
}
|
|
50836
50988
|
const displayName = opts.displayName ?? config2.displayName ?? `${hostname3()}-${process.pid}`;
|
|
50837
|
-
const
|
|
50989
|
+
const client2 = new BrokerClient(mesh, { displayName });
|
|
50838
50990
|
try {
|
|
50839
|
-
await
|
|
50840
|
-
const result = await fn(
|
|
50991
|
+
await client2.connect();
|
|
50992
|
+
const result = await fn(client2, mesh);
|
|
50841
50993
|
return result;
|
|
50842
50994
|
} finally {
|
|
50843
|
-
|
|
50995
|
+
client2.close();
|
|
50844
50996
|
}
|
|
50845
50997
|
}
|
|
50846
50998
|
|
|
@@ -50851,8 +51003,8 @@ async function runPeers(flags) {
|
|
|
50851
51003
|
const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
|
|
50852
51004
|
const green = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
|
|
50853
51005
|
const yellow = (s) => useColor ? `\x1B[33m${s}\x1B[39m` : s;
|
|
50854
|
-
await withMesh({ meshSlug: flags.mesh ?? null }, async (
|
|
50855
|
-
const peers = await
|
|
51006
|
+
await withMesh({ meshSlug: flags.mesh ?? null }, async (client2, mesh) => {
|
|
51007
|
+
const peers = await client2.listPeers();
|
|
50856
51008
|
if (flags.json) {
|
|
50857
51009
|
console.log(JSON.stringify(peers, null, 2));
|
|
50858
51010
|
return;
|
|
@@ -50877,10 +51029,10 @@ async function runPeers(flags) {
|
|
|
50877
51029
|
// src/commands/send.ts
|
|
50878
51030
|
async function runSend(flags, to, message) {
|
|
50879
51031
|
const priority = flags.priority === "now" ? "now" : flags.priority === "low" ? "low" : "next";
|
|
50880
|
-
await withMesh({ meshSlug: flags.mesh ?? null }, async (
|
|
51032
|
+
await withMesh({ meshSlug: flags.mesh ?? null }, async (client2) => {
|
|
50881
51033
|
let targetSpec = to;
|
|
50882
51034
|
if (!to.startsWith("@") && to !== "*" && !/^[0-9a-f]{64}$/i.test(to)) {
|
|
50883
|
-
const peers = await
|
|
51035
|
+
const peers = await client2.listPeers();
|
|
50884
51036
|
const match = peers.find((p) => p.displayName.toLowerCase() === to.toLowerCase());
|
|
50885
51037
|
if (!match) {
|
|
50886
51038
|
const names = peers.map((p) => p.displayName).join(", ");
|
|
@@ -50889,7 +51041,7 @@ async function runSend(flags, to, message) {
|
|
|
50889
51041
|
}
|
|
50890
51042
|
targetSpec = match.pubkey;
|
|
50891
51043
|
}
|
|
50892
|
-
const result = await
|
|
51044
|
+
const result = await client2.send(targetSpec, message, priority);
|
|
50893
51045
|
if (result.ok) {
|
|
50894
51046
|
console.log(`✓ Sent to ${to}${result.messageId ? ` (${result.messageId.slice(0, 8)})` : ""}`);
|
|
50895
51047
|
} else {
|
|
@@ -50915,9 +51067,9 @@ async function runInbox(flags) {
|
|
|
50915
51067
|
const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
|
|
50916
51068
|
const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
|
|
50917
51069
|
const waitMs = (flags.wait ?? 1) * 1000;
|
|
50918
|
-
await withMesh({ meshSlug: flags.mesh ?? null }, async (
|
|
51070
|
+
await withMesh({ meshSlug: flags.mesh ?? null }, async (client2, mesh) => {
|
|
50919
51071
|
await new Promise((resolve2) => setTimeout(resolve2, waitMs));
|
|
50920
|
-
const messages =
|
|
51072
|
+
const messages = client2.drainPushBuffer();
|
|
50921
51073
|
if (flags.json) {
|
|
50922
51074
|
console.log(JSON.stringify(messages, null, 2));
|
|
50923
51075
|
return;
|
|
@@ -50939,8 +51091,8 @@ async function runInbox(flags) {
|
|
|
50939
51091
|
async function runStateGet(flags, key) {
|
|
50940
51092
|
const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
|
|
50941
51093
|
const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
|
|
50942
|
-
await withMesh({ meshSlug: flags.mesh ?? null }, async (
|
|
50943
|
-
const entry = await
|
|
51094
|
+
await withMesh({ meshSlug: flags.mesh ?? null }, async (client2) => {
|
|
51095
|
+
const entry = await client2.getState(key);
|
|
50944
51096
|
if (!entry) {
|
|
50945
51097
|
console.log(dim(`(not set)`));
|
|
50946
51098
|
return;
|
|
@@ -50961,8 +51113,8 @@ async function runStateSet(flags, key, value) {
|
|
|
50961
51113
|
} catch {
|
|
50962
51114
|
parsed = value;
|
|
50963
51115
|
}
|
|
50964
|
-
await withMesh({ meshSlug: flags.mesh ?? null }, async (
|
|
50965
|
-
await
|
|
51116
|
+
await withMesh({ meshSlug: flags.mesh ?? null }, async (client2) => {
|
|
51117
|
+
await client2.setState(key, parsed);
|
|
50966
51118
|
console.log(`✓ ${key} = ${JSON.stringify(parsed)}`);
|
|
50967
51119
|
});
|
|
50968
51120
|
}
|
|
@@ -50970,8 +51122,8 @@ async function runStateList(flags) {
|
|
|
50970
51122
|
const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
|
|
50971
51123
|
const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
|
|
50972
51124
|
const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
|
|
50973
|
-
await withMesh({ meshSlug: flags.mesh ?? null }, async (
|
|
50974
|
-
const entries = await
|
|
51125
|
+
await withMesh({ meshSlug: flags.mesh ?? null }, async (client2, mesh) => {
|
|
51126
|
+
const entries = await client2.listState();
|
|
50975
51127
|
if (flags.json) {
|
|
50976
51128
|
console.log(JSON.stringify(entries, null, 2));
|
|
50977
51129
|
return;
|
|
@@ -50988,6 +51140,214 @@ async function runStateList(flags) {
|
|
|
50988
51140
|
});
|
|
50989
51141
|
}
|
|
50990
51142
|
|
|
51143
|
+
// src/commands/memory.ts
|
|
51144
|
+
async function runRemember(flags, content) {
|
|
51145
|
+
const tags = flags.tags ? flags.tags.split(",").map((t) => t.trim()).filter(Boolean) : undefined;
|
|
51146
|
+
await withMesh({ meshSlug: flags.mesh ?? null }, async (client2) => {
|
|
51147
|
+
const id = await client2.remember(content, tags);
|
|
51148
|
+
if (flags.json) {
|
|
51149
|
+
console.log(JSON.stringify({ id, content, tags }));
|
|
51150
|
+
return;
|
|
51151
|
+
}
|
|
51152
|
+
if (id) {
|
|
51153
|
+
console.log(`✓ Remembered (${id.slice(0, 8)})`);
|
|
51154
|
+
} else {
|
|
51155
|
+
console.error("✗ Failed to store memory");
|
|
51156
|
+
process.exit(1);
|
|
51157
|
+
}
|
|
51158
|
+
});
|
|
51159
|
+
}
|
|
51160
|
+
async function runRecall(flags, query) {
|
|
51161
|
+
const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
|
|
51162
|
+
const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
|
|
51163
|
+
const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
|
|
51164
|
+
await withMesh({ meshSlug: flags.mesh ?? null }, async (client2) => {
|
|
51165
|
+
const memories = await client2.recall(query);
|
|
51166
|
+
if (flags.json) {
|
|
51167
|
+
console.log(JSON.stringify(memories, null, 2));
|
|
51168
|
+
return;
|
|
51169
|
+
}
|
|
51170
|
+
if (memories.length === 0) {
|
|
51171
|
+
console.log(dim("No memories found."));
|
|
51172
|
+
return;
|
|
51173
|
+
}
|
|
51174
|
+
for (const m of memories) {
|
|
51175
|
+
const tags = m.tags.length ? dim(` [${m.tags.join(", ")}]`) : "";
|
|
51176
|
+
console.log(`${bold2(m.id.slice(0, 8))}${tags}`);
|
|
51177
|
+
console.log(` ${m.content}`);
|
|
51178
|
+
console.log(dim(` ${m.rememberedBy} · ${new Date(m.rememberedAt).toLocaleString()}`));
|
|
51179
|
+
console.log("");
|
|
51180
|
+
}
|
|
51181
|
+
});
|
|
51182
|
+
}
|
|
51183
|
+
|
|
51184
|
+
// src/commands/info.ts
|
|
51185
|
+
init_config();
|
|
51186
|
+
async function runInfo(flags) {
|
|
51187
|
+
const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
|
|
51188
|
+
const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
|
|
51189
|
+
const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
|
|
51190
|
+
const config2 = loadConfig();
|
|
51191
|
+
await withMesh({ meshSlug: flags.mesh ?? null }, async (client2, mesh) => {
|
|
51192
|
+
const [brokerInfo, peers, state] = await Promise.all([
|
|
51193
|
+
client2.meshInfo(),
|
|
51194
|
+
client2.listPeers(),
|
|
51195
|
+
client2.listState()
|
|
51196
|
+
]);
|
|
51197
|
+
const output = {
|
|
51198
|
+
slug: mesh.slug,
|
|
51199
|
+
meshId: mesh.meshId,
|
|
51200
|
+
memberId: mesh.memberId,
|
|
51201
|
+
brokerUrl: mesh.brokerUrl,
|
|
51202
|
+
displayName: config2.displayName ?? null,
|
|
51203
|
+
peerCount: peers.length,
|
|
51204
|
+
stateCount: state.length,
|
|
51205
|
+
...brokerInfo ?? {}
|
|
51206
|
+
};
|
|
51207
|
+
if (flags.json) {
|
|
51208
|
+
console.log(JSON.stringify(output, null, 2));
|
|
51209
|
+
return;
|
|
51210
|
+
}
|
|
51211
|
+
console.log(bold2(mesh.slug) + dim(` · ${mesh.brokerUrl}`));
|
|
51212
|
+
console.log(dim(` mesh: ${mesh.meshId}`));
|
|
51213
|
+
console.log(dim(` member: ${mesh.memberId}`));
|
|
51214
|
+
console.log(` peers: ${peers.length} connected`);
|
|
51215
|
+
console.log(` state: ${state.length} keys`);
|
|
51216
|
+
if (brokerInfo && typeof brokerInfo === "object") {
|
|
51217
|
+
for (const [k, v] of Object.entries(brokerInfo)) {
|
|
51218
|
+
if (["slug", "meshId", "brokerUrl"].includes(k))
|
|
51219
|
+
continue;
|
|
51220
|
+
console.log(dim(` ${k}: ${JSON.stringify(v)}`));
|
|
51221
|
+
}
|
|
51222
|
+
}
|
|
51223
|
+
});
|
|
51224
|
+
}
|
|
51225
|
+
|
|
51226
|
+
// src/commands/remind.ts
|
|
51227
|
+
function parseDuration(raw) {
|
|
51228
|
+
const m = raw.trim().match(/^(\d+(?:\.\d+)?)\s*(s|sec|m|min|h|hr|d|day)?$/i);
|
|
51229
|
+
if (!m)
|
|
51230
|
+
return null;
|
|
51231
|
+
const n = parseFloat(m[1]);
|
|
51232
|
+
const unit = (m[2] ?? "s").toLowerCase();
|
|
51233
|
+
if (unit.startsWith("d"))
|
|
51234
|
+
return n * 86400000;
|
|
51235
|
+
if (unit.startsWith("h"))
|
|
51236
|
+
return n * 3600000;
|
|
51237
|
+
if (unit.startsWith("m"))
|
|
51238
|
+
return n * 60000;
|
|
51239
|
+
return n * 1000;
|
|
51240
|
+
}
|
|
51241
|
+
function parseDeliverAt(flags) {
|
|
51242
|
+
if (flags.in) {
|
|
51243
|
+
const ms = parseDuration(flags.in);
|
|
51244
|
+
if (ms === null)
|
|
51245
|
+
return null;
|
|
51246
|
+
return Date.now() + ms;
|
|
51247
|
+
}
|
|
51248
|
+
if (flags.at) {
|
|
51249
|
+
const hm = flags.at.match(/^(\d{1,2}):(\d{2})$/);
|
|
51250
|
+
if (hm) {
|
|
51251
|
+
const now = new Date;
|
|
51252
|
+
const target = new Date(now);
|
|
51253
|
+
target.setHours(parseInt(hm[1], 10), parseInt(hm[2], 10), 0, 0);
|
|
51254
|
+
if (target <= now)
|
|
51255
|
+
target.setDate(target.getDate() + 1);
|
|
51256
|
+
return target.getTime();
|
|
51257
|
+
}
|
|
51258
|
+
const ts = Date.parse(flags.at);
|
|
51259
|
+
return isNaN(ts) ? null : ts;
|
|
51260
|
+
}
|
|
51261
|
+
return null;
|
|
51262
|
+
}
|
|
51263
|
+
async function runRemind(flags, positional) {
|
|
51264
|
+
const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
|
|
51265
|
+
const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
|
|
51266
|
+
const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
|
|
51267
|
+
const action = positional[0];
|
|
51268
|
+
if (action === "list") {
|
|
51269
|
+
await withMesh({ meshSlug: flags.mesh ?? null }, async (client2) => {
|
|
51270
|
+
const scheduled = await client2.listScheduled();
|
|
51271
|
+
if (flags.json) {
|
|
51272
|
+
console.log(JSON.stringify(scheduled, null, 2));
|
|
51273
|
+
return;
|
|
51274
|
+
}
|
|
51275
|
+
if (scheduled.length === 0) {
|
|
51276
|
+
console.log(dim("No pending reminders."));
|
|
51277
|
+
return;
|
|
51278
|
+
}
|
|
51279
|
+
for (const m of scheduled) {
|
|
51280
|
+
const when = new Date(m.deliverAt).toLocaleString();
|
|
51281
|
+
const to = m.to === client2.getSessionPubkey() ? dim("(self)") : m.to;
|
|
51282
|
+
console.log(` ${bold2(m.id.slice(0, 8))} → ${to} at ${when}`);
|
|
51283
|
+
console.log(` ${dim(m.message.slice(0, 80))}`);
|
|
51284
|
+
console.log("");
|
|
51285
|
+
}
|
|
51286
|
+
});
|
|
51287
|
+
return;
|
|
51288
|
+
}
|
|
51289
|
+
if (action === "cancel") {
|
|
51290
|
+
const id = positional[1];
|
|
51291
|
+
if (!id) {
|
|
51292
|
+
console.error("Usage: claudemesh remind cancel <id>");
|
|
51293
|
+
process.exit(1);
|
|
51294
|
+
}
|
|
51295
|
+
await withMesh({ meshSlug: flags.mesh ?? null }, async (client2) => {
|
|
51296
|
+
const ok = await client2.cancelScheduled(id);
|
|
51297
|
+
if (ok)
|
|
51298
|
+
console.log(`✓ Cancelled ${id}`);
|
|
51299
|
+
else {
|
|
51300
|
+
console.error(`✗ Not found or already fired: ${id}`);
|
|
51301
|
+
process.exit(1);
|
|
51302
|
+
}
|
|
51303
|
+
});
|
|
51304
|
+
return;
|
|
51305
|
+
}
|
|
51306
|
+
const message = action ?? positional.join(" ");
|
|
51307
|
+
if (!message) {
|
|
51308
|
+
console.error("Usage: claudemesh remind <message> --in <duration>");
|
|
51309
|
+
console.error(" claudemesh remind <message> --at <time>");
|
|
51310
|
+
console.error(" claudemesh remind list");
|
|
51311
|
+
console.error(" claudemesh remind cancel <id>");
|
|
51312
|
+
process.exit(1);
|
|
51313
|
+
}
|
|
51314
|
+
const deliverAt = parseDeliverAt(flags);
|
|
51315
|
+
if (deliverAt === null) {
|
|
51316
|
+
console.error('Specify when: --in <duration> (e.g. "2h", "30m") or --at <time> (e.g. "15:00")');
|
|
51317
|
+
process.exit(1);
|
|
51318
|
+
}
|
|
51319
|
+
await withMesh({ meshSlug: flags.mesh ?? null }, async (client2) => {
|
|
51320
|
+
let targetSpec;
|
|
51321
|
+
if (flags.to && flags.to !== "self") {
|
|
51322
|
+
if (flags.to.startsWith("@") || flags.to === "*" || /^[0-9a-f]{64}$/i.test(flags.to)) {
|
|
51323
|
+
targetSpec = flags.to;
|
|
51324
|
+
} else {
|
|
51325
|
+
const peers = await client2.listPeers();
|
|
51326
|
+
const match = peers.find((p) => p.displayName.toLowerCase() === flags.to.toLowerCase());
|
|
51327
|
+
if (!match) {
|
|
51328
|
+
console.error(`Peer "${flags.to}" not found. Online: ${peers.map((p) => p.displayName).join(", ") || "(none)"}`);
|
|
51329
|
+
process.exit(1);
|
|
51330
|
+
}
|
|
51331
|
+
targetSpec = match.pubkey;
|
|
51332
|
+
}
|
|
51333
|
+
} else {
|
|
51334
|
+
targetSpec = client2.getSessionPubkey() ?? "*";
|
|
51335
|
+
}
|
|
51336
|
+
const result = await client2.scheduleMessage(targetSpec, message, deliverAt);
|
|
51337
|
+
if (!result) {
|
|
51338
|
+
console.error("✗ Broker did not acknowledge — check connection");
|
|
51339
|
+
process.exit(1);
|
|
51340
|
+
}
|
|
51341
|
+
if (flags.json) {
|
|
51342
|
+
console.log(JSON.stringify(result));
|
|
51343
|
+
return;
|
|
51344
|
+
}
|
|
51345
|
+
const when = new Date(result.deliverAt).toLocaleString();
|
|
51346
|
+
const toLabel = !flags.to || flags.to === "self" ? "yourself" : flags.to;
|
|
51347
|
+
console.log(`✓ Reminder set (${result.scheduledId.slice(0, 8)}): "${message}" → ${toLabel} at ${when}`);
|
|
51348
|
+
});
|
|
51349
|
+
}
|
|
51350
|
+
|
|
50991
51351
|
// src/index.ts
|
|
50992
51352
|
var launch = defineCommand({
|
|
50993
51353
|
meta: {
|
|
@@ -51173,6 +51533,55 @@ var main = defineCommand({
|
|
|
51173
51533
|
}
|
|
51174
51534
|
}
|
|
51175
51535
|
}),
|
|
51536
|
+
info: defineCommand({
|
|
51537
|
+
meta: { name: "info", description: "Show mesh overview: slug, broker, peer count, state keys" },
|
|
51538
|
+
args: {
|
|
51539
|
+
mesh: { type: "string", description: "Mesh slug (auto-selected if only one joined)" },
|
|
51540
|
+
json: { type: "boolean", description: "Output as JSON", default: false }
|
|
51541
|
+
},
|
|
51542
|
+
async run({ args }) {
|
|
51543
|
+
await runInfo(args);
|
|
51544
|
+
}
|
|
51545
|
+
}),
|
|
51546
|
+
remember: defineCommand({
|
|
51547
|
+
meta: { name: "remember", description: "Store a memory in the mesh (accessible to all peers)" },
|
|
51548
|
+
args: {
|
|
51549
|
+
content: { type: "positional", description: "Text to remember", required: true },
|
|
51550
|
+
mesh: { type: "string", description: "Mesh slug (auto-selected if only one joined)" },
|
|
51551
|
+
tags: { type: "string", description: "Comma-separated tags (e.g. task,context)" },
|
|
51552
|
+
json: { type: "boolean", description: "Output as JSON", default: false }
|
|
51553
|
+
},
|
|
51554
|
+
async run({ args }) {
|
|
51555
|
+
await runRemember(args, args.content);
|
|
51556
|
+
}
|
|
51557
|
+
}),
|
|
51558
|
+
recall: defineCommand({
|
|
51559
|
+
meta: { name: "recall", description: "Search mesh memory by keyword or phrase" },
|
|
51560
|
+
args: {
|
|
51561
|
+
query: { type: "positional", description: "Search query", required: true },
|
|
51562
|
+
mesh: { type: "string", description: "Mesh slug (auto-selected if only one joined)" },
|
|
51563
|
+
json: { type: "boolean", description: "Output as JSON", default: false }
|
|
51564
|
+
},
|
|
51565
|
+
async run({ args }) {
|
|
51566
|
+
await runRecall(args, args.query);
|
|
51567
|
+
}
|
|
51568
|
+
}),
|
|
51569
|
+
remind: defineCommand({
|
|
51570
|
+
meta: { name: "remind", description: "Schedule a reminder or delayed message via the broker" },
|
|
51571
|
+
args: {
|
|
51572
|
+
message: { type: "positional", description: "Message text, or: list | cancel <id>", required: false },
|
|
51573
|
+
extra: { type: "positional", description: "Additional positional args", required: false },
|
|
51574
|
+
in: { type: "string", description: 'Deliver after duration: "2h", "30m", "90s"' },
|
|
51575
|
+
at: { type: "string", description: 'Deliver at time: "15:00" or ISO timestamp' },
|
|
51576
|
+
to: { type: "string", description: "Recipient (default: self). Name, @group, pubkey, or *" },
|
|
51577
|
+
mesh: { type: "string", description: "Mesh slug (auto-selected if only one joined)" },
|
|
51578
|
+
json: { type: "boolean", description: "Output as JSON", default: false }
|
|
51579
|
+
},
|
|
51580
|
+
async run({ args, rawArgs }) {
|
|
51581
|
+
const positionals = rawArgs.filter((a) => !a.startsWith("-"));
|
|
51582
|
+
await runRemind(args, positionals);
|
|
51583
|
+
}
|
|
51584
|
+
}),
|
|
51176
51585
|
status: defineCommand({
|
|
51177
51586
|
meta: { name: "status", description: "Check broker reachability for each joined mesh" },
|
|
51178
51587
|
async run() {
|