claudemesh-cli 1.26.0 → 1.27.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/entrypoints/cli.js +1602 -1091
- package/dist/entrypoints/cli.js.map +14 -14
- package/dist/entrypoints/mcp.js +2 -2
- package/dist/entrypoints/mcp.js.map +1 -1
- package/package.json +1 -1
package/dist/entrypoints/cli.js
CHANGED
|
@@ -103,7 +103,7 @@ __export(exports_urls, {
|
|
|
103
103
|
VERSION: () => VERSION,
|
|
104
104
|
URLS: () => URLS
|
|
105
105
|
});
|
|
106
|
-
var URLS, VERSION = "1.
|
|
106
|
+
var URLS, VERSION = "1.27.0", env;
|
|
107
107
|
var init_urls = __esm(() => {
|
|
108
108
|
URLS = {
|
|
109
109
|
BROKER: process.env.CLAUDEMESH_BROKER_URL ?? "wss://ic.claudemesh.com/ws",
|
|
@@ -6524,1227 +6524,1369 @@ var init_connect = __esm(() => {
|
|
|
6524
6524
|
init_facade();
|
|
6525
6525
|
});
|
|
6526
6526
|
|
|
6527
|
-
// src/commands/
|
|
6528
|
-
var
|
|
6529
|
-
__export(
|
|
6530
|
-
|
|
6531
|
-
runDisconnect: () => runDisconnect
|
|
6527
|
+
// src/commands/info.ts
|
|
6528
|
+
var exports_info = {};
|
|
6529
|
+
__export(exports_info, {
|
|
6530
|
+
runInfo: () => runInfo
|
|
6532
6531
|
});
|
|
6533
|
-
function
|
|
6534
|
-
const m = input.match(/^(\d+)(s|m|h)$/);
|
|
6535
|
-
if (!m)
|
|
6536
|
-
return null;
|
|
6537
|
-
const val = parseInt(m[1], 10);
|
|
6538
|
-
const unit = m[2];
|
|
6539
|
-
if (unit === "s")
|
|
6540
|
-
return val * 1000;
|
|
6541
|
-
if (unit === "m")
|
|
6542
|
-
return val * 60000;
|
|
6543
|
-
if (unit === "h")
|
|
6544
|
-
return val * 3600000;
|
|
6545
|
-
return null;
|
|
6546
|
-
}
|
|
6547
|
-
function buildPayload(kind, target, opts) {
|
|
6548
|
-
if (opts.all)
|
|
6549
|
-
return { type: kind, all: true };
|
|
6550
|
-
if (opts.stale) {
|
|
6551
|
-
const ms = parseStaleMs(opts.stale);
|
|
6552
|
-
if (!ms)
|
|
6553
|
-
return { error: `Invalid stale duration: "${opts.stale}". Use e.g. 30m, 1h, 300s.` };
|
|
6554
|
-
return { type: kind, stale: ms };
|
|
6555
|
-
}
|
|
6556
|
-
if (target)
|
|
6557
|
-
return { type: kind, target };
|
|
6558
|
-
return { error: `Usage: claudemesh ${kind} <peer> | --stale 30m | --all` };
|
|
6559
|
-
}
|
|
6560
|
-
async function runDisconnect(target, opts = {}) {
|
|
6532
|
+
async function runInfo(flags) {
|
|
6561
6533
|
const config = readConfig();
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
6570
|
-
|
|
6571
|
-
|
|
6572
|
-
|
|
6573
|
-
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6534
|
+
await withMesh({ meshSlug: flags.mesh ?? null }, async (client, mesh) => {
|
|
6535
|
+
const [brokerInfo, peers, state] = await Promise.all([
|
|
6536
|
+
client.meshInfo(),
|
|
6537
|
+
client.listPeers(),
|
|
6538
|
+
client.listState()
|
|
6539
|
+
]);
|
|
6540
|
+
const output = {
|
|
6541
|
+
slug: mesh.slug,
|
|
6542
|
+
meshId: mesh.meshId,
|
|
6543
|
+
memberId: mesh.memberId,
|
|
6544
|
+
brokerUrl: mesh.brokerUrl,
|
|
6545
|
+
displayName: config.displayName ?? null,
|
|
6546
|
+
peerCount: peers.length,
|
|
6547
|
+
stateCount: state.length,
|
|
6548
|
+
...brokerInfo ?? {}
|
|
6549
|
+
};
|
|
6550
|
+
if (flags.json) {
|
|
6551
|
+
process.stdout.write(JSON.stringify(output, null, 2) + `
|
|
6552
|
+
`);
|
|
6553
|
+
return;
|
|
6580
6554
|
}
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
|
|
6597
|
-
const result = await client.sendAndWait(built);
|
|
6598
|
-
const peers = result?.affected ?? result?.kicked ?? [];
|
|
6599
|
-
if (peers.length === 0)
|
|
6600
|
-
render.info("No peers matched.");
|
|
6601
|
-
else {
|
|
6602
|
-
render.ok(`Kicked ${peers.length} peer(s): ${peers.join(", ")}`);
|
|
6603
|
-
render.hint("Their Claude Code session ended. They can rejoin anytime by running `claudemesh`.");
|
|
6555
|
+
render.section(`${mesh.slug} · ${mesh.brokerUrl}`);
|
|
6556
|
+
render.kv([
|
|
6557
|
+
["mesh", mesh.meshId],
|
|
6558
|
+
["member", mesh.memberId],
|
|
6559
|
+
["peers", `${peers.length} connected`],
|
|
6560
|
+
["state", `${state.length} keys`]
|
|
6561
|
+
]);
|
|
6562
|
+
if (brokerInfo && typeof brokerInfo === "object") {
|
|
6563
|
+
const extras = [];
|
|
6564
|
+
for (const [k, v] of Object.entries(brokerInfo)) {
|
|
6565
|
+
if (["slug", "meshId", "brokerUrl"].includes(k))
|
|
6566
|
+
continue;
|
|
6567
|
+
extras.push([k, JSON.stringify(v)]);
|
|
6568
|
+
}
|
|
6569
|
+
if (extras.length)
|
|
6570
|
+
render.kv(extras);
|
|
6604
6571
|
}
|
|
6605
|
-
return EXIT.SUCCESS;
|
|
6606
6572
|
});
|
|
6607
6573
|
}
|
|
6608
|
-
var
|
|
6574
|
+
var init_info2 = __esm(() => {
|
|
6609
6575
|
init_connect();
|
|
6610
6576
|
init_facade();
|
|
6611
6577
|
init_render();
|
|
6612
|
-
init_exit_codes();
|
|
6613
6578
|
});
|
|
6614
6579
|
|
|
6615
|
-
// src/
|
|
6616
|
-
|
|
6617
|
-
|
|
6618
|
-
|
|
6619
|
-
|
|
6620
|
-
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
}
|
|
6627
|
-
const config = readConfig();
|
|
6628
|
-
const meshSlug = opts.mesh ?? config.meshes[0]?.slug;
|
|
6629
|
-
if (!meshSlug) {
|
|
6630
|
-
render.err("No mesh joined.");
|
|
6631
|
-
return EXIT.NOT_FOUND;
|
|
6632
|
-
}
|
|
6633
|
-
return await withMesh({ meshSlug }, async (client) => {
|
|
6634
|
-
const result = await client.sendAndWait({ type: "ban", target });
|
|
6635
|
-
if (result?.banned) {
|
|
6636
|
-
render.ok(`Banned ${result.banned} from ${meshSlug}. They cannot reconnect until unbanned.`);
|
|
6637
|
-
render.hint(`Undo: claudemesh unban ${result.banned} --mesh ${meshSlug}`);
|
|
6638
|
-
} else {
|
|
6639
|
-
render.err(result?.message ?? result?.error ?? result?.code ?? "ban failed");
|
|
6640
|
-
}
|
|
6641
|
-
return result?.banned ? EXIT.SUCCESS : EXIT.INTERNAL_ERROR;
|
|
6642
|
-
});
|
|
6643
|
-
}
|
|
6644
|
-
async function runUnban(target, opts = {}) {
|
|
6645
|
-
if (!target) {
|
|
6646
|
-
render.err("Usage: claudemesh unban <peer-name-or-pubkey>");
|
|
6647
|
-
return EXIT.INVALID_ARGS;
|
|
6648
|
-
}
|
|
6649
|
-
const config = readConfig();
|
|
6650
|
-
const meshSlug = opts.mesh ?? config.meshes[0]?.slug;
|
|
6651
|
-
if (!meshSlug) {
|
|
6652
|
-
render.err("No mesh joined.");
|
|
6653
|
-
return EXIT.NOT_FOUND;
|
|
6654
|
-
}
|
|
6655
|
-
return await withMesh({ meshSlug }, async (client) => {
|
|
6656
|
-
const result = await client.sendAndWait({ type: "unban", target });
|
|
6657
|
-
if (result?.unbanned) {
|
|
6658
|
-
render.ok(`Unbanned ${result.unbanned} from ${meshSlug}. They can rejoin.`);
|
|
6659
|
-
} else {
|
|
6660
|
-
render.err(result?.message ?? result?.error ?? result?.code ?? "unban failed");
|
|
6661
|
-
}
|
|
6662
|
-
return result?.unbanned ? EXIT.SUCCESS : EXIT.INTERNAL_ERROR;
|
|
6663
|
-
});
|
|
6664
|
-
}
|
|
6665
|
-
async function runBans(opts = {}) {
|
|
6666
|
-
const config = readConfig();
|
|
6667
|
-
const meshSlug = opts.mesh ?? config.meshes[0]?.slug;
|
|
6668
|
-
if (!meshSlug) {
|
|
6669
|
-
render.err("No mesh joined.");
|
|
6670
|
-
return EXIT.NOT_FOUND;
|
|
6671
|
-
}
|
|
6672
|
-
return await withMesh({ meshSlug }, async (client) => {
|
|
6673
|
-
const result = await client.sendAndWait({ type: "list_bans" });
|
|
6674
|
-
const bans = result?.bans ?? [];
|
|
6675
|
-
if (opts.json) {
|
|
6676
|
-
process.stdout.write(JSON.stringify(bans, null, 2) + `
|
|
6677
|
-
`);
|
|
6678
|
-
return EXIT.SUCCESS;
|
|
6679
|
-
}
|
|
6680
|
-
if (bans.length === 0) {
|
|
6681
|
-
render.info("No banned members.");
|
|
6682
|
-
return EXIT.SUCCESS;
|
|
6580
|
+
// src/services/api/with-rest-key.ts
|
|
6581
|
+
async function withRestKey(opts, fn) {
|
|
6582
|
+
return withMesh({ meshSlug: opts.meshSlug ?? null }, async (client, mesh) => {
|
|
6583
|
+
const result = await client.apiKeyCreate({
|
|
6584
|
+
label: `cli-${opts.purpose ?? "rest"}-${process.pid}`,
|
|
6585
|
+
capabilities: opts.capabilities ?? ["read"],
|
|
6586
|
+
topicScopes: opts.topicScopes ?? undefined,
|
|
6587
|
+
expiresAt: new Date(Date.now() + 5 * 60 * 1000).toISOString()
|
|
6588
|
+
});
|
|
6589
|
+
if (!result || !result.secret) {
|
|
6590
|
+
throw new Error("apikey mint failed — broker did not return a secret");
|
|
6683
6591
|
}
|
|
6684
|
-
|
|
6685
|
-
|
|
6686
|
-
|
|
6592
|
+
try {
|
|
6593
|
+
return await fn({
|
|
6594
|
+
secret: result.secret,
|
|
6595
|
+
meshId: mesh.meshId,
|
|
6596
|
+
meshSlug: mesh.slug,
|
|
6597
|
+
client,
|
|
6598
|
+
mesh
|
|
6599
|
+
});
|
|
6600
|
+
} finally {
|
|
6601
|
+
try {
|
|
6602
|
+
await client.apiKeyRevoke(result.id);
|
|
6603
|
+
} catch {}
|
|
6687
6604
|
}
|
|
6688
|
-
return EXIT.SUCCESS;
|
|
6689
6605
|
});
|
|
6690
6606
|
}
|
|
6691
|
-
var
|
|
6607
|
+
var init_with_rest_key = __esm(() => {
|
|
6692
6608
|
init_connect();
|
|
6693
|
-
init_facade();
|
|
6694
|
-
init_render();
|
|
6695
|
-
init_exit_codes();
|
|
6696
6609
|
});
|
|
6697
6610
|
|
|
6698
|
-
// src/
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
6703
|
-
|
|
6704
|
-
|
|
6705
|
-
|
|
6706
|
-
|
|
6611
|
+
// src/commands/me.ts
|
|
6612
|
+
var exports_me = {};
|
|
6613
|
+
__export(exports_me, {
|
|
6614
|
+
runMeTopics: () => runMeTopics,
|
|
6615
|
+
runMeTasks: () => runMeTasks,
|
|
6616
|
+
runMeState: () => runMeState,
|
|
6617
|
+
runMeSearch: () => runMeSearch,
|
|
6618
|
+
runMeNotifications: () => runMeNotifications,
|
|
6619
|
+
runMeMemory: () => runMeMemory,
|
|
6620
|
+
runMeActivity: () => runMeActivity,
|
|
6621
|
+
runMe: () => runMe
|
|
6622
|
+
});
|
|
6623
|
+
function resolveMeshForMint(explicit) {
|
|
6624
|
+
if (explicit)
|
|
6625
|
+
return explicit;
|
|
6626
|
+
const cfg = readConfig();
|
|
6627
|
+
return cfg.meshes[0]?.slug ?? null;
|
|
6707
6628
|
}
|
|
6708
|
-
|
|
6709
|
-
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
|
|
6713
|
-
|
|
6714
|
-
|
|
6715
|
-
|
|
6716
|
-
|
|
6717
|
-
|
|
6718
|
-
|
|
6719
|
-
|
|
6629
|
+
async function runMe(flags) {
|
|
6630
|
+
return withRestKey({
|
|
6631
|
+
meshSlug: resolveMeshForMint(flags.mesh),
|
|
6632
|
+
purpose: "workspace-overview",
|
|
6633
|
+
capabilities: ["read"]
|
|
6634
|
+
}, async ({ secret }) => {
|
|
6635
|
+
const ws = await request({
|
|
6636
|
+
path: "/api/v1/me/workspace",
|
|
6637
|
+
token: secret
|
|
6638
|
+
});
|
|
6639
|
+
if (flags.json) {
|
|
6640
|
+
console.log(JSON.stringify(ws, null, 2));
|
|
6641
|
+
return EXIT.SUCCESS;
|
|
6642
|
+
}
|
|
6643
|
+
render.section(`${clay("workspace")} — ${bold(ws.userId.slice(0, 8))} ${dim(`· ${ws.totals.meshes} mesh${ws.totals.meshes === 1 ? "" : "es"}`)}`);
|
|
6644
|
+
const totalsLine = [
|
|
6645
|
+
`${green(String(ws.totals.online))}/${ws.totals.peers} online`,
|
|
6646
|
+
`${ws.totals.topics} topic${ws.totals.topics === 1 ? "" : "s"}`,
|
|
6647
|
+
ws.totals.unreadMentions > 0 ? yellow(`${ws.totals.unreadMentions} unread @you`) : dim("0 unread @you")
|
|
6648
|
+
].join(dim(" · "));
|
|
6649
|
+
process.stdout.write(" " + totalsLine + `
|
|
6650
|
+
|
|
6720
6651
|
`);
|
|
6652
|
+
if (ws.meshes.length === 0) {
|
|
6653
|
+
process.stdout.write(dim(" no meshes joined — run `claudemesh new` or accept an invite\n"));
|
|
6654
|
+
return EXIT.SUCCESS;
|
|
6721
6655
|
}
|
|
6722
|
-
|
|
6723
|
-
|
|
6656
|
+
const slugWidth = Math.max(...ws.meshes.map((m) => m.slug.length), 8);
|
|
6657
|
+
for (const m of ws.meshes) {
|
|
6658
|
+
const slug = cyan(m.slug.padEnd(slugWidth));
|
|
6659
|
+
const peers = `${m.online}/${m.peers}`;
|
|
6660
|
+
const role = dim(m.myRole);
|
|
6661
|
+
const unread = m.unreadMentions > 0 ? " " + yellow(`${m.unreadMentions} @you`) : "";
|
|
6662
|
+
process.stdout.write(` ${slug} ${peers.padStart(5)} online ${dim(String(m.topics).padStart(2) + " topics")} ${role}${unread}
|
|
6663
|
+
`);
|
|
6664
|
+
}
|
|
6665
|
+
return EXIT.SUCCESS;
|
|
6666
|
+
});
|
|
6724
6667
|
}
|
|
6725
|
-
|
|
6726
|
-
|
|
6727
|
-
|
|
6728
|
-
|
|
6729
|
-
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
|
|
6733
|
-
|
|
6734
|
-
return null;
|
|
6735
|
-
return new Promise((resolve) => {
|
|
6736
|
-
const id = randomUUID2();
|
|
6737
|
-
const req = { id, verb, args };
|
|
6738
|
-
const parser = new LineParser;
|
|
6739
|
-
let settled = false;
|
|
6740
|
-
const finish = (value) => {
|
|
6741
|
-
if (settled)
|
|
6742
|
-
return;
|
|
6743
|
-
settled = true;
|
|
6744
|
-
try {
|
|
6745
|
-
socket.destroy();
|
|
6746
|
-
} catch {}
|
|
6747
|
-
clearTimeout(timer);
|
|
6748
|
-
resolve(value);
|
|
6749
|
-
};
|
|
6750
|
-
const socket = createConnection({ path });
|
|
6751
|
-
const timer = setTimeout(() => {
|
|
6752
|
-
finish(null);
|
|
6753
|
-
}, timeoutMs);
|
|
6754
|
-
socket.on("connect", () => {
|
|
6755
|
-
try {
|
|
6756
|
-
socket.write(frame(req));
|
|
6757
|
-
} catch {
|
|
6758
|
-
finish(null);
|
|
6759
|
-
}
|
|
6760
|
-
});
|
|
6761
|
-
socket.on("data", (chunk) => {
|
|
6762
|
-
const lines = parser.feed(chunk);
|
|
6763
|
-
for (const line of lines) {
|
|
6764
|
-
if (!line.trim())
|
|
6765
|
-
continue;
|
|
6766
|
-
let res;
|
|
6767
|
-
try {
|
|
6768
|
-
res = JSON.parse(line);
|
|
6769
|
-
} catch {
|
|
6770
|
-
continue;
|
|
6771
|
-
}
|
|
6772
|
-
if (res.id !== id)
|
|
6773
|
-
continue;
|
|
6774
|
-
if (res.ok)
|
|
6775
|
-
finish({ ok: true, result: res.result });
|
|
6776
|
-
else
|
|
6777
|
-
finish({ ok: false, error: res.error });
|
|
6778
|
-
return;
|
|
6779
|
-
}
|
|
6780
|
-
});
|
|
6781
|
-
socket.on("error", (err) => {
|
|
6782
|
-
const code = err.code;
|
|
6783
|
-
if (code === "ECONNREFUSED" || code === "ENOENT" || code === "EPERM") {
|
|
6784
|
-
finish(null);
|
|
6785
|
-
} else {
|
|
6786
|
-
finish(null);
|
|
6787
|
-
}
|
|
6788
|
-
});
|
|
6789
|
-
socket.on("close", () => {
|
|
6790
|
-
finish(null);
|
|
6668
|
+
async function runMeTopics(flags) {
|
|
6669
|
+
return withRestKey({
|
|
6670
|
+
meshSlug: resolveMeshForMint(flags.mesh),
|
|
6671
|
+
purpose: "workspace-topics",
|
|
6672
|
+
capabilities: ["read"]
|
|
6673
|
+
}, async ({ secret }) => {
|
|
6674
|
+
const ws = await request({
|
|
6675
|
+
path: "/api/v1/me/topics",
|
|
6676
|
+
token: secret
|
|
6791
6677
|
});
|
|
6678
|
+
const visible = flags.unread ? ws.topics.filter((t) => t.unread > 0) : ws.topics;
|
|
6679
|
+
if (flags.json) {
|
|
6680
|
+
console.log(JSON.stringify({ topics: visible, totals: ws.totals }, null, 2));
|
|
6681
|
+
return EXIT.SUCCESS;
|
|
6682
|
+
}
|
|
6683
|
+
render.section(`${clay("topics")} — ${ws.totals.topics} across all meshes ${dim(ws.totals.unread > 0 ? `· ${ws.totals.unread} unread` : "· all read")}`);
|
|
6684
|
+
if (visible.length === 0) {
|
|
6685
|
+
process.stdout.write(dim(flags.unread ? ` no unread topics
|
|
6686
|
+
` : " no topics — run `claudemesh topic create #general`\n"));
|
|
6687
|
+
return EXIT.SUCCESS;
|
|
6688
|
+
}
|
|
6689
|
+
const slugWidth = Math.max(...visible.map((t) => t.meshSlug.length), 6);
|
|
6690
|
+
const nameWidth = Math.max(...visible.map((t) => t.name.length), 8);
|
|
6691
|
+
for (const t of visible) {
|
|
6692
|
+
const slug = dim(t.meshSlug.padEnd(slugWidth));
|
|
6693
|
+
const name = cyan(t.name.padEnd(nameWidth));
|
|
6694
|
+
const unread = t.unread > 0 ? yellow(`${t.unread} unread`.padStart(10)) : dim("·".padStart(10));
|
|
6695
|
+
const last = t.lastMessageAt ? dim(formatRelativeTime(t.lastMessageAt)) : dim("never");
|
|
6696
|
+
process.stdout.write(` ${slug} ${name} ${unread} ${last}
|
|
6697
|
+
`);
|
|
6698
|
+
}
|
|
6699
|
+
return EXIT.SUCCESS;
|
|
6792
6700
|
});
|
|
6793
6701
|
}
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
|
|
6799
|
-
|
|
6800
|
-
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
|
|
6702
|
+
async function runMeNotifications(flags) {
|
|
6703
|
+
return withRestKey({
|
|
6704
|
+
meshSlug: resolveMeshForMint(flags.mesh),
|
|
6705
|
+
purpose: "workspace-notifications",
|
|
6706
|
+
capabilities: ["read"]
|
|
6707
|
+
}, async ({ secret }) => {
|
|
6708
|
+
const params = new URLSearchParams;
|
|
6709
|
+
if (flags.all)
|
|
6710
|
+
params.set("include", "all");
|
|
6711
|
+
if (flags.since)
|
|
6712
|
+
params.set("since", flags.since);
|
|
6713
|
+
const path = "/api/v1/me/notifications" + (params.toString() ? `?${params.toString()}` : "");
|
|
6714
|
+
const ws = await request({
|
|
6715
|
+
path,
|
|
6716
|
+
token: secret
|
|
6717
|
+
});
|
|
6718
|
+
if (flags.json) {
|
|
6719
|
+
console.log(JSON.stringify(ws, null, 2));
|
|
6720
|
+
return EXIT.SUCCESS;
|
|
6721
|
+
}
|
|
6722
|
+
const headerLabel = flags.all ? "@-mentions (all)" : "@-mentions (unread)";
|
|
6723
|
+
render.section(`${clay(headerLabel)} — ${ws.totals.total} ${dim(ws.totals.unread > 0 ? `· ${ws.totals.unread} unread` : "· nothing pending")}`);
|
|
6724
|
+
if (ws.notifications.length === 0) {
|
|
6725
|
+
process.stdout.write(dim(flags.all ? ` no @-mentions in window
|
|
6726
|
+
` : ` inbox zero — nothing waiting
|
|
6727
|
+
`));
|
|
6728
|
+
return EXIT.SUCCESS;
|
|
6729
|
+
}
|
|
6730
|
+
const slugWidth = Math.max(...ws.notifications.map((n) => n.meshSlug.length), 6);
|
|
6731
|
+
for (const n of ws.notifications) {
|
|
6732
|
+
const slug = dim(n.meshSlug.padEnd(slugWidth));
|
|
6733
|
+
const topic = cyan(`#${n.topicName}`);
|
|
6734
|
+
const sender = n.senderName ? `from ${n.senderName}` : "from ?";
|
|
6735
|
+
const ago = formatRelativeTime(n.createdAt);
|
|
6736
|
+
const dot = n.read ? dim("·") : yellow("●");
|
|
6737
|
+
const snippet = n.snippet ?? (n.ciphertext ? dim("[encrypted]") : dim("[empty]"));
|
|
6738
|
+
process.stdout.write(` ${dot} ${slug} ${topic} ${dim(sender)} ${dim(ago)}
|
|
6739
|
+
` + ` ${snippet.length > 200 ? snippet.slice(0, 200) + "…" : snippet}
|
|
6740
|
+
`);
|
|
6741
|
+
}
|
|
6742
|
+
return EXIT.SUCCESS;
|
|
6743
|
+
});
|
|
6809
6744
|
}
|
|
6810
|
-
function
|
|
6811
|
-
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6745
|
+
async function runMeActivity(flags) {
|
|
6746
|
+
return withRestKey({
|
|
6747
|
+
meshSlug: resolveMeshForMint(flags.mesh),
|
|
6748
|
+
purpose: "workspace-activity",
|
|
6749
|
+
capabilities: ["read"]
|
|
6750
|
+
}, async ({ secret }) => {
|
|
6751
|
+
const params = new URLSearchParams;
|
|
6752
|
+
if (flags.since)
|
|
6753
|
+
params.set("since", flags.since);
|
|
6754
|
+
const path = "/api/v1/me/activity" + (params.toString() ? `?${params.toString()}` : "");
|
|
6755
|
+
const ws = await request({
|
|
6756
|
+
path,
|
|
6757
|
+
token: secret
|
|
6758
|
+
});
|
|
6759
|
+
if (flags.json) {
|
|
6760
|
+
console.log(JSON.stringify(ws, null, 2));
|
|
6761
|
+
return EXIT.SUCCESS;
|
|
6762
|
+
}
|
|
6763
|
+
render.section(`${clay("activity")} — ${ws.totals.events} ${dim(flags.since ? `since ${flags.since}` : "in the last 24h")}`);
|
|
6764
|
+
if (ws.activity.length === 0) {
|
|
6765
|
+
process.stdout.write(dim(` quiet — no activity in window
|
|
6766
|
+
`));
|
|
6767
|
+
return EXIT.SUCCESS;
|
|
6768
|
+
}
|
|
6769
|
+
const slugWidth = Math.max(...ws.activity.map((a) => a.meshSlug.length), 6);
|
|
6770
|
+
for (const a of ws.activity) {
|
|
6771
|
+
const slug = dim(a.meshSlug.padEnd(slugWidth));
|
|
6772
|
+
const topic = cyan(`#${a.topicName}`);
|
|
6773
|
+
const sender = a.senderName ?? "?";
|
|
6774
|
+
const ago = formatRelativeTime(a.createdAt);
|
|
6775
|
+
const snippet = a.snippet ?? (a.ciphertext ? dim("[encrypted]") : dim("[empty]"));
|
|
6776
|
+
process.stdout.write(` ${slug} ${topic} ${dim(sender + " ·")} ${dim(ago)}
|
|
6777
|
+
` + ` ${snippet.length > 200 ? snippet.slice(0, 200) + "…" : snippet}
|
|
6778
|
+
`);
|
|
6779
|
+
}
|
|
6780
|
+
return EXIT.SUCCESS;
|
|
6781
|
+
});
|
|
6819
6782
|
}
|
|
6820
|
-
|
|
6821
|
-
|
|
6822
|
-
|
|
6823
|
-
|
|
6824
|
-
|
|
6825
|
-
import { request as httpRequest } from "node:http";
|
|
6826
|
-
async function ipc(opts) {
|
|
6827
|
-
const useTcp = !!opts.preferTcp;
|
|
6828
|
-
const headers = {
|
|
6829
|
-
accept: "application/json",
|
|
6830
|
-
host: "localhost"
|
|
6831
|
-
};
|
|
6832
|
-
let bodyBuf;
|
|
6833
|
-
if (opts.body !== undefined) {
|
|
6834
|
-
bodyBuf = Buffer.from(JSON.stringify(opts.body), "utf8");
|
|
6835
|
-
headers["content-type"] = "application/json";
|
|
6836
|
-
headers["content-length"] = String(bodyBuf.length);
|
|
6837
|
-
}
|
|
6838
|
-
if (useTcp) {
|
|
6839
|
-
const tok = readLocalToken();
|
|
6840
|
-
if (!tok)
|
|
6841
|
-
throw new IpcError(0, null, "daemon local token not found; is the daemon running?");
|
|
6842
|
-
headers.authorization = `Bearer ${tok}`;
|
|
6783
|
+
async function runMeSearch(flags) {
|
|
6784
|
+
if (!flags.query || flags.query.length < 2) {
|
|
6785
|
+
process.stderr.write(`Usage: claudemesh me search <query> (min 2 chars)
|
|
6786
|
+
`);
|
|
6787
|
+
return EXIT.INVALID_ARGS;
|
|
6843
6788
|
}
|
|
6844
|
-
return
|
|
6845
|
-
|
|
6846
|
-
|
|
6847
|
-
|
|
6848
|
-
|
|
6849
|
-
|
|
6850
|
-
|
|
6851
|
-
|
|
6852
|
-
|
|
6853
|
-
} catch {}
|
|
6854
|
-
resolve({ status: res.statusCode ?? 0, body: parsed });
|
|
6855
|
-
});
|
|
6789
|
+
return withRestKey({
|
|
6790
|
+
meshSlug: resolveMeshForMint(flags.mesh),
|
|
6791
|
+
purpose: "workspace-search",
|
|
6792
|
+
capabilities: ["read"]
|
|
6793
|
+
}, async ({ secret }) => {
|
|
6794
|
+
const params = new URLSearchParams({ q: flags.query });
|
|
6795
|
+
const ws = await request({
|
|
6796
|
+
path: `/api/v1/me/search?${params.toString()}`,
|
|
6797
|
+
token: secret
|
|
6856
6798
|
});
|
|
6857
|
-
|
|
6858
|
-
|
|
6859
|
-
|
|
6860
|
-
|
|
6861
|
-
|
|
6799
|
+
if (flags.json) {
|
|
6800
|
+
console.log(JSON.stringify(ws, null, 2));
|
|
6801
|
+
return EXIT.SUCCESS;
|
|
6802
|
+
}
|
|
6803
|
+
render.section(`${clay("search")} — "${flags.query}" ${dim(`${ws.totals.topics} topic${ws.totals.topics === 1 ? "" : "s"}, ` + `${ws.totals.messages} message${ws.totals.messages === 1 ? "" : "s"}`)}`);
|
|
6804
|
+
if (ws.topics.length === 0 && ws.messages.length === 0) {
|
|
6805
|
+
process.stdout.write(dim(` no matches
|
|
6806
|
+
`));
|
|
6807
|
+
return EXIT.SUCCESS;
|
|
6808
|
+
}
|
|
6809
|
+
if (ws.topics.length > 0) {
|
|
6810
|
+
process.stdout.write(dim(`
|
|
6811
|
+
topics
|
|
6812
|
+
`));
|
|
6813
|
+
const slugWidth = Math.max(...ws.topics.map((t) => t.meshSlug.length), 6);
|
|
6814
|
+
for (const t of ws.topics) {
|
|
6815
|
+
const slug = dim(t.meshSlug.padEnd(slugWidth));
|
|
6816
|
+
const name = cyan(`#${t.name}`);
|
|
6817
|
+
const desc = t.description ? dim(` — ${t.description}`) : "";
|
|
6818
|
+
process.stdout.write(` ${slug} ${name}${desc}
|
|
6819
|
+
`);
|
|
6820
|
+
}
|
|
6821
|
+
}
|
|
6822
|
+
if (ws.messages.length > 0) {
|
|
6823
|
+
process.stdout.write(dim(`
|
|
6824
|
+
messages
|
|
6825
|
+
`));
|
|
6826
|
+
const slugWidth = Math.max(...ws.messages.map((m) => m.meshSlug.length), 6);
|
|
6827
|
+
for (const m of ws.messages) {
|
|
6828
|
+
const slug = dim(m.meshSlug.padEnd(slugWidth));
|
|
6829
|
+
const topic = cyan(`#${m.topicName}`);
|
|
6830
|
+
const sender = m.senderName;
|
|
6831
|
+
const ago = formatRelativeTime(m.createdAt);
|
|
6832
|
+
const snippet = m.snippet ?? (m.bodyVersion === 2 ? dim("[encrypted — open the topic to decrypt]") : dim("[empty]"));
|
|
6833
|
+
const highlighted = m.snippet ? highlightMatch(snippet, flags.query) : snippet;
|
|
6834
|
+
process.stdout.write(` ${slug} ${topic} ${dim(sender + " ·")} ${dim(ago)}
|
|
6835
|
+
` + ` ${highlighted}
|
|
6836
|
+
`);
|
|
6837
|
+
}
|
|
6838
|
+
}
|
|
6839
|
+
return EXIT.SUCCESS;
|
|
6862
6840
|
});
|
|
6863
6841
|
}
|
|
6864
|
-
|
|
6865
|
-
|
|
6866
|
-
|
|
6867
|
-
|
|
6868
|
-
|
|
6869
|
-
|
|
6870
|
-
|
|
6871
|
-
|
|
6872
|
-
|
|
6873
|
-
|
|
6874
|
-
this.payload = payload;
|
|
6875
|
-
}
|
|
6876
|
-
};
|
|
6877
|
-
});
|
|
6878
|
-
|
|
6879
|
-
// src/services/bridge/daemon-route.ts
|
|
6880
|
-
var exports_daemon_route = {};
|
|
6881
|
-
__export(exports_daemon_route, {
|
|
6882
|
-
trySendViaDaemon: () => trySendViaDaemon,
|
|
6883
|
-
tryListSkillsViaDaemon: () => tryListSkillsViaDaemon,
|
|
6884
|
-
tryListPeersViaDaemon: () => tryListPeersViaDaemon,
|
|
6885
|
-
tryGetSkillViaDaemon: () => tryGetSkillViaDaemon
|
|
6886
|
-
});
|
|
6887
|
-
import { existsSync as existsSync7 } from "node:fs";
|
|
6888
|
-
async function tryListPeersViaDaemon() {
|
|
6889
|
-
if (!existsSync7(DAEMON_PATHS.SOCK_FILE))
|
|
6890
|
-
return null;
|
|
6891
|
-
try {
|
|
6892
|
-
const res = await ipc({ path: "/v1/peers", timeoutMs: 3000 });
|
|
6893
|
-
if (res.status !== 200)
|
|
6894
|
-
return null;
|
|
6895
|
-
return Array.isArray(res.body.peers) ? res.body.peers : [];
|
|
6896
|
-
} catch (err) {
|
|
6897
|
-
const msg = String(err);
|
|
6898
|
-
if (/ENOENT|ECONNREFUSED|ipc_timeout/.test(msg))
|
|
6899
|
-
return null;
|
|
6900
|
-
return null;
|
|
6901
|
-
}
|
|
6842
|
+
function highlightMatch(text, query) {
|
|
6843
|
+
if (!query)
|
|
6844
|
+
return text;
|
|
6845
|
+
const idx = text.toLowerCase().indexOf(query.toLowerCase());
|
|
6846
|
+
if (idx === -1)
|
|
6847
|
+
return text;
|
|
6848
|
+
const before = text.slice(0, idx);
|
|
6849
|
+
const match = text.slice(idx, idx + query.length);
|
|
6850
|
+
const after = text.slice(idx + query.length);
|
|
6851
|
+
return `${before}${yellow(match)}${after}`;
|
|
6902
6852
|
}
|
|
6903
|
-
async function
|
|
6904
|
-
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
|
|
6911
|
-
|
|
6912
|
-
const
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6853
|
+
async function runMeTasks(flags) {
|
|
6854
|
+
return withRestKey({
|
|
6855
|
+
meshSlug: resolveMeshForMint(flags.mesh),
|
|
6856
|
+
purpose: "workspace-tasks",
|
|
6857
|
+
capabilities: ["read"]
|
|
6858
|
+
}, async ({ secret }) => {
|
|
6859
|
+
const params = new URLSearchParams;
|
|
6860
|
+
if (flags.status)
|
|
6861
|
+
params.set("status", flags.status);
|
|
6862
|
+
const path = "/api/v1/me/tasks" + (params.toString() ? `?${params.toString()}` : "");
|
|
6863
|
+
const ws = await request({
|
|
6864
|
+
path,
|
|
6865
|
+
token: secret
|
|
6866
|
+
});
|
|
6867
|
+
if (flags.json) {
|
|
6868
|
+
console.log(JSON.stringify(ws, null, 2));
|
|
6869
|
+
return EXIT.SUCCESS;
|
|
6870
|
+
}
|
|
6871
|
+
render.section(`${clay("tasks")} — ${dim(`${ws.totals.open} open · ${ws.totals.claimed} in-flight · ${ws.totals.completed} done`)}`);
|
|
6872
|
+
if (ws.tasks.length === 0) {
|
|
6873
|
+
process.stdout.write(dim(` no tasks in window
|
|
6874
|
+
`));
|
|
6875
|
+
return EXIT.SUCCESS;
|
|
6876
|
+
}
|
|
6877
|
+
const slugWidth = Math.max(...ws.tasks.map((t) => t.meshSlug.length), 6);
|
|
6878
|
+
for (const t of ws.tasks) {
|
|
6879
|
+
const slug = dim(t.meshSlug.padEnd(slugWidth));
|
|
6880
|
+
const status = t.status === "open" ? yellow("open ") : t.status === "claimed" ? cyan("working ") : green("done ");
|
|
6881
|
+
const prio = t.priority === "urgent" ? yellow("!") : t.priority === "low" ? dim("·") : " ";
|
|
6882
|
+
const claimer = t.claimedByName ? dim(` ← ${t.claimedByName}`) : "";
|
|
6883
|
+
process.stdout.write(` ${slug} ${prio} ${status} ${t.title}${claimer}
|
|
6884
|
+
`);
|
|
6885
|
+
}
|
|
6886
|
+
return EXIT.SUCCESS;
|
|
6887
|
+
});
|
|
6917
6888
|
}
|
|
6918
|
-
async function
|
|
6919
|
-
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
|
|
6923
|
-
|
|
6924
|
-
|
|
6889
|
+
async function runMeState(flags) {
|
|
6890
|
+
return withRestKey({
|
|
6891
|
+
meshSlug: resolveMeshForMint(flags.mesh),
|
|
6892
|
+
purpose: "workspace-state",
|
|
6893
|
+
capabilities: ["read"]
|
|
6894
|
+
}, async ({ secret }) => {
|
|
6895
|
+
const params = new URLSearchParams;
|
|
6896
|
+
if (flags.key)
|
|
6897
|
+
params.set("key", flags.key);
|
|
6898
|
+
const path = "/api/v1/me/state" + (params.toString() ? `?${params.toString()}` : "");
|
|
6899
|
+
const ws = await request({
|
|
6900
|
+
path,
|
|
6901
|
+
token: secret
|
|
6925
6902
|
});
|
|
6926
|
-
if (
|
|
6927
|
-
|
|
6928
|
-
|
|
6929
|
-
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6903
|
+
if (flags.json) {
|
|
6904
|
+
console.log(JSON.stringify(ws, null, 2));
|
|
6905
|
+
return EXIT.SUCCESS;
|
|
6906
|
+
}
|
|
6907
|
+
render.section(`${clay("state")} — ${ws.totals.entries} entr${ws.totals.entries === 1 ? "y" : "ies"} ${dim(`across ${ws.totals.meshes} mesh${ws.totals.meshes === 1 ? "" : "es"}`)}`);
|
|
6908
|
+
if (ws.entries.length === 0) {
|
|
6909
|
+
process.stdout.write(dim(` no state entries
|
|
6910
|
+
`));
|
|
6911
|
+
return EXIT.SUCCESS;
|
|
6912
|
+
}
|
|
6913
|
+
const slugWidth = Math.max(...ws.entries.map((e) => e.meshSlug.length), 6);
|
|
6914
|
+
const keyWidth = Math.max(...ws.entries.map((e) => e.key.length), 8);
|
|
6915
|
+
for (const e of ws.entries) {
|
|
6916
|
+
const slug = dim(e.meshSlug.padEnd(slugWidth));
|
|
6917
|
+
const key = cyan(e.key.padEnd(keyWidth));
|
|
6918
|
+
const valueStr = typeof e.value === "string" ? e.value : JSON.stringify(e.value);
|
|
6919
|
+
const trimmed = valueStr.length > 80 ? valueStr.slice(0, 80) + "…" : valueStr;
|
|
6920
|
+
const ago = dim(formatRelativeTime(e.updatedAt));
|
|
6921
|
+
process.stdout.write(` ${slug} ${key} ${trimmed} ${ago}
|
|
6922
|
+
`);
|
|
6923
|
+
}
|
|
6924
|
+
return EXIT.SUCCESS;
|
|
6925
|
+
});
|
|
6934
6926
|
}
|
|
6935
|
-
async function
|
|
6936
|
-
|
|
6937
|
-
|
|
6938
|
-
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
|
|
6944
|
-
|
|
6945
|
-
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
...args.expectedMesh ? { mesh: args.expectedMesh } : {}
|
|
6949
|
-
}
|
|
6927
|
+
async function runMeMemory(flags) {
|
|
6928
|
+
return withRestKey({
|
|
6929
|
+
meshSlug: resolveMeshForMint(flags.mesh),
|
|
6930
|
+
purpose: "workspace-memory",
|
|
6931
|
+
capabilities: ["read"]
|
|
6932
|
+
}, async ({ secret }) => {
|
|
6933
|
+
const params = new URLSearchParams;
|
|
6934
|
+
if (flags.query)
|
|
6935
|
+
params.set("q", flags.query);
|
|
6936
|
+
const path = "/api/v1/me/memory" + (params.toString() ? `?${params.toString()}` : "");
|
|
6937
|
+
const ws = await request({
|
|
6938
|
+
path,
|
|
6939
|
+
token: secret
|
|
6950
6940
|
});
|
|
6951
|
-
if (
|
|
6952
|
-
|
|
6953
|
-
|
|
6954
|
-
messageId: res.body.broker_message_id ?? res.body.client_message_id ?? "",
|
|
6955
|
-
duplicate: res.body.duplicate,
|
|
6956
|
-
status: res.body.status
|
|
6957
|
-
};
|
|
6941
|
+
if (flags.json) {
|
|
6942
|
+
console.log(JSON.stringify(ws, null, 2));
|
|
6943
|
+
return EXIT.SUCCESS;
|
|
6958
6944
|
}
|
|
6959
|
-
|
|
6960
|
-
}
|
|
6961
|
-
|
|
6962
|
-
|
|
6963
|
-
|
|
6964
|
-
|
|
6965
|
-
|
|
6945
|
+
const headerLabel = flags.query ? `recall — "${flags.query}"` : "recall — last 30 days";
|
|
6946
|
+
render.section(`${clay(headerLabel)} ${dim(`${ws.totals.entries} match${ws.totals.entries === 1 ? "" : "es"}`)}`);
|
|
6947
|
+
if (ws.memories.length === 0) {
|
|
6948
|
+
process.stdout.write(dim(` no memories
|
|
6949
|
+
`));
|
|
6950
|
+
return EXIT.SUCCESS;
|
|
6951
|
+
}
|
|
6952
|
+
const slugWidth = Math.max(...ws.memories.map((m) => m.meshSlug.length), 6);
|
|
6953
|
+
for (const m of ws.memories) {
|
|
6954
|
+
const slug = dim(m.meshSlug.padEnd(slugWidth));
|
|
6955
|
+
const ago = dim(formatRelativeTime(m.rememberedAt));
|
|
6956
|
+
const tags = m.tags.length > 0 ? " " + dim("[" + m.tags.join(", ") + "]") : "";
|
|
6957
|
+
const content = m.content.length > 240 ? m.content.slice(0, 240) + "…" : m.content;
|
|
6958
|
+
process.stdout.write(` ${slug} ${ago}${tags}
|
|
6959
|
+
${content}
|
|
6960
|
+
`);
|
|
6961
|
+
}
|
|
6962
|
+
return EXIT.SUCCESS;
|
|
6963
|
+
});
|
|
6966
6964
|
}
|
|
6967
|
-
|
|
6968
|
-
|
|
6969
|
-
|
|
6965
|
+
function formatRelativeTime(iso) {
|
|
6966
|
+
const then = new Date(iso).getTime();
|
|
6967
|
+
const now = Date.now();
|
|
6968
|
+
const sec = Math.max(0, Math.floor((now - then) / 1000));
|
|
6969
|
+
if (sec < 60)
|
|
6970
|
+
return `${sec}s ago`;
|
|
6971
|
+
if (sec < 3600)
|
|
6972
|
+
return `${Math.floor(sec / 60)}m ago`;
|
|
6973
|
+
if (sec < 86400)
|
|
6974
|
+
return `${Math.floor(sec / 3600)}h ago`;
|
|
6975
|
+
if (sec < 86400 * 30)
|
|
6976
|
+
return `${Math.floor(sec / 86400)}d ago`;
|
|
6977
|
+
if (sec < 86400 * 365)
|
|
6978
|
+
return `${Math.floor(sec / (86400 * 30))}mo ago`;
|
|
6979
|
+
return `${Math.floor(sec / (86400 * 365))}y ago`;
|
|
6980
|
+
}
|
|
6981
|
+
var init_me = __esm(() => {
|
|
6982
|
+
init_with_rest_key();
|
|
6983
|
+
init_client();
|
|
6984
|
+
init_facade();
|
|
6985
|
+
init_render();
|
|
6986
|
+
init_styles();
|
|
6987
|
+
init_exit_codes();
|
|
6970
6988
|
});
|
|
6971
6989
|
|
|
6972
|
-
// src/commands/
|
|
6973
|
-
var
|
|
6974
|
-
__export(
|
|
6975
|
-
|
|
6990
|
+
// src/commands/kick.ts
|
|
6991
|
+
var exports_kick = {};
|
|
6992
|
+
__export(exports_kick, {
|
|
6993
|
+
runKick: () => runKick,
|
|
6994
|
+
runDisconnect: () => runDisconnect
|
|
6976
6995
|
});
|
|
6977
|
-
function
|
|
6978
|
-
const
|
|
6979
|
-
|
|
6980
|
-
|
|
6981
|
-
|
|
6982
|
-
|
|
6983
|
-
|
|
6996
|
+
function parseStaleMs(input) {
|
|
6997
|
+
const m = input.match(/^(\d+)(s|m|h)$/);
|
|
6998
|
+
if (!m)
|
|
6999
|
+
return null;
|
|
7000
|
+
const val = parseInt(m[1], 10);
|
|
7001
|
+
const unit = m[2];
|
|
7002
|
+
if (unit === "s")
|
|
7003
|
+
return val * 1000;
|
|
7004
|
+
if (unit === "m")
|
|
7005
|
+
return val * 60000;
|
|
7006
|
+
if (unit === "h")
|
|
7007
|
+
return val * 3600000;
|
|
7008
|
+
return null;
|
|
6984
7009
|
}
|
|
6985
|
-
|
|
6986
|
-
|
|
6987
|
-
|
|
6988
|
-
|
|
6989
|
-
|
|
6990
|
-
|
|
6991
|
-
|
|
6992
|
-
|
|
6993
|
-
return dr.map((p) => annotateSelf(p, selfMemberPubkey, null));
|
|
6994
|
-
}
|
|
6995
|
-
} catch {}
|
|
6996
|
-
const bridged = await tryBridge(slug, "peers");
|
|
6997
|
-
if (bridged && bridged.ok) {
|
|
6998
|
-
const peers = bridged.result;
|
|
6999
|
-
return peers.map((p) => annotateSelf(p, selfMemberPubkey, null));
|
|
7010
|
+
function buildPayload(kind, target, opts) {
|
|
7011
|
+
if (opts.all)
|
|
7012
|
+
return { type: kind, all: true };
|
|
7013
|
+
if (opts.stale) {
|
|
7014
|
+
const ms = parseStaleMs(opts.stale);
|
|
7015
|
+
if (!ms)
|
|
7016
|
+
return { error: `Invalid stale duration: "${opts.stale}". Use e.g. 30m, 1h, 300s.` };
|
|
7017
|
+
return { type: kind, stale: ms };
|
|
7000
7018
|
}
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
const selfSessionPubkey = client.getSessionPubkey();
|
|
7005
|
-
result = all.map((p) => annotateSelf(p, selfMemberPubkey, selfSessionPubkey));
|
|
7006
|
-
});
|
|
7007
|
-
return result;
|
|
7008
|
-
}
|
|
7009
|
-
function annotateSelf(peer, selfMemberPubkey, selfSessionPubkey) {
|
|
7010
|
-
const isSelf = !!(selfMemberPubkey && peer.memberPubkey && peer.memberPubkey === selfMemberPubkey);
|
|
7011
|
-
const isThisSession = !!(isSelf && selfSessionPubkey && peer.pubkey === selfSessionPubkey);
|
|
7012
|
-
return { ...peer, isSelf, isThisSession };
|
|
7019
|
+
if (target)
|
|
7020
|
+
return { type: kind, target };
|
|
7021
|
+
return { error: `Usage: claudemesh ${kind} <peer> | --stale 30m | --all` };
|
|
7013
7022
|
}
|
|
7014
|
-
async function
|
|
7023
|
+
async function runDisconnect(target, opts = {}) {
|
|
7015
7024
|
const config = readConfig();
|
|
7016
|
-
const
|
|
7017
|
-
if (
|
|
7018
|
-
render.err("No
|
|
7019
|
-
|
|
7020
|
-
process.exit(1);
|
|
7025
|
+
const meshSlug = opts.mesh ?? config.meshes[0]?.slug;
|
|
7026
|
+
if (!meshSlug) {
|
|
7027
|
+
render.err("No mesh joined.");
|
|
7028
|
+
return EXIT.NOT_FOUND;
|
|
7021
7029
|
}
|
|
7022
|
-
const
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
|
|
7028
|
-
|
|
7029
|
-
|
|
7030
|
-
|
|
7031
|
-
|
|
7032
|
-
|
|
7033
|
-
render.
|
|
7034
|
-
|
|
7035
|
-
render.info(dim(" (no peers connected)"));
|
|
7036
|
-
continue;
|
|
7037
|
-
}
|
|
7038
|
-
for (const p of peers) {
|
|
7039
|
-
const groups = p.groups.length ? " [" + p.groups.map((g) => `@${g.name}${g.role ? `:${g.role}` : ""}`).join(", ") + "]" : "";
|
|
7040
|
-
const statusDot = p.status === "working" ? yellow("●") : green("●");
|
|
7041
|
-
const name = bold(p.displayName);
|
|
7042
|
-
const meta = [];
|
|
7043
|
-
if (p.peerType)
|
|
7044
|
-
meta.push(p.peerType);
|
|
7045
|
-
if (p.channel)
|
|
7046
|
-
meta.push(p.channel);
|
|
7047
|
-
if (p.model)
|
|
7048
|
-
meta.push(p.model);
|
|
7049
|
-
const metaStr = meta.length ? dim(` (${meta.join(", ")})`) : "";
|
|
7050
|
-
const summary = p.summary ? dim(` — ${p.summary}`) : "";
|
|
7051
|
-
const pubkeyTag = dim(` · ${p.pubkey.slice(0, 16)}…`);
|
|
7052
|
-
const selfTag = p.isThisSession ? dim(" ") + yellow("(this session)") : p.isSelf ? dim(" ") + yellow("(your other session)") : "";
|
|
7053
|
-
render.info(`${statusDot} ${name}${selfTag}${groups}${metaStr}${pubkeyTag}${summary}`);
|
|
7054
|
-
if (p.cwd)
|
|
7055
|
-
render.info(dim(` cwd: ${p.cwd}`));
|
|
7056
|
-
}
|
|
7057
|
-
} catch (e) {
|
|
7058
|
-
render.err(`${slug}: ${e instanceof Error ? e.message : String(e)}`);
|
|
7030
|
+
const built = buildPayload("disconnect", target, opts);
|
|
7031
|
+
if ("error" in built) {
|
|
7032
|
+
render.err(String(built.error));
|
|
7033
|
+
return EXIT.INVALID_ARGS;
|
|
7034
|
+
}
|
|
7035
|
+
return await withMesh({ meshSlug }, async (client) => {
|
|
7036
|
+
const result = await client.sendAndWait(built);
|
|
7037
|
+
const peers = result?.affected ?? result?.kicked ?? [];
|
|
7038
|
+
if (peers.length === 0)
|
|
7039
|
+
render.info("No peers matched.");
|
|
7040
|
+
else {
|
|
7041
|
+
render.ok(`Disconnected ${peers.length} peer(s): ${peers.join(", ")}`);
|
|
7042
|
+
render.hint("They will auto-reconnect within seconds. For a session-ending kick, use `claudemesh kick`.");
|
|
7059
7043
|
}
|
|
7044
|
+
return EXIT.SUCCESS;
|
|
7045
|
+
});
|
|
7046
|
+
}
|
|
7047
|
+
async function runKick(target, opts = {}) {
|
|
7048
|
+
const config = readConfig();
|
|
7049
|
+
const meshSlug = opts.mesh ?? config.meshes[0]?.slug;
|
|
7050
|
+
if (!meshSlug) {
|
|
7051
|
+
render.err("No mesh joined.");
|
|
7052
|
+
return EXIT.NOT_FOUND;
|
|
7060
7053
|
}
|
|
7061
|
-
|
|
7062
|
-
|
|
7063
|
-
|
|
7054
|
+
const built = buildPayload("kick", target, opts);
|
|
7055
|
+
if ("error" in built) {
|
|
7056
|
+
render.err(String(built.error));
|
|
7057
|
+
return EXIT.INVALID_ARGS;
|
|
7064
7058
|
}
|
|
7059
|
+
return await withMesh({ meshSlug }, async (client) => {
|
|
7060
|
+
const result = await client.sendAndWait(built);
|
|
7061
|
+
const peers = result?.affected ?? result?.kicked ?? [];
|
|
7062
|
+
if (peers.length === 0)
|
|
7063
|
+
render.info("No peers matched.");
|
|
7064
|
+
else {
|
|
7065
|
+
render.ok(`Kicked ${peers.length} peer(s): ${peers.join(", ")}`);
|
|
7066
|
+
render.hint("Their Claude Code session ended. They can rejoin anytime by running `claudemesh`.");
|
|
7067
|
+
}
|
|
7068
|
+
return EXIT.SUCCESS;
|
|
7069
|
+
});
|
|
7065
7070
|
}
|
|
7066
|
-
var
|
|
7067
|
-
var init_peers = __esm(() => {
|
|
7071
|
+
var init_kick = __esm(() => {
|
|
7068
7072
|
init_connect();
|
|
7069
7073
|
init_facade();
|
|
7070
|
-
init_client3();
|
|
7071
7074
|
init_render();
|
|
7072
|
-
|
|
7073
|
-
FIELD_ALIAS = {
|
|
7074
|
-
name: "displayName"
|
|
7075
|
-
};
|
|
7075
|
+
init_exit_codes();
|
|
7076
7076
|
});
|
|
7077
7077
|
|
|
7078
|
-
// src/commands/
|
|
7079
|
-
var
|
|
7080
|
-
__export(
|
|
7081
|
-
|
|
7078
|
+
// src/commands/ban.ts
|
|
7079
|
+
var exports_ban = {};
|
|
7080
|
+
__export(exports_ban, {
|
|
7081
|
+
runUnban: () => runUnban,
|
|
7082
|
+
runBans: () => runBans,
|
|
7083
|
+
runBan: () => runBan
|
|
7082
7084
|
});
|
|
7083
|
-
async function
|
|
7084
|
-
if (!
|
|
7085
|
-
render.err("Usage: claudemesh
|
|
7086
|
-
|
|
7085
|
+
async function runBan(target, opts = {}) {
|
|
7086
|
+
if (!target) {
|
|
7087
|
+
render.err("Usage: claudemesh ban <peer-name-or-pubkey>");
|
|
7088
|
+
return EXIT.INVALID_ARGS;
|
|
7087
7089
|
}
|
|
7088
|
-
const priority = flags.priority === "now" ? "now" : flags.priority === "low" ? "low" : "next";
|
|
7089
7090
|
const config = readConfig();
|
|
7090
|
-
const meshSlug =
|
|
7091
|
-
if (!
|
|
7092
|
-
|
|
7093
|
-
|
|
7094
|
-
render.err(`Target "${to.slice(0, 16)}…" is your own member pubkey on mesh "${meshSlug}".`);
|
|
7095
|
-
render.hint("Pass --self to message a sibling session of your own member, or pick a different peer's pubkey.");
|
|
7096
|
-
process.exit(1);
|
|
7097
|
-
}
|
|
7091
|
+
const meshSlug = opts.mesh ?? config.meshes[0]?.slug;
|
|
7092
|
+
if (!meshSlug) {
|
|
7093
|
+
render.err("No mesh joined.");
|
|
7094
|
+
return EXIT.NOT_FOUND;
|
|
7098
7095
|
}
|
|
7099
|
-
{
|
|
7100
|
-
const
|
|
7101
|
-
if (
|
|
7102
|
-
|
|
7103
|
-
|
|
7104
|
-
|
|
7105
|
-
|
|
7106
|
-
render.ok(`sent to ${to} (daemon)`, dr.messageId ? dim(dr.messageId.slice(0, 8)) : undefined);
|
|
7107
|
-
return;
|
|
7108
|
-
}
|
|
7109
|
-
if (flags.json)
|
|
7110
|
-
console.log(JSON.stringify({ ok: false, error: dr.error, via: "daemon" }));
|
|
7111
|
-
else
|
|
7112
|
-
render.err(`send failed (daemon): ${dr.error}`);
|
|
7113
|
-
process.exit(1);
|
|
7096
|
+
return await withMesh({ meshSlug }, async (client) => {
|
|
7097
|
+
const result = await client.sendAndWait({ type: "ban", target });
|
|
7098
|
+
if (result?.banned) {
|
|
7099
|
+
render.ok(`Banned ${result.banned} from ${meshSlug}. They cannot reconnect until unbanned.`);
|
|
7100
|
+
render.hint(`Undo: claudemesh unban ${result.banned} --mesh ${meshSlug}`);
|
|
7101
|
+
} else {
|
|
7102
|
+
render.err(result?.message ?? result?.error ?? result?.code ?? "ban failed");
|
|
7114
7103
|
}
|
|
7104
|
+
return result?.banned ? EXIT.SUCCESS : EXIT.INTERNAL_ERROR;
|
|
7105
|
+
});
|
|
7106
|
+
}
|
|
7107
|
+
async function runUnban(target, opts = {}) {
|
|
7108
|
+
if (!target) {
|
|
7109
|
+
render.err("Usage: claudemesh unban <peer-name-or-pubkey>");
|
|
7110
|
+
return EXIT.INVALID_ARGS;
|
|
7115
7111
|
}
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
7122
|
-
|
|
7123
|
-
|
|
7124
|
-
|
|
7125
|
-
|
|
7126
|
-
|
|
7127
|
-
|
|
7128
|
-
if (flags.json) {
|
|
7129
|
-
console.log(JSON.stringify({ ok: false, error: bridged.error }));
|
|
7130
|
-
} else {
|
|
7131
|
-
render.err(`send failed: ${bridged.error}`);
|
|
7132
|
-
}
|
|
7133
|
-
process.exit(1);
|
|
7112
|
+
const config = readConfig();
|
|
7113
|
+
const meshSlug = opts.mesh ?? config.meshes[0]?.slug;
|
|
7114
|
+
if (!meshSlug) {
|
|
7115
|
+
render.err("No mesh joined.");
|
|
7116
|
+
return EXIT.NOT_FOUND;
|
|
7117
|
+
}
|
|
7118
|
+
return await withMesh({ meshSlug }, async (client) => {
|
|
7119
|
+
const result = await client.sendAndWait({ type: "unban", target });
|
|
7120
|
+
if (result?.unbanned) {
|
|
7121
|
+
render.ok(`Unbanned ${result.unbanned} from ${meshSlug}. They can rejoin.`);
|
|
7122
|
+
} else {
|
|
7123
|
+
render.err(result?.message ?? result?.error ?? result?.code ?? "unban failed");
|
|
7134
7124
|
}
|
|
7125
|
+
return result?.unbanned ? EXIT.SUCCESS : EXIT.INTERNAL_ERROR;
|
|
7126
|
+
});
|
|
7127
|
+
}
|
|
7128
|
+
async function runBans(opts = {}) {
|
|
7129
|
+
const config = readConfig();
|
|
7130
|
+
const meshSlug = opts.mesh ?? config.meshes[0]?.slug;
|
|
7131
|
+
if (!meshSlug) {
|
|
7132
|
+
render.err("No mesh joined.");
|
|
7133
|
+
return EXIT.NOT_FOUND;
|
|
7135
7134
|
}
|
|
7136
|
-
await withMesh({ meshSlug
|
|
7137
|
-
|
|
7138
|
-
|
|
7139
|
-
|
|
7140
|
-
|
|
7141
|
-
|
|
7142
|
-
|
|
7143
|
-
const names = topics.map((t) => "#" + t.name).join(", ");
|
|
7144
|
-
render.err(`Topic "${to}" not found.`, `topics: ${names || "(none)"}`);
|
|
7145
|
-
process.exit(1);
|
|
7146
|
-
}
|
|
7147
|
-
targetSpec = "#" + match.id;
|
|
7148
|
-
} else if (!to.startsWith("@") && !to.startsWith("#") && to !== "*" && !/^[0-9a-f]{64}$/i.test(to)) {
|
|
7149
|
-
const peers = await client.listPeers();
|
|
7150
|
-
const match = peers.find((p) => p.displayName.toLowerCase() === to.toLowerCase());
|
|
7151
|
-
if (!match) {
|
|
7152
|
-
const names = peers.map((p) => p.displayName).join(", ");
|
|
7153
|
-
render.err(`Peer "${to}" not found.`, `online: ${names || "(none)"}`);
|
|
7154
|
-
process.exit(1);
|
|
7155
|
-
}
|
|
7156
|
-
targetSpec = match.pubkey;
|
|
7135
|
+
return await withMesh({ meshSlug }, async (client) => {
|
|
7136
|
+
const result = await client.sendAndWait({ type: "list_bans" });
|
|
7137
|
+
const bans = result?.bans ?? [];
|
|
7138
|
+
if (opts.json) {
|
|
7139
|
+
process.stdout.write(JSON.stringify(bans, null, 2) + `
|
|
7140
|
+
`);
|
|
7141
|
+
return EXIT.SUCCESS;
|
|
7157
7142
|
}
|
|
7158
|
-
|
|
7159
|
-
|
|
7160
|
-
|
|
7161
|
-
|
|
7162
|
-
|
|
7163
|
-
|
|
7143
|
+
if (bans.length === 0) {
|
|
7144
|
+
render.info("No banned members.");
|
|
7145
|
+
return EXIT.SUCCESS;
|
|
7146
|
+
}
|
|
7147
|
+
render.section(`banned members on ${meshSlug}`);
|
|
7148
|
+
for (const b of bans) {
|
|
7149
|
+
render.kv([[b.name, `${b.pubkey.slice(0, 16)}… · banned ${new Date(b.revokedAt).toLocaleDateString()}`]]);
|
|
7150
|
+
}
|
|
7151
|
+
return EXIT.SUCCESS;
|
|
7152
|
+
});
|
|
7153
|
+
}
|
|
7154
|
+
var init_ban = __esm(() => {
|
|
7155
|
+
init_connect();
|
|
7156
|
+
init_facade();
|
|
7157
|
+
init_render();
|
|
7158
|
+
init_exit_codes();
|
|
7159
|
+
});
|
|
7160
|
+
|
|
7161
|
+
// src/services/bridge/protocol.ts
|
|
7162
|
+
import { homedir as homedir5 } from "node:os";
|
|
7163
|
+
import { join as join6 } from "node:path";
|
|
7164
|
+
function socketPath(meshSlug) {
|
|
7165
|
+
return join6(homedir5(), ".claudemesh", "sockets", `${meshSlug}.sock`);
|
|
7166
|
+
}
|
|
7167
|
+
function frame(obj) {
|
|
7168
|
+
return JSON.stringify(obj) + `
|
|
7169
|
+
`;
|
|
7170
|
+
}
|
|
7171
|
+
|
|
7172
|
+
class LineParser {
|
|
7173
|
+
buf = "";
|
|
7174
|
+
feed(chunk) {
|
|
7175
|
+
this.buf += typeof chunk === "string" ? chunk : chunk.toString("utf-8");
|
|
7176
|
+
const lines = [];
|
|
7177
|
+
let nl = this.buf.indexOf(`
|
|
7178
|
+
`);
|
|
7179
|
+
while (nl !== -1) {
|
|
7180
|
+
lines.push(this.buf.slice(0, nl));
|
|
7181
|
+
this.buf = this.buf.slice(nl + 1);
|
|
7182
|
+
nl = this.buf.indexOf(`
|
|
7183
|
+
`);
|
|
7184
|
+
}
|
|
7185
|
+
return lines;
|
|
7186
|
+
}
|
|
7187
|
+
}
|
|
7188
|
+
var init_protocol = () => {};
|
|
7189
|
+
|
|
7190
|
+
// src/services/bridge/client.ts
|
|
7191
|
+
import { createConnection } from "node:net";
|
|
7192
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
7193
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
7194
|
+
async function tryBridge(meshSlug, verb, args = {}, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
7195
|
+
const path = socketPath(meshSlug);
|
|
7196
|
+
if (!existsSync6(path))
|
|
7197
|
+
return null;
|
|
7198
|
+
return new Promise((resolve) => {
|
|
7199
|
+
const id = randomUUID2();
|
|
7200
|
+
const req = { id, verb, args };
|
|
7201
|
+
const parser = new LineParser;
|
|
7202
|
+
let settled = false;
|
|
7203
|
+
const finish = (value) => {
|
|
7204
|
+
if (settled)
|
|
7205
|
+
return;
|
|
7206
|
+
settled = true;
|
|
7207
|
+
try {
|
|
7208
|
+
socket.destroy();
|
|
7209
|
+
} catch {}
|
|
7210
|
+
clearTimeout(timer);
|
|
7211
|
+
resolve(value);
|
|
7212
|
+
};
|
|
7213
|
+
const socket = createConnection({ path });
|
|
7214
|
+
const timer = setTimeout(() => {
|
|
7215
|
+
finish(null);
|
|
7216
|
+
}, timeoutMs);
|
|
7217
|
+
socket.on("connect", () => {
|
|
7218
|
+
try {
|
|
7219
|
+
socket.write(frame(req));
|
|
7220
|
+
} catch {
|
|
7221
|
+
finish(null);
|
|
7164
7222
|
}
|
|
7165
|
-
}
|
|
7166
|
-
|
|
7167
|
-
|
|
7223
|
+
});
|
|
7224
|
+
socket.on("data", (chunk) => {
|
|
7225
|
+
const lines = parser.feed(chunk);
|
|
7226
|
+
for (const line of lines) {
|
|
7227
|
+
if (!line.trim())
|
|
7228
|
+
continue;
|
|
7229
|
+
let res;
|
|
7230
|
+
try {
|
|
7231
|
+
res = JSON.parse(line);
|
|
7232
|
+
} catch {
|
|
7233
|
+
continue;
|
|
7234
|
+
}
|
|
7235
|
+
if (res.id !== id)
|
|
7236
|
+
continue;
|
|
7237
|
+
if (res.ok)
|
|
7238
|
+
finish({ ok: true, result: res.result });
|
|
7239
|
+
else
|
|
7240
|
+
finish({ ok: false, error: res.error });
|
|
7241
|
+
return;
|
|
7242
|
+
}
|
|
7243
|
+
});
|
|
7244
|
+
socket.on("error", (err) => {
|
|
7245
|
+
const code = err.code;
|
|
7246
|
+
if (code === "ECONNREFUSED" || code === "ENOENT" || code === "EPERM") {
|
|
7247
|
+
finish(null);
|
|
7168
7248
|
} else {
|
|
7169
|
-
|
|
7249
|
+
finish(null);
|
|
7170
7250
|
}
|
|
7171
|
-
|
|
7172
|
-
|
|
7251
|
+
});
|
|
7252
|
+
socket.on("close", () => {
|
|
7253
|
+
finish(null);
|
|
7254
|
+
});
|
|
7173
7255
|
});
|
|
7174
7256
|
}
|
|
7175
|
-
var
|
|
7176
|
-
|
|
7177
|
-
|
|
7178
|
-
init_client3();
|
|
7179
|
-
init_daemon_route();
|
|
7180
|
-
init_render();
|
|
7181
|
-
init_styles();
|
|
7257
|
+
var DEFAULT_TIMEOUT_MS = 5000;
|
|
7258
|
+
var init_client3 = __esm(() => {
|
|
7259
|
+
init_protocol();
|
|
7182
7260
|
});
|
|
7183
7261
|
|
|
7184
|
-
// src/
|
|
7185
|
-
|
|
7186
|
-
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
|
|
7190
|
-
|
|
7191
|
-
|
|
7192
|
-
|
|
7193
|
-
|
|
7194
|
-
return ` ${bold(from)} ${dim(`[${kindTag}] ${time}`)}
|
|
7195
|
-
${text}`;
|
|
7262
|
+
// src/daemon/local-token.ts
|
|
7263
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync6 } from "node:fs";
|
|
7264
|
+
import { dirname as dirname3 } from "node:path";
|
|
7265
|
+
import { randomBytes as randomBytes4 } from "node:crypto";
|
|
7266
|
+
function readLocalToken() {
|
|
7267
|
+
try {
|
|
7268
|
+
return readFileSync5(DAEMON_PATHS.TOKEN_FILE, "utf8").trim();
|
|
7269
|
+
} catch {
|
|
7270
|
+
return null;
|
|
7271
|
+
}
|
|
7196
7272
|
}
|
|
7197
|
-
|
|
7198
|
-
const
|
|
7199
|
-
|
|
7200
|
-
|
|
7201
|
-
|
|
7202
|
-
|
|
7203
|
-
|
|
7204
|
-
|
|
7205
|
-
|
|
7206
|
-
|
|
7207
|
-
|
|
7208
|
-
|
|
7209
|
-
|
|
7210
|
-
}
|
|
7211
|
-
render.section(`inbox — ${mesh.slug} (${messages.length} message${messages.length === 1 ? "" : "s"})`);
|
|
7212
|
-
for (const msg of messages) {
|
|
7213
|
-
process.stdout.write(formatMessage(msg) + `
|
|
7273
|
+
function ensureLocalToken() {
|
|
7274
|
+
const existing = readLocalToken();
|
|
7275
|
+
if (existing)
|
|
7276
|
+
return existing;
|
|
7277
|
+
mkdirSync4(dirname3(DAEMON_PATHS.TOKEN_FILE), { recursive: true, mode: 448 });
|
|
7278
|
+
const tok = randomBytes4(32).toString("base64url");
|
|
7279
|
+
writeFileSync6(DAEMON_PATHS.TOKEN_FILE, tok + `
|
|
7280
|
+
`, { mode: 384 });
|
|
7281
|
+
return tok;
|
|
7282
|
+
}
|
|
7283
|
+
var init_local_token = __esm(() => {
|
|
7284
|
+
init_paths2();
|
|
7285
|
+
});
|
|
7214
7286
|
|
|
7215
|
-
|
|
7216
|
-
|
|
7287
|
+
// src/daemon/ipc/client.ts
|
|
7288
|
+
import { request as httpRequest } from "node:http";
|
|
7289
|
+
async function ipc(opts) {
|
|
7290
|
+
const useTcp = !!opts.preferTcp;
|
|
7291
|
+
const headers = {
|
|
7292
|
+
accept: "application/json",
|
|
7293
|
+
host: "localhost"
|
|
7294
|
+
};
|
|
7295
|
+
let bodyBuf;
|
|
7296
|
+
if (opts.body !== undefined) {
|
|
7297
|
+
bodyBuf = Buffer.from(JSON.stringify(opts.body), "utf8");
|
|
7298
|
+
headers["content-type"] = "application/json";
|
|
7299
|
+
headers["content-length"] = String(bodyBuf.length);
|
|
7300
|
+
}
|
|
7301
|
+
if (useTcp) {
|
|
7302
|
+
const tok = readLocalToken();
|
|
7303
|
+
if (!tok)
|
|
7304
|
+
throw new IpcError(0, null, "daemon local token not found; is the daemon running?");
|
|
7305
|
+
headers.authorization = `Bearer ${tok}`;
|
|
7306
|
+
}
|
|
7307
|
+
return new Promise((resolve, reject) => {
|
|
7308
|
+
const req = httpRequest(useTcp ? { host: DAEMON_TCP_HOST, port: DAEMON_TCP_DEFAULT_PORT, path: opts.path, method: opts.method ?? "GET", headers } : { socketPath: DAEMON_PATHS.SOCK_FILE, path: opts.path, method: opts.method ?? "GET", headers }, (res) => {
|
|
7309
|
+
const chunks = [];
|
|
7310
|
+
res.on("data", (c) => chunks.push(c));
|
|
7311
|
+
res.on("end", () => {
|
|
7312
|
+
const raw = Buffer.concat(chunks).toString("utf8");
|
|
7313
|
+
let parsed = raw;
|
|
7314
|
+
try {
|
|
7315
|
+
parsed = raw.length > 0 ? JSON.parse(raw) : null;
|
|
7316
|
+
} catch {}
|
|
7317
|
+
resolve({ status: res.statusCode ?? 0, body: parsed });
|
|
7318
|
+
});
|
|
7319
|
+
});
|
|
7320
|
+
req.setTimeout(opts.timeoutMs ?? 5000, () => req.destroy(new Error("ipc_timeout")));
|
|
7321
|
+
req.on("error", (err) => reject(err));
|
|
7322
|
+
if (bodyBuf)
|
|
7323
|
+
req.write(bodyBuf);
|
|
7324
|
+
req.end();
|
|
7217
7325
|
});
|
|
7218
7326
|
}
|
|
7219
|
-
var
|
|
7220
|
-
|
|
7221
|
-
|
|
7222
|
-
|
|
7327
|
+
var IpcError;
|
|
7328
|
+
var init_client4 = __esm(() => {
|
|
7329
|
+
init_paths2();
|
|
7330
|
+
init_local_token();
|
|
7331
|
+
IpcError = class IpcError extends Error {
|
|
7332
|
+
status;
|
|
7333
|
+
payload;
|
|
7334
|
+
constructor(status, payload, msg) {
|
|
7335
|
+
super(msg);
|
|
7336
|
+
this.status = status;
|
|
7337
|
+
this.payload = payload;
|
|
7338
|
+
}
|
|
7339
|
+
};
|
|
7223
7340
|
});
|
|
7224
7341
|
|
|
7225
|
-
// src/
|
|
7226
|
-
var
|
|
7227
|
-
__export(
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
|
|
7342
|
+
// src/services/bridge/daemon-route.ts
|
|
7343
|
+
var exports_daemon_route = {};
|
|
7344
|
+
__export(exports_daemon_route, {
|
|
7345
|
+
trySetStateViaDaemon: () => trySetStateViaDaemon,
|
|
7346
|
+
trySendViaDaemon: () => trySendViaDaemon,
|
|
7347
|
+
tryRememberViaDaemon: () => tryRememberViaDaemon,
|
|
7348
|
+
tryRecallViaDaemon: () => tryRecallViaDaemon,
|
|
7349
|
+
tryListStateViaDaemon: () => tryListStateViaDaemon,
|
|
7350
|
+
tryListSkillsViaDaemon: () => tryListSkillsViaDaemon,
|
|
7351
|
+
tryListPeersViaDaemon: () => tryListPeersViaDaemon,
|
|
7352
|
+
tryGetStateViaDaemon: () => tryGetStateViaDaemon,
|
|
7353
|
+
tryGetSkillViaDaemon: () => tryGetSkillViaDaemon,
|
|
7354
|
+
tryForgetViaDaemon: () => tryForgetViaDaemon
|
|
7231
7355
|
});
|
|
7232
|
-
|
|
7233
|
-
|
|
7234
|
-
|
|
7235
|
-
|
|
7236
|
-
|
|
7237
|
-
|
|
7238
|
-
|
|
7239
|
-
|
|
7240
|
-
|
|
7356
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
7357
|
+
function meshQuery(mesh) {
|
|
7358
|
+
return mesh ? `?mesh=${encodeURIComponent(mesh)}` : "";
|
|
7359
|
+
}
|
|
7360
|
+
async function tryListPeersViaDaemon(mesh) {
|
|
7361
|
+
if (!existsSync7(DAEMON_PATHS.SOCK_FILE))
|
|
7362
|
+
return null;
|
|
7363
|
+
try {
|
|
7364
|
+
const res = await ipc({ path: `/v1/peers${meshQuery(mesh)}`, timeoutMs: 3000 });
|
|
7365
|
+
if (res.status !== 200)
|
|
7366
|
+
return null;
|
|
7367
|
+
return Array.isArray(res.body.peers) ? res.body.peers : [];
|
|
7368
|
+
} catch (err) {
|
|
7369
|
+
const msg = String(err);
|
|
7370
|
+
if (/ENOENT|ECONNREFUSED|ipc_timeout/.test(msg))
|
|
7371
|
+
return null;
|
|
7372
|
+
return null;
|
|
7373
|
+
}
|
|
7374
|
+
}
|
|
7375
|
+
async function tryListSkillsViaDaemon(mesh) {
|
|
7376
|
+
if (!existsSync7(DAEMON_PATHS.SOCK_FILE))
|
|
7377
|
+
return null;
|
|
7378
|
+
try {
|
|
7379
|
+
const res = await ipc({ path: `/v1/skills${meshQuery(mesh)}`, timeoutMs: 3000 });
|
|
7380
|
+
if (res.status !== 200)
|
|
7381
|
+
return null;
|
|
7382
|
+
return Array.isArray(res.body.skills) ? res.body.skills : [];
|
|
7383
|
+
} catch (err) {
|
|
7384
|
+
const msg = String(err);
|
|
7385
|
+
if (/ENOENT|ECONNREFUSED|ipc_timeout/.test(msg))
|
|
7386
|
+
return null;
|
|
7387
|
+
return null;
|
|
7388
|
+
}
|
|
7389
|
+
}
|
|
7390
|
+
async function tryGetSkillViaDaemon(name, mesh) {
|
|
7391
|
+
if (!existsSync7(DAEMON_PATHS.SOCK_FILE))
|
|
7392
|
+
return null;
|
|
7393
|
+
try {
|
|
7394
|
+
const res = await ipc({
|
|
7395
|
+
path: `/v1/skills/${encodeURIComponent(name)}${meshQuery(mesh)}`,
|
|
7396
|
+
timeoutMs: 3000
|
|
7397
|
+
});
|
|
7398
|
+
if (res.status === 404)
|
|
7399
|
+
return null;
|
|
7400
|
+
if (res.status !== 200)
|
|
7401
|
+
return null;
|
|
7402
|
+
return res.body.skill ?? null;
|
|
7403
|
+
} catch {
|
|
7404
|
+
return null;
|
|
7405
|
+
}
|
|
7406
|
+
}
|
|
7407
|
+
async function tryGetStateViaDaemon(key, mesh) {
|
|
7408
|
+
if (!existsSync7(DAEMON_PATHS.SOCK_FILE))
|
|
7409
|
+
return null;
|
|
7410
|
+
try {
|
|
7411
|
+
const path = `/v1/state?key=${encodeURIComponent(key)}${mesh ? `&mesh=${encodeURIComponent(mesh)}` : ""}`;
|
|
7412
|
+
const res = await ipc({ path, timeoutMs: 3000 });
|
|
7413
|
+
if (res.status === 404)
|
|
7241
7414
|
return;
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
|
|
7415
|
+
if (res.status !== 200)
|
|
7416
|
+
return null;
|
|
7417
|
+
return res.body.state ?? undefined;
|
|
7418
|
+
} catch (err) {
|
|
7419
|
+
const msg = String(err);
|
|
7420
|
+
if (/ENOENT|ECONNREFUSED|ipc_timeout/.test(msg))
|
|
7421
|
+
return null;
|
|
7422
|
+
return null;
|
|
7423
|
+
}
|
|
7424
|
+
}
|
|
7425
|
+
async function tryListStateViaDaemon(mesh) {
|
|
7426
|
+
if (!existsSync7(DAEMON_PATHS.SOCK_FILE))
|
|
7427
|
+
return null;
|
|
7428
|
+
try {
|
|
7429
|
+
const res = await ipc({ path: `/v1/state${meshQuery(mesh)}`, timeoutMs: 3000 });
|
|
7430
|
+
if (res.status !== 200)
|
|
7431
|
+
return null;
|
|
7432
|
+
return Array.isArray(res.body.entries) ? res.body.entries : [];
|
|
7433
|
+
} catch (err) {
|
|
7434
|
+
const msg = String(err);
|
|
7435
|
+
if (/ENOENT|ECONNREFUSED|ipc_timeout/.test(msg))
|
|
7436
|
+
return null;
|
|
7437
|
+
return null;
|
|
7438
|
+
}
|
|
7439
|
+
}
|
|
7440
|
+
async function trySetStateViaDaemon(key, value, mesh) {
|
|
7441
|
+
if (!existsSync7(DAEMON_PATHS.SOCK_FILE))
|
|
7442
|
+
return false;
|
|
7443
|
+
try {
|
|
7444
|
+
const res = await ipc({
|
|
7445
|
+
method: "POST",
|
|
7446
|
+
path: "/v1/state",
|
|
7447
|
+
timeoutMs: 3000,
|
|
7448
|
+
body: { key, value, ...mesh ? { mesh } : {} }
|
|
7449
|
+
});
|
|
7450
|
+
return res.status === 200 && res.body.ok === true;
|
|
7451
|
+
} catch {
|
|
7452
|
+
return false;
|
|
7453
|
+
}
|
|
7247
7454
|
}
|
|
7248
|
-
async function
|
|
7249
|
-
|
|
7455
|
+
async function tryRememberViaDaemon(content, tags, mesh) {
|
|
7456
|
+
if (!existsSync7(DAEMON_PATHS.SOCK_FILE))
|
|
7457
|
+
return null;
|
|
7250
7458
|
try {
|
|
7251
|
-
|
|
7459
|
+
const res = await ipc({
|
|
7460
|
+
method: "POST",
|
|
7461
|
+
path: "/v1/memory",
|
|
7462
|
+
timeoutMs: 5000,
|
|
7463
|
+
body: { content, ...tags?.length ? { tags } : {}, ...mesh ? { mesh } : {} }
|
|
7464
|
+
});
|
|
7465
|
+
if (res.status !== 200 || !res.body.id)
|
|
7466
|
+
return null;
|
|
7467
|
+
return { id: res.body.id, mesh: res.body.mesh };
|
|
7252
7468
|
} catch {
|
|
7253
|
-
|
|
7469
|
+
return null;
|
|
7254
7470
|
}
|
|
7255
|
-
await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
7256
|
-
await client.setState(key, parsed);
|
|
7257
|
-
render.ok(`${bold(key)} = ${JSON.stringify(parsed)}`);
|
|
7258
|
-
});
|
|
7259
7471
|
}
|
|
7260
|
-
async function
|
|
7261
|
-
|
|
7262
|
-
|
|
7263
|
-
|
|
7264
|
-
|
|
7265
|
-
|
|
7266
|
-
|
|
7267
|
-
|
|
7268
|
-
|
|
7269
|
-
|
|
7270
|
-
|
|
7271
|
-
|
|
7272
|
-
|
|
7273
|
-
|
|
7274
|
-
|
|
7275
|
-
`);
|
|
7276
|
-
process.stdout.write(` ${dim(e.updatedBy + " · " + new Date(e.updatedAt).toLocaleString())}
|
|
7277
|
-
`);
|
|
7278
|
-
}
|
|
7279
|
-
});
|
|
7472
|
+
async function tryRecallViaDaemon(query, mesh) {
|
|
7473
|
+
if (!existsSync7(DAEMON_PATHS.SOCK_FILE))
|
|
7474
|
+
return null;
|
|
7475
|
+
try {
|
|
7476
|
+
const path = `/v1/memory?q=${encodeURIComponent(query)}${mesh ? `&mesh=${encodeURIComponent(mesh)}` : ""}`;
|
|
7477
|
+
const res = await ipc({ path, timeoutMs: 5000 });
|
|
7478
|
+
if (res.status !== 200)
|
|
7479
|
+
return null;
|
|
7480
|
+
return Array.isArray(res.body.matches) ? res.body.matches : [];
|
|
7481
|
+
} catch (err) {
|
|
7482
|
+
const msg = String(err);
|
|
7483
|
+
if (/ENOENT|ECONNREFUSED|ipc_timeout/.test(msg))
|
|
7484
|
+
return null;
|
|
7485
|
+
return null;
|
|
7486
|
+
}
|
|
7280
7487
|
}
|
|
7281
|
-
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
})
|
|
7286
|
-
|
|
7287
|
-
|
|
7288
|
-
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
|
|
7292
|
-
|
|
7293
|
-
|
|
7294
|
-
|
|
7488
|
+
async function tryForgetViaDaemon(id, mesh) {
|
|
7489
|
+
if (!existsSync7(DAEMON_PATHS.SOCK_FILE))
|
|
7490
|
+
return false;
|
|
7491
|
+
try {
|
|
7492
|
+
const path = `/v1/memory/${encodeURIComponent(id)}${meshQuery(mesh)}`;
|
|
7493
|
+
const res = await ipc({ method: "DELETE", path, timeoutMs: 3000 });
|
|
7494
|
+
return res.status === 200 && res.body.ok === true;
|
|
7495
|
+
} catch {
|
|
7496
|
+
return false;
|
|
7497
|
+
}
|
|
7498
|
+
}
|
|
7499
|
+
async function trySendViaDaemon(args) {
|
|
7500
|
+
if (!existsSync7(DAEMON_PATHS.SOCK_FILE))
|
|
7501
|
+
return null;
|
|
7502
|
+
try {
|
|
7503
|
+
const res = await ipc({
|
|
7504
|
+
method: "POST",
|
|
7505
|
+
path: "/v1/send",
|
|
7506
|
+
timeoutMs: 3000,
|
|
7507
|
+
body: {
|
|
7508
|
+
to: args.to,
|
|
7509
|
+
message: args.message,
|
|
7510
|
+
priority: args.priority,
|
|
7511
|
+
...args.idempotencyKey ? { client_message_id: args.idempotencyKey } : {},
|
|
7512
|
+
...args.expectedMesh ? { mesh: args.expectedMesh } : {}
|
|
7513
|
+
}
|
|
7295
7514
|
});
|
|
7296
|
-
if (
|
|
7297
|
-
|
|
7298
|
-
|
|
7299
|
-
|
|
7300
|
-
|
|
7301
|
-
|
|
7302
|
-
|
|
7303
|
-
meshSlug: mesh.slug,
|
|
7304
|
-
client,
|
|
7305
|
-
mesh
|
|
7306
|
-
});
|
|
7307
|
-
} finally {
|
|
7308
|
-
try {
|
|
7309
|
-
await client.apiKeyRevoke(result.id);
|
|
7310
|
-
} catch {}
|
|
7515
|
+
if (res.status === 202 || res.status === 200) {
|
|
7516
|
+
return {
|
|
7517
|
+
ok: true,
|
|
7518
|
+
messageId: res.body.broker_message_id ?? res.body.client_message_id ?? "",
|
|
7519
|
+
duplicate: res.body.duplicate,
|
|
7520
|
+
status: res.body.status
|
|
7521
|
+
};
|
|
7311
7522
|
}
|
|
7312
|
-
|
|
7523
|
+
return { ok: false, error: res.body.error ?? `daemon http ${res.status}` };
|
|
7524
|
+
} catch (err) {
|
|
7525
|
+
const msg = String(err);
|
|
7526
|
+
if (/ENOENT|ECONNREFUSED|ipc_timeout/.test(msg))
|
|
7527
|
+
return null;
|
|
7528
|
+
return { ok: false, error: msg };
|
|
7529
|
+
}
|
|
7313
7530
|
}
|
|
7314
|
-
var
|
|
7315
|
-
|
|
7531
|
+
var init_daemon_route = __esm(() => {
|
|
7532
|
+
init_client4();
|
|
7533
|
+
init_paths2();
|
|
7316
7534
|
});
|
|
7317
7535
|
|
|
7318
|
-
// src/commands/
|
|
7319
|
-
var
|
|
7320
|
-
__export(
|
|
7321
|
-
|
|
7322
|
-
runMeTasks: () => runMeTasks,
|
|
7323
|
-
runMeState: () => runMeState,
|
|
7324
|
-
runMeSearch: () => runMeSearch,
|
|
7325
|
-
runMeNotifications: () => runMeNotifications,
|
|
7326
|
-
runMeMemory: () => runMeMemory,
|
|
7327
|
-
runMeActivity: () => runMeActivity,
|
|
7328
|
-
runMe: () => runMe
|
|
7536
|
+
// src/commands/peers.ts
|
|
7537
|
+
var exports_peers = {};
|
|
7538
|
+
__export(exports_peers, {
|
|
7539
|
+
runPeers: () => runPeers
|
|
7329
7540
|
});
|
|
7330
|
-
function
|
|
7331
|
-
|
|
7332
|
-
|
|
7333
|
-
|
|
7334
|
-
|
|
7335
|
-
}
|
|
7336
|
-
|
|
7337
|
-
|
|
7338
|
-
|
|
7339
|
-
|
|
7340
|
-
|
|
7341
|
-
|
|
7342
|
-
|
|
7343
|
-
|
|
7344
|
-
|
|
7345
|
-
|
|
7346
|
-
|
|
7347
|
-
console.log(JSON.stringify(ws, null, 2));
|
|
7348
|
-
return EXIT.SUCCESS;
|
|
7349
|
-
}
|
|
7350
|
-
render.section(`${clay("workspace")} — ${bold(ws.userId.slice(0, 8))} ${dim(`· ${ws.totals.meshes} mesh${ws.totals.meshes === 1 ? "" : "es"}`)}`);
|
|
7351
|
-
const totalsLine = [
|
|
7352
|
-
`${green(String(ws.totals.online))}/${ws.totals.peers} online`,
|
|
7353
|
-
`${ws.totals.topics} topic${ws.totals.topics === 1 ? "" : "s"}`,
|
|
7354
|
-
ws.totals.unreadMentions > 0 ? yellow(`${ws.totals.unreadMentions} unread @you`) : dim("0 unread @you")
|
|
7355
|
-
].join(dim(" · "));
|
|
7356
|
-
process.stdout.write(" " + totalsLine + `
|
|
7357
|
-
|
|
7358
|
-
`);
|
|
7359
|
-
if (ws.meshes.length === 0) {
|
|
7360
|
-
process.stdout.write(dim(" no meshes joined — run `claudemesh new` or accept an invite\n"));
|
|
7361
|
-
return EXIT.SUCCESS;
|
|
7362
|
-
}
|
|
7363
|
-
const slugWidth = Math.max(...ws.meshes.map((m) => m.slug.length), 8);
|
|
7364
|
-
for (const m of ws.meshes) {
|
|
7365
|
-
const slug = cyan(m.slug.padEnd(slugWidth));
|
|
7366
|
-
const peers = `${m.online}/${m.peers}`;
|
|
7367
|
-
const role = dim(m.myRole);
|
|
7368
|
-
const unread = m.unreadMentions > 0 ? " " + yellow(`${m.unreadMentions} @you`) : "";
|
|
7369
|
-
process.stdout.write(` ${slug} ${peers.padStart(5)} online ${dim(String(m.topics).padStart(2) + " topics")} ${role}${unread}
|
|
7370
|
-
`);
|
|
7371
|
-
}
|
|
7372
|
-
return EXIT.SUCCESS;
|
|
7373
|
-
});
|
|
7374
|
-
}
|
|
7375
|
-
async function runMeTopics(flags) {
|
|
7376
|
-
return withRestKey({
|
|
7377
|
-
meshSlug: resolveMeshForMint(flags.mesh),
|
|
7378
|
-
purpose: "workspace-topics",
|
|
7379
|
-
capabilities: ["read"]
|
|
7380
|
-
}, async ({ secret }) => {
|
|
7381
|
-
const ws = await request({
|
|
7382
|
-
path: "/api/v1/me/topics",
|
|
7383
|
-
token: secret
|
|
7384
|
-
});
|
|
7385
|
-
const visible = flags.unread ? ws.topics.filter((t) => t.unread > 0) : ws.topics;
|
|
7386
|
-
if (flags.json) {
|
|
7387
|
-
console.log(JSON.stringify({ topics: visible, totals: ws.totals }, null, 2));
|
|
7388
|
-
return EXIT.SUCCESS;
|
|
7389
|
-
}
|
|
7390
|
-
render.section(`${clay("topics")} — ${ws.totals.topics} across all meshes ${dim(ws.totals.unread > 0 ? `· ${ws.totals.unread} unread` : "· all read")}`);
|
|
7391
|
-
if (visible.length === 0) {
|
|
7392
|
-
process.stdout.write(dim(flags.unread ? ` no unread topics
|
|
7393
|
-
` : " no topics — run `claudemesh topic create #general`\n"));
|
|
7394
|
-
return EXIT.SUCCESS;
|
|
7395
|
-
}
|
|
7396
|
-
const slugWidth = Math.max(...visible.map((t) => t.meshSlug.length), 6);
|
|
7397
|
-
const nameWidth = Math.max(...visible.map((t) => t.name.length), 8);
|
|
7398
|
-
for (const t of visible) {
|
|
7399
|
-
const slug = dim(t.meshSlug.padEnd(slugWidth));
|
|
7400
|
-
const name = cyan(t.name.padEnd(nameWidth));
|
|
7401
|
-
const unread = t.unread > 0 ? yellow(`${t.unread} unread`.padStart(10)) : dim("·".padStart(10));
|
|
7402
|
-
const last = t.lastMessageAt ? dim(formatRelativeTime(t.lastMessageAt)) : dim("never");
|
|
7403
|
-
process.stdout.write(` ${slug} ${name} ${unread} ${last}
|
|
7404
|
-
`);
|
|
7405
|
-
}
|
|
7406
|
-
return EXIT.SUCCESS;
|
|
7407
|
-
});
|
|
7408
|
-
}
|
|
7409
|
-
async function runMeNotifications(flags) {
|
|
7410
|
-
return withRestKey({
|
|
7411
|
-
meshSlug: resolveMeshForMint(flags.mesh),
|
|
7412
|
-
purpose: "workspace-notifications",
|
|
7413
|
-
capabilities: ["read"]
|
|
7414
|
-
}, async ({ secret }) => {
|
|
7415
|
-
const params = new URLSearchParams;
|
|
7416
|
-
if (flags.all)
|
|
7417
|
-
params.set("include", "all");
|
|
7418
|
-
if (flags.since)
|
|
7419
|
-
params.set("since", flags.since);
|
|
7420
|
-
const path = "/api/v1/me/notifications" + (params.toString() ? `?${params.toString()}` : "");
|
|
7421
|
-
const ws = await request({
|
|
7422
|
-
path,
|
|
7423
|
-
token: secret
|
|
7424
|
-
});
|
|
7425
|
-
if (flags.json) {
|
|
7426
|
-
console.log(JSON.stringify(ws, null, 2));
|
|
7427
|
-
return EXIT.SUCCESS;
|
|
7428
|
-
}
|
|
7429
|
-
const headerLabel = flags.all ? "@-mentions (all)" : "@-mentions (unread)";
|
|
7430
|
-
render.section(`${clay(headerLabel)} — ${ws.totals.total} ${dim(ws.totals.unread > 0 ? `· ${ws.totals.unread} unread` : "· nothing pending")}`);
|
|
7431
|
-
if (ws.notifications.length === 0) {
|
|
7432
|
-
process.stdout.write(dim(flags.all ? ` no @-mentions in window
|
|
7433
|
-
` : ` inbox zero — nothing waiting
|
|
7434
|
-
`));
|
|
7435
|
-
return EXIT.SUCCESS;
|
|
7436
|
-
}
|
|
7437
|
-
const slugWidth = Math.max(...ws.notifications.map((n) => n.meshSlug.length), 6);
|
|
7438
|
-
for (const n of ws.notifications) {
|
|
7439
|
-
const slug = dim(n.meshSlug.padEnd(slugWidth));
|
|
7440
|
-
const topic = cyan(`#${n.topicName}`);
|
|
7441
|
-
const sender = n.senderName ? `from ${n.senderName}` : "from ?";
|
|
7442
|
-
const ago = formatRelativeTime(n.createdAt);
|
|
7443
|
-
const dot = n.read ? dim("·") : yellow("●");
|
|
7444
|
-
const snippet = n.snippet ?? (n.ciphertext ? dim("[encrypted]") : dim("[empty]"));
|
|
7445
|
-
process.stdout.write(` ${dot} ${slug} ${topic} ${dim(sender)} ${dim(ago)}
|
|
7446
|
-
` + ` ${snippet.length > 200 ? snippet.slice(0, 200) + "…" : snippet}
|
|
7447
|
-
`);
|
|
7541
|
+
function projectFields(record, fields) {
|
|
7542
|
+
const out = {};
|
|
7543
|
+
for (const f of fields) {
|
|
7544
|
+
const sourceKey = FIELD_ALIAS[f] ?? f;
|
|
7545
|
+
out[f] = record[sourceKey];
|
|
7546
|
+
}
|
|
7547
|
+
return out;
|
|
7548
|
+
}
|
|
7549
|
+
async function listPeersForMesh(slug) {
|
|
7550
|
+
const config = readConfig();
|
|
7551
|
+
const joined = config.meshes.find((m) => m.slug === slug);
|
|
7552
|
+
const selfMemberPubkey = joined?.pubkey ?? null;
|
|
7553
|
+
try {
|
|
7554
|
+
const { tryListPeersViaDaemon: tryListPeersViaDaemon2 } = await Promise.resolve().then(() => (init_daemon_route(), exports_daemon_route));
|
|
7555
|
+
const dr = await tryListPeersViaDaemon2();
|
|
7556
|
+
if (dr !== null) {
|
|
7557
|
+
return dr.map((p) => annotateSelf(p, selfMemberPubkey, null));
|
|
7448
7558
|
}
|
|
7449
|
-
|
|
7559
|
+
} catch {}
|
|
7560
|
+
const bridged = await tryBridge(slug, "peers");
|
|
7561
|
+
if (bridged && bridged.ok) {
|
|
7562
|
+
const peers = bridged.result;
|
|
7563
|
+
return peers.map((p) => annotateSelf(p, selfMemberPubkey, null));
|
|
7564
|
+
}
|
|
7565
|
+
let result = [];
|
|
7566
|
+
await withMesh({ meshSlug: slug }, async (client) => {
|
|
7567
|
+
const all = await client.listPeers();
|
|
7568
|
+
const selfSessionPubkey = client.getSessionPubkey();
|
|
7569
|
+
result = all.map((p) => annotateSelf(p, selfMemberPubkey, selfSessionPubkey));
|
|
7450
7570
|
});
|
|
7571
|
+
return result;
|
|
7451
7572
|
}
|
|
7452
|
-
|
|
7453
|
-
|
|
7454
|
-
|
|
7455
|
-
|
|
7456
|
-
|
|
7457
|
-
|
|
7458
|
-
|
|
7459
|
-
|
|
7460
|
-
|
|
7461
|
-
|
|
7462
|
-
|
|
7463
|
-
|
|
7464
|
-
|
|
7465
|
-
|
|
7466
|
-
|
|
7467
|
-
|
|
7468
|
-
|
|
7469
|
-
|
|
7470
|
-
|
|
7471
|
-
|
|
7472
|
-
|
|
7473
|
-
|
|
7474
|
-
|
|
7573
|
+
function annotateSelf(peer, selfMemberPubkey, selfSessionPubkey) {
|
|
7574
|
+
const isSelf = !!(selfMemberPubkey && peer.memberPubkey && peer.memberPubkey === selfMemberPubkey);
|
|
7575
|
+
const isThisSession = !!(isSelf && selfSessionPubkey && peer.pubkey === selfSessionPubkey);
|
|
7576
|
+
return { ...peer, isSelf, isThisSession };
|
|
7577
|
+
}
|
|
7578
|
+
async function runPeers(flags) {
|
|
7579
|
+
const config = readConfig();
|
|
7580
|
+
const slugs = flags.mesh ? [flags.mesh] : config.meshes.map((m) => m.slug);
|
|
7581
|
+
if (slugs.length === 0) {
|
|
7582
|
+
render.err("No meshes joined.");
|
|
7583
|
+
render.hint("claudemesh <invite-url> # join + launch");
|
|
7584
|
+
process.exit(1);
|
|
7585
|
+
}
|
|
7586
|
+
const fieldList = typeof flags.json === "string" && flags.json.length > 0 ? flags.json.split(",").map((s) => s.trim()).filter(Boolean) : null;
|
|
7587
|
+
const wantsJson = flags.json !== undefined && flags.json !== false;
|
|
7588
|
+
const allJson = [];
|
|
7589
|
+
for (const slug of slugs) {
|
|
7590
|
+
try {
|
|
7591
|
+
const peers = await listPeersForMesh(slug);
|
|
7592
|
+
if (wantsJson) {
|
|
7593
|
+
const projected = fieldList ? peers.map((p) => projectFields(p, fieldList)) : peers;
|
|
7594
|
+
allJson.push({ mesh: slug, peers: projected });
|
|
7595
|
+
continue;
|
|
7596
|
+
}
|
|
7597
|
+
render.section(`peers on ${slug} (${peers.length})`);
|
|
7598
|
+
if (peers.length === 0) {
|
|
7599
|
+
render.info(dim(" (no peers connected)"));
|
|
7600
|
+
continue;
|
|
7601
|
+
}
|
|
7602
|
+
for (const p of peers) {
|
|
7603
|
+
const groups = p.groups.length ? " [" + p.groups.map((g) => `@${g.name}${g.role ? `:${g.role}` : ""}`).join(", ") + "]" : "";
|
|
7604
|
+
const statusDot = p.status === "working" ? yellow("●") : green("●");
|
|
7605
|
+
const name = bold(p.displayName);
|
|
7606
|
+
const meta = [];
|
|
7607
|
+
if (p.peerType)
|
|
7608
|
+
meta.push(p.peerType);
|
|
7609
|
+
if (p.channel)
|
|
7610
|
+
meta.push(p.channel);
|
|
7611
|
+
if (p.model)
|
|
7612
|
+
meta.push(p.model);
|
|
7613
|
+
const metaStr = meta.length ? dim(` (${meta.join(", ")})`) : "";
|
|
7614
|
+
const summary = p.summary ? dim(` — ${p.summary}`) : "";
|
|
7615
|
+
const pubkeyTag = dim(` · ${p.pubkey.slice(0, 16)}…`);
|
|
7616
|
+
const selfTag = p.isThisSession ? dim(" ") + yellow("(this session)") : p.isSelf ? dim(" ") + yellow("(your other session)") : "";
|
|
7617
|
+
render.info(`${statusDot} ${name}${selfTag}${groups}${metaStr}${pubkeyTag}${summary}`);
|
|
7618
|
+
if (p.cwd)
|
|
7619
|
+
render.info(dim(` cwd: ${p.cwd}`));
|
|
7620
|
+
}
|
|
7621
|
+
} catch (e) {
|
|
7622
|
+
render.err(`${slug}: ${e instanceof Error ? e.message : String(e)}`);
|
|
7475
7623
|
}
|
|
7476
|
-
|
|
7477
|
-
|
|
7478
|
-
|
|
7479
|
-
const topic = cyan(`#${a.topicName}`);
|
|
7480
|
-
const sender = a.senderName ?? "?";
|
|
7481
|
-
const ago = formatRelativeTime(a.createdAt);
|
|
7482
|
-
const snippet = a.snippet ?? (a.ciphertext ? dim("[encrypted]") : dim("[empty]"));
|
|
7483
|
-
process.stdout.write(` ${slug} ${topic} ${dim(sender + " ·")} ${dim(ago)}
|
|
7484
|
-
` + ` ${snippet.length > 200 ? snippet.slice(0, 200) + "…" : snippet}
|
|
7624
|
+
}
|
|
7625
|
+
if (wantsJson) {
|
|
7626
|
+
process.stdout.write(JSON.stringify(slugs.length === 1 ? allJson[0]?.peers : allJson, null, 2) + `
|
|
7485
7627
|
`);
|
|
7486
|
-
|
|
7487
|
-
return EXIT.SUCCESS;
|
|
7488
|
-
});
|
|
7628
|
+
}
|
|
7489
7629
|
}
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
|
|
7494
|
-
|
|
7630
|
+
var FIELD_ALIAS;
|
|
7631
|
+
var init_peers = __esm(() => {
|
|
7632
|
+
init_connect();
|
|
7633
|
+
init_facade();
|
|
7634
|
+
init_client3();
|
|
7635
|
+
init_render();
|
|
7636
|
+
init_styles();
|
|
7637
|
+
FIELD_ALIAS = {
|
|
7638
|
+
name: "displayName"
|
|
7639
|
+
};
|
|
7640
|
+
});
|
|
7641
|
+
|
|
7642
|
+
// src/commands/send.ts
|
|
7643
|
+
var exports_send = {};
|
|
7644
|
+
__export(exports_send, {
|
|
7645
|
+
runSend: () => runSend
|
|
7646
|
+
});
|
|
7647
|
+
async function runSend(flags, to, message) {
|
|
7648
|
+
if (!to || !message) {
|
|
7649
|
+
render.err("Usage: claudemesh send <to> <message>");
|
|
7650
|
+
process.exit(1);
|
|
7495
7651
|
}
|
|
7496
|
-
|
|
7497
|
-
|
|
7498
|
-
|
|
7499
|
-
|
|
7500
|
-
|
|
7501
|
-
|
|
7502
|
-
|
|
7503
|
-
|
|
7504
|
-
|
|
7505
|
-
});
|
|
7506
|
-
if (flags.json) {
|
|
7507
|
-
console.log(JSON.stringify(ws, null, 2));
|
|
7508
|
-
return EXIT.SUCCESS;
|
|
7652
|
+
const priority = flags.priority === "now" ? "now" : flags.priority === "low" ? "low" : "next";
|
|
7653
|
+
const config = readConfig();
|
|
7654
|
+
const meshSlug = flags.mesh ?? (config.meshes.length === 1 ? config.meshes[0].slug : null);
|
|
7655
|
+
if (!flags.self && meshSlug) {
|
|
7656
|
+
const joined = config.meshes.find((m) => m.slug === meshSlug);
|
|
7657
|
+
if (joined && /^[0-9a-f]{64}$/i.test(to) && to.toLowerCase() === joined.pubkey.toLowerCase()) {
|
|
7658
|
+
render.err(`Target "${to.slice(0, 16)}…" is your own member pubkey on mesh "${meshSlug}".`);
|
|
7659
|
+
render.hint("Pass --self to message a sibling session of your own member, or pick a different peer's pubkey.");
|
|
7660
|
+
process.exit(1);
|
|
7509
7661
|
}
|
|
7510
|
-
|
|
7511
|
-
|
|
7512
|
-
|
|
7513
|
-
|
|
7514
|
-
|
|
7662
|
+
}
|
|
7663
|
+
{
|
|
7664
|
+
const dr = await trySendViaDaemon({ to, message, priority, expectedMesh: meshSlug ?? undefined });
|
|
7665
|
+
if (dr !== null) {
|
|
7666
|
+
if (dr.ok) {
|
|
7667
|
+
if (flags.json)
|
|
7668
|
+
console.log(JSON.stringify({ ok: true, messageId: dr.messageId, target: to, via: "daemon", duplicate: !!dr.duplicate }));
|
|
7669
|
+
else
|
|
7670
|
+
render.ok(`sent to ${to} (daemon)`, dr.messageId ? dim(dr.messageId.slice(0, 8)) : undefined);
|
|
7671
|
+
return;
|
|
7672
|
+
}
|
|
7673
|
+
if (flags.json)
|
|
7674
|
+
console.log(JSON.stringify({ ok: false, error: dr.error, via: "daemon" }));
|
|
7675
|
+
else
|
|
7676
|
+
render.err(`send failed (daemon): ${dr.error}`);
|
|
7677
|
+
process.exit(1);
|
|
7515
7678
|
}
|
|
7516
|
-
|
|
7517
|
-
|
|
7518
|
-
|
|
7519
|
-
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
|
|
7523
|
-
|
|
7524
|
-
|
|
7525
|
-
|
|
7526
|
-
|
|
7679
|
+
}
|
|
7680
|
+
if (meshSlug) {
|
|
7681
|
+
const bridged = await tryBridge(meshSlug, "send", { to, message, priority });
|
|
7682
|
+
if (bridged !== null) {
|
|
7683
|
+
if (bridged.ok) {
|
|
7684
|
+
const r = bridged.result;
|
|
7685
|
+
if (flags.json) {
|
|
7686
|
+
console.log(JSON.stringify({ ok: true, messageId: r.messageId, target: to }));
|
|
7687
|
+
} else {
|
|
7688
|
+
render.ok(`sent to ${to}`, r.messageId ? dim(r.messageId.slice(0, 8)) : undefined);
|
|
7689
|
+
}
|
|
7690
|
+
return;
|
|
7691
|
+
}
|
|
7692
|
+
if (flags.json) {
|
|
7693
|
+
console.log(JSON.stringify({ ok: false, error: bridged.error }));
|
|
7694
|
+
} else {
|
|
7695
|
+
render.err(`send failed: ${bridged.error}`);
|
|
7527
7696
|
}
|
|
7697
|
+
process.exit(1);
|
|
7528
7698
|
}
|
|
7529
|
-
|
|
7530
|
-
|
|
7531
|
-
|
|
7532
|
-
|
|
7533
|
-
const
|
|
7534
|
-
|
|
7535
|
-
|
|
7536
|
-
|
|
7537
|
-
const
|
|
7538
|
-
|
|
7539
|
-
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
|
|
7543
|
-
|
|
7699
|
+
}
|
|
7700
|
+
await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
7701
|
+
let targetSpec = to;
|
|
7702
|
+
if (to.startsWith("#") && !/^#[0-9a-z_-]{20,}$/i.test(to)) {
|
|
7703
|
+
const name = to.slice(1);
|
|
7704
|
+
const topics = await client.topicList();
|
|
7705
|
+
const match = topics.find((t) => t.name === name);
|
|
7706
|
+
if (!match) {
|
|
7707
|
+
const names = topics.map((t) => "#" + t.name).join(", ");
|
|
7708
|
+
render.err(`Topic "${to}" not found.`, `topics: ${names || "(none)"}`);
|
|
7709
|
+
process.exit(1);
|
|
7710
|
+
}
|
|
7711
|
+
targetSpec = "#" + match.id;
|
|
7712
|
+
} else if (!to.startsWith("@") && !to.startsWith("#") && to !== "*" && !/^[0-9a-f]{64}$/i.test(to)) {
|
|
7713
|
+
const peers = await client.listPeers();
|
|
7714
|
+
const match = peers.find((p) => p.displayName.toLowerCase() === to.toLowerCase());
|
|
7715
|
+
if (!match) {
|
|
7716
|
+
const names = peers.map((p) => p.displayName).join(", ");
|
|
7717
|
+
render.err(`Peer "${to}" not found.`, `online: ${names || "(none)"}`);
|
|
7718
|
+
process.exit(1);
|
|
7719
|
+
}
|
|
7720
|
+
targetSpec = match.pubkey;
|
|
7721
|
+
}
|
|
7722
|
+
const result = await client.send(targetSpec, message, priority);
|
|
7723
|
+
if (result.ok) {
|
|
7724
|
+
if (flags.json) {
|
|
7725
|
+
console.log(JSON.stringify({ ok: true, messageId: result.messageId, target: to }));
|
|
7726
|
+
} else {
|
|
7727
|
+
render.ok(`sent to ${to}`, result.messageId ? dim(result.messageId.slice(0, 8)) : undefined);
|
|
7728
|
+
}
|
|
7729
|
+
} else {
|
|
7730
|
+
if (flags.json) {
|
|
7731
|
+
console.log(JSON.stringify({ ok: false, error: result.error ?? "unknown" }));
|
|
7732
|
+
} else {
|
|
7733
|
+
render.err(`send failed: ${result.error ?? "unknown error"}`);
|
|
7544
7734
|
}
|
|
7735
|
+
process.exit(1);
|
|
7545
7736
|
}
|
|
7546
|
-
return EXIT.SUCCESS;
|
|
7547
7737
|
});
|
|
7548
7738
|
}
|
|
7549
|
-
|
|
7550
|
-
|
|
7551
|
-
|
|
7552
|
-
|
|
7553
|
-
|
|
7554
|
-
|
|
7555
|
-
|
|
7556
|
-
|
|
7557
|
-
|
|
7558
|
-
|
|
7739
|
+
var init_send = __esm(() => {
|
|
7740
|
+
init_connect();
|
|
7741
|
+
init_facade();
|
|
7742
|
+
init_client3();
|
|
7743
|
+
init_daemon_route();
|
|
7744
|
+
init_render();
|
|
7745
|
+
init_styles();
|
|
7746
|
+
});
|
|
7747
|
+
|
|
7748
|
+
// src/commands/inbox.ts
|
|
7749
|
+
var exports_inbox = {};
|
|
7750
|
+
__export(exports_inbox, {
|
|
7751
|
+
runInbox: () => runInbox
|
|
7752
|
+
});
|
|
7753
|
+
function formatMessage(msg) {
|
|
7754
|
+
const text = msg.plaintext ?? `[encrypted: ${msg.ciphertext.slice(0, 32)}…]`;
|
|
7755
|
+
const from = msg.senderPubkey.slice(0, 8);
|
|
7756
|
+
const time = new Date(msg.createdAt).toLocaleTimeString();
|
|
7757
|
+
const kindTag = msg.kind === "direct" ? "→ direct" : msg.kind;
|
|
7758
|
+
return ` ${bold(from)} ${dim(`[${kindTag}] ${time}`)}
|
|
7759
|
+
${text}`;
|
|
7559
7760
|
}
|
|
7560
|
-
async function
|
|
7561
|
-
|
|
7562
|
-
|
|
7563
|
-
|
|
7564
|
-
|
|
7565
|
-
}, async ({ secret }) => {
|
|
7566
|
-
const params = new URLSearchParams;
|
|
7567
|
-
if (flags.status)
|
|
7568
|
-
params.set("status", flags.status);
|
|
7569
|
-
const path = "/api/v1/me/tasks" + (params.toString() ? `?${params.toString()}` : "");
|
|
7570
|
-
const ws = await request({
|
|
7571
|
-
path,
|
|
7572
|
-
token: secret
|
|
7573
|
-
});
|
|
7761
|
+
async function runInbox(flags) {
|
|
7762
|
+
const waitMs = (flags.wait ?? 1) * 1000;
|
|
7763
|
+
await withMesh({ meshSlug: flags.mesh ?? null }, async (client, mesh) => {
|
|
7764
|
+
await new Promise((resolve) => setTimeout(resolve, waitMs));
|
|
7765
|
+
const messages = client.drainPushBuffer();
|
|
7574
7766
|
if (flags.json) {
|
|
7575
|
-
|
|
7576
|
-
|
|
7767
|
+
process.stdout.write(JSON.stringify(messages, null, 2) + `
|
|
7768
|
+
`);
|
|
7769
|
+
return;
|
|
7577
7770
|
}
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
`));
|
|
7582
|
-
return EXIT.SUCCESS;
|
|
7771
|
+
if (messages.length === 0) {
|
|
7772
|
+
render.info(dim(`No messages on mesh "${mesh.slug}".`));
|
|
7773
|
+
return;
|
|
7583
7774
|
}
|
|
7584
|
-
|
|
7585
|
-
for (const
|
|
7586
|
-
|
|
7587
|
-
|
|
7588
|
-
const prio = t.priority === "urgent" ? yellow("!") : t.priority === "low" ? dim("·") : " ";
|
|
7589
|
-
const claimer = t.claimedByName ? dim(` ← ${t.claimedByName}`) : "";
|
|
7590
|
-
process.stdout.write(` ${slug} ${prio} ${status} ${t.title}${claimer}
|
|
7775
|
+
render.section(`inbox — ${mesh.slug} (${messages.length} message${messages.length === 1 ? "" : "s"})`);
|
|
7776
|
+
for (const msg of messages) {
|
|
7777
|
+
process.stdout.write(formatMessage(msg) + `
|
|
7778
|
+
|
|
7591
7779
|
`);
|
|
7592
7780
|
}
|
|
7593
|
-
return EXIT.SUCCESS;
|
|
7594
7781
|
});
|
|
7595
7782
|
}
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
7604
|
-
|
|
7605
|
-
|
|
7606
|
-
|
|
7607
|
-
|
|
7608
|
-
|
|
7609
|
-
|
|
7783
|
+
var init_inbox = __esm(() => {
|
|
7784
|
+
init_connect();
|
|
7785
|
+
init_render();
|
|
7786
|
+
init_styles();
|
|
7787
|
+
});
|
|
7788
|
+
|
|
7789
|
+
// src/commands/state.ts
|
|
7790
|
+
var exports_state = {};
|
|
7791
|
+
__export(exports_state, {
|
|
7792
|
+
runStateSet: () => runStateSet,
|
|
7793
|
+
runStateList: () => runStateList,
|
|
7794
|
+
runStateGet: () => runStateGet
|
|
7795
|
+
});
|
|
7796
|
+
async function runStateGet(flags, key) {
|
|
7797
|
+
const daemonEntry = await tryGetStateViaDaemon(key, flags.mesh);
|
|
7798
|
+
if (daemonEntry !== null) {
|
|
7799
|
+
if (!daemonEntry) {
|
|
7800
|
+
render.info(dim("(not set)"));
|
|
7801
|
+
return;
|
|
7802
|
+
}
|
|
7610
7803
|
if (flags.json) {
|
|
7611
|
-
console.log(JSON.stringify(
|
|
7612
|
-
return
|
|
7804
|
+
console.log(JSON.stringify(daemonEntry, null, 2));
|
|
7805
|
+
return;
|
|
7613
7806
|
}
|
|
7614
|
-
|
|
7615
|
-
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
|
|
7807
|
+
const val = typeof daemonEntry.value === "string" ? daemonEntry.value : JSON.stringify(daemonEntry.value);
|
|
7808
|
+
render.info(val);
|
|
7809
|
+
render.info(dim(` set by ${daemonEntry.updatedBy} at ${new Date(daemonEntry.updatedAt).toLocaleString()}`));
|
|
7810
|
+
return;
|
|
7811
|
+
}
|
|
7812
|
+
await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
7813
|
+
const entry = await client.getState(key);
|
|
7814
|
+
if (!entry) {
|
|
7815
|
+
render.info(dim("(not set)"));
|
|
7816
|
+
return;
|
|
7619
7817
|
}
|
|
7620
|
-
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
const slug = dim(e.meshSlug.padEnd(slugWidth));
|
|
7624
|
-
const key = cyan(e.key.padEnd(keyWidth));
|
|
7625
|
-
const valueStr = typeof e.value === "string" ? e.value : JSON.stringify(e.value);
|
|
7626
|
-
const trimmed = valueStr.length > 80 ? valueStr.slice(0, 80) + "…" : valueStr;
|
|
7627
|
-
const ago = dim(formatRelativeTime(e.updatedAt));
|
|
7628
|
-
process.stdout.write(` ${slug} ${key} ${trimmed} ${ago}
|
|
7629
|
-
`);
|
|
7818
|
+
if (flags.json) {
|
|
7819
|
+
console.log(JSON.stringify(entry, null, 2));
|
|
7820
|
+
return;
|
|
7630
7821
|
}
|
|
7631
|
-
|
|
7822
|
+
const val = typeof entry.value === "string" ? entry.value : JSON.stringify(entry.value);
|
|
7823
|
+
render.info(val);
|
|
7824
|
+
render.info(dim(` set by ${entry.updatedBy} at ${new Date(entry.updatedAt).toLocaleString()}`));
|
|
7632
7825
|
});
|
|
7633
7826
|
}
|
|
7634
|
-
async function
|
|
7635
|
-
|
|
7636
|
-
|
|
7637
|
-
|
|
7638
|
-
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
|
|
7642
|
-
|
|
7643
|
-
|
|
7644
|
-
|
|
7645
|
-
|
|
7646
|
-
|
|
7647
|
-
|
|
7827
|
+
async function runStateSet(flags, key, value) {
|
|
7828
|
+
let parsed;
|
|
7829
|
+
try {
|
|
7830
|
+
parsed = JSON.parse(value);
|
|
7831
|
+
} catch {
|
|
7832
|
+
parsed = value;
|
|
7833
|
+
}
|
|
7834
|
+
const daemonOk = await trySetStateViaDaemon(key, parsed, flags.mesh);
|
|
7835
|
+
if (daemonOk) {
|
|
7836
|
+
render.ok(`${bold(key)} = ${JSON.stringify(parsed)}`);
|
|
7837
|
+
return;
|
|
7838
|
+
}
|
|
7839
|
+
await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
7840
|
+
await client.setState(key, parsed);
|
|
7841
|
+
render.ok(`${bold(key)} = ${JSON.stringify(parsed)}`);
|
|
7842
|
+
});
|
|
7843
|
+
}
|
|
7844
|
+
async function runStateList(flags) {
|
|
7845
|
+
const daemonRows = await tryListStateViaDaemon(flags.mesh);
|
|
7846
|
+
if (daemonRows !== null) {
|
|
7648
7847
|
if (flags.json) {
|
|
7649
|
-
console.log(JSON.stringify(
|
|
7650
|
-
return
|
|
7848
|
+
console.log(JSON.stringify(daemonRows, null, 2));
|
|
7849
|
+
return;
|
|
7651
7850
|
}
|
|
7652
|
-
|
|
7653
|
-
|
|
7654
|
-
|
|
7655
|
-
process.stdout.write(dim(` no memories
|
|
7656
|
-
`));
|
|
7657
|
-
return EXIT.SUCCESS;
|
|
7851
|
+
if (daemonRows.length === 0) {
|
|
7852
|
+
render.info(dim("(no state)"));
|
|
7853
|
+
return;
|
|
7658
7854
|
}
|
|
7659
|
-
|
|
7660
|
-
for (const
|
|
7661
|
-
const
|
|
7662
|
-
|
|
7663
|
-
|
|
7664
|
-
|
|
7665
|
-
process.stdout.write(` ${slug} ${ago}${tags}
|
|
7666
|
-
${content}
|
|
7855
|
+
render.section(`state (${daemonRows.length})`);
|
|
7856
|
+
for (const e of daemonRows) {
|
|
7857
|
+
const val = typeof e.value === "string" ? e.value : JSON.stringify(e.value);
|
|
7858
|
+
process.stdout.write(` ${bold(e.key)}: ${val}
|
|
7859
|
+
`);
|
|
7860
|
+
process.stdout.write(` ${dim(e.updatedBy + " · " + new Date(e.updatedAt).toLocaleString())}
|
|
7667
7861
|
`);
|
|
7668
7862
|
}
|
|
7669
|
-
return
|
|
7670
|
-
}
|
|
7671
|
-
}
|
|
7672
|
-
function formatRelativeTime(iso) {
|
|
7673
|
-
const then = new Date(iso).getTime();
|
|
7674
|
-
const now = Date.now();
|
|
7675
|
-
const sec = Math.max(0, Math.floor((now - then) / 1000));
|
|
7676
|
-
if (sec < 60)
|
|
7677
|
-
return `${sec}s ago`;
|
|
7678
|
-
if (sec < 3600)
|
|
7679
|
-
return `${Math.floor(sec / 60)}m ago`;
|
|
7680
|
-
if (sec < 86400)
|
|
7681
|
-
return `${Math.floor(sec / 3600)}h ago`;
|
|
7682
|
-
if (sec < 86400 * 30)
|
|
7683
|
-
return `${Math.floor(sec / 86400)}d ago`;
|
|
7684
|
-
if (sec < 86400 * 365)
|
|
7685
|
-
return `${Math.floor(sec / (86400 * 30))}mo ago`;
|
|
7686
|
-
return `${Math.floor(sec / (86400 * 365))}y ago`;
|
|
7687
|
-
}
|
|
7688
|
-
var init_me = __esm(() => {
|
|
7689
|
-
init_with_rest_key();
|
|
7690
|
-
init_client();
|
|
7691
|
-
init_facade();
|
|
7692
|
-
init_render();
|
|
7693
|
-
init_styles();
|
|
7694
|
-
init_exit_codes();
|
|
7695
|
-
});
|
|
7696
|
-
|
|
7697
|
-
// src/commands/info.ts
|
|
7698
|
-
var exports_info = {};
|
|
7699
|
-
__export(exports_info, {
|
|
7700
|
-
runInfo: () => runInfo
|
|
7701
|
-
});
|
|
7702
|
-
async function runInfo(flags) {
|
|
7703
|
-
const config = readConfig();
|
|
7863
|
+
return;
|
|
7864
|
+
}
|
|
7704
7865
|
await withMesh({ meshSlug: flags.mesh ?? null }, async (client, mesh) => {
|
|
7705
|
-
const
|
|
7706
|
-
client.meshInfo(),
|
|
7707
|
-
client.listPeers(),
|
|
7708
|
-
client.listState()
|
|
7709
|
-
]);
|
|
7710
|
-
const output = {
|
|
7711
|
-
slug: mesh.slug,
|
|
7712
|
-
meshId: mesh.meshId,
|
|
7713
|
-
memberId: mesh.memberId,
|
|
7714
|
-
brokerUrl: mesh.brokerUrl,
|
|
7715
|
-
displayName: config.displayName ?? null,
|
|
7716
|
-
peerCount: peers.length,
|
|
7717
|
-
stateCount: state.length,
|
|
7718
|
-
...brokerInfo ?? {}
|
|
7719
|
-
};
|
|
7866
|
+
const entries = await client.listState();
|
|
7720
7867
|
if (flags.json) {
|
|
7721
|
-
|
|
7722
|
-
`);
|
|
7868
|
+
console.log(JSON.stringify(entries, null, 2));
|
|
7723
7869
|
return;
|
|
7724
7870
|
}
|
|
7725
|
-
|
|
7726
|
-
|
|
7727
|
-
|
|
7728
|
-
|
|
7729
|
-
|
|
7730
|
-
|
|
7731
|
-
|
|
7732
|
-
|
|
7733
|
-
|
|
7734
|
-
|
|
7735
|
-
|
|
7736
|
-
continue;
|
|
7737
|
-
extras.push([k, JSON.stringify(v)]);
|
|
7738
|
-
}
|
|
7739
|
-
if (extras.length)
|
|
7740
|
-
render.kv(extras);
|
|
7871
|
+
if (entries.length === 0) {
|
|
7872
|
+
render.info(dim(`No state on mesh "${mesh.slug}".`));
|
|
7873
|
+
return;
|
|
7874
|
+
}
|
|
7875
|
+
render.section(`state (${entries.length})`);
|
|
7876
|
+
for (const e of entries) {
|
|
7877
|
+
const val = typeof e.value === "string" ? e.value : JSON.stringify(e.value);
|
|
7878
|
+
process.stdout.write(` ${bold(e.key)}: ${val}
|
|
7879
|
+
`);
|
|
7880
|
+
process.stdout.write(` ${dim(e.updatedBy + " · " + new Date(e.updatedAt).toLocaleString())}
|
|
7881
|
+
`);
|
|
7741
7882
|
}
|
|
7742
7883
|
});
|
|
7743
7884
|
}
|
|
7744
|
-
var
|
|
7885
|
+
var init_state = __esm(() => {
|
|
7745
7886
|
init_connect();
|
|
7746
|
-
|
|
7887
|
+
init_daemon_route();
|
|
7747
7888
|
init_render();
|
|
7889
|
+
init_styles();
|
|
7748
7890
|
});
|
|
7749
7891
|
|
|
7750
7892
|
// src/commands/remember.ts
|
|
@@ -7758,6 +7900,15 @@ async function remember(content, opts = {}) {
|
|
|
7758
7900
|
return EXIT.INVALID_ARGS;
|
|
7759
7901
|
}
|
|
7760
7902
|
const tags = opts.tags?.split(",").map((t) => t.trim()).filter(Boolean);
|
|
7903
|
+
const daemonRes = await tryRememberViaDaemon(content, tags, opts.mesh);
|
|
7904
|
+
if (daemonRes) {
|
|
7905
|
+
if (opts.json) {
|
|
7906
|
+
console.log(JSON.stringify({ id: daemonRes.id, content, tags, mesh: daemonRes.mesh }));
|
|
7907
|
+
return EXIT.SUCCESS;
|
|
7908
|
+
}
|
|
7909
|
+
render.ok("remembered", dim(daemonRes.id.slice(0, 8)));
|
|
7910
|
+
return EXIT.SUCCESS;
|
|
7911
|
+
}
|
|
7761
7912
|
return await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => {
|
|
7762
7913
|
const id = await client.remember(content, tags);
|
|
7763
7914
|
if (opts.json) {
|
|
@@ -7774,6 +7925,7 @@ async function remember(content, opts = {}) {
|
|
|
7774
7925
|
}
|
|
7775
7926
|
var init_remember = __esm(() => {
|
|
7776
7927
|
init_connect();
|
|
7928
|
+
init_daemon_route();
|
|
7777
7929
|
init_render();
|
|
7778
7930
|
init_styles();
|
|
7779
7931
|
init_exit_codes();
|
|
@@ -7789,6 +7941,29 @@ async function recall(query, opts = {}) {
|
|
|
7789
7941
|
render.err("Usage: claudemesh recall <query>");
|
|
7790
7942
|
return EXIT.INVALID_ARGS;
|
|
7791
7943
|
}
|
|
7944
|
+
const daemonMatches = await tryRecallViaDaemon(query, opts.mesh);
|
|
7945
|
+
if (daemonMatches !== null) {
|
|
7946
|
+
if (opts.json) {
|
|
7947
|
+
console.log(JSON.stringify(daemonMatches, null, 2));
|
|
7948
|
+
return EXIT.SUCCESS;
|
|
7949
|
+
}
|
|
7950
|
+
if (daemonMatches.length === 0) {
|
|
7951
|
+
render.info(dim("no memories found."));
|
|
7952
|
+
return EXIT.SUCCESS;
|
|
7953
|
+
}
|
|
7954
|
+
render.section(`memories (${daemonMatches.length})`);
|
|
7955
|
+
for (const m of daemonMatches) {
|
|
7956
|
+
const tags = m.tags.length ? dim(` [${m.tags.map((t) => clay(t)).join(dim(", "))}]`) : "";
|
|
7957
|
+
process.stdout.write(` ${bold(m.id.slice(0, 8))}${tags}
|
|
7958
|
+
`);
|
|
7959
|
+
process.stdout.write(` ${m.content}
|
|
7960
|
+
`);
|
|
7961
|
+
process.stdout.write(` ${dim(m.rememberedBy + " · " + new Date(m.rememberedAt).toLocaleString())}
|
|
7962
|
+
|
|
7963
|
+
`);
|
|
7964
|
+
}
|
|
7965
|
+
return EXIT.SUCCESS;
|
|
7966
|
+
}
|
|
7792
7967
|
return await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => {
|
|
7793
7968
|
const memories = await client.recall(query);
|
|
7794
7969
|
if (opts.json) {
|
|
@@ -7815,6 +7990,7 @@ async function recall(query, opts = {}) {
|
|
|
7815
7990
|
}
|
|
7816
7991
|
var init_recall = __esm(() => {
|
|
7817
7992
|
init_connect();
|
|
7993
|
+
init_daemon_route();
|
|
7818
7994
|
init_render();
|
|
7819
7995
|
init_styles();
|
|
7820
7996
|
init_exit_codes();
|
|
@@ -8027,6 +8203,14 @@ async function runForget(id, opts) {
|
|
|
8027
8203
|
render.err("Usage: claudemesh forget <memory-id>");
|
|
8028
8204
|
return EXIT.INVALID_ARGS;
|
|
8029
8205
|
}
|
|
8206
|
+
if (await tryForgetViaDaemon(id, opts.mesh)) {
|
|
8207
|
+
if (opts.json) {
|
|
8208
|
+
console.log(JSON.stringify({ id, forgotten: true }));
|
|
8209
|
+
return EXIT.SUCCESS;
|
|
8210
|
+
}
|
|
8211
|
+
render.ok(`forgot ${dim(id.slice(0, 8))}`);
|
|
8212
|
+
return EXIT.SUCCESS;
|
|
8213
|
+
}
|
|
8030
8214
|
await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => {
|
|
8031
8215
|
await client.forget(id);
|
|
8032
8216
|
});
|
|
@@ -8204,6 +8388,7 @@ var init_broker_actions = __esm(() => {
|
|
|
8204
8388
|
init_connect();
|
|
8205
8389
|
init_facade();
|
|
8206
8390
|
init_client3();
|
|
8391
|
+
init_daemon_route();
|
|
8207
8392
|
init_render();
|
|
8208
8393
|
init_styles();
|
|
8209
8394
|
init_exit_codes();
|
|
@@ -9003,7 +9188,7 @@ function makeHandler(opts) {
|
|
|
9003
9188
|
respond(res, 200, {
|
|
9004
9189
|
daemon_version: VERSION,
|
|
9005
9190
|
ipc_api: "v1",
|
|
9006
|
-
ipc_features: ["version", "health", "send", "inbox", "events", "peers", "profile", "skills"],
|
|
9191
|
+
ipc_features: ["version", "health", "send", "inbox", "events", "peers", "profile", "skills", "state", "memory"],
|
|
9007
9192
|
schema_version: 1
|
|
9008
9193
|
});
|
|
9009
9194
|
return;
|
|
@@ -9045,6 +9230,157 @@ function makeHandler(opts) {
|
|
|
9045
9230
|
}
|
|
9046
9231
|
return;
|
|
9047
9232
|
}
|
|
9233
|
+
if (req.method === "GET" && url.pathname === "/v1/state") {
|
|
9234
|
+
if (!opts.brokers || opts.brokers.size === 0) {
|
|
9235
|
+
respond(res, 503, { error: "broker not initialised" });
|
|
9236
|
+
return;
|
|
9237
|
+
}
|
|
9238
|
+
const filterMesh = url.searchParams.get("mesh") ?? undefined;
|
|
9239
|
+
const key = url.searchParams.get("key");
|
|
9240
|
+
try {
|
|
9241
|
+
if (key) {
|
|
9242
|
+
for (const [slug, b] of opts.brokers.entries()) {
|
|
9243
|
+
if (filterMesh && filterMesh !== slug)
|
|
9244
|
+
continue;
|
|
9245
|
+
const row = await b.getState(key).catch(() => null);
|
|
9246
|
+
if (row) {
|
|
9247
|
+
respond(res, 200, { state: { ...row, mesh: slug } });
|
|
9248
|
+
return;
|
|
9249
|
+
}
|
|
9250
|
+
}
|
|
9251
|
+
respond(res, 404, { error: "state_not_found", key });
|
|
9252
|
+
return;
|
|
9253
|
+
}
|
|
9254
|
+
const all = [];
|
|
9255
|
+
for (const [slug, b] of opts.brokers.entries()) {
|
|
9256
|
+
if (filterMesh && filterMesh !== slug)
|
|
9257
|
+
continue;
|
|
9258
|
+
const rows = await b.listState().catch(() => []);
|
|
9259
|
+
for (const r of rows)
|
|
9260
|
+
all.push({ ...r, mesh: slug });
|
|
9261
|
+
}
|
|
9262
|
+
respond(res, 200, { entries: all });
|
|
9263
|
+
} catch (e) {
|
|
9264
|
+
respond(res, 502, { error: "broker_unreachable", detail: String(e) });
|
|
9265
|
+
}
|
|
9266
|
+
return;
|
|
9267
|
+
}
|
|
9268
|
+
if (req.method === "POST" && url.pathname === "/v1/state") {
|
|
9269
|
+
if (!opts.brokers || opts.brokers.size === 0) {
|
|
9270
|
+
respond(res, 503, { error: "broker not initialised" });
|
|
9271
|
+
return;
|
|
9272
|
+
}
|
|
9273
|
+
try {
|
|
9274
|
+
const body = await readJsonBody(req, 256 * 1024);
|
|
9275
|
+
if (!body || typeof body.key !== "string") {
|
|
9276
|
+
respond(res, 400, { error: "missing 'key' (string)" });
|
|
9277
|
+
return;
|
|
9278
|
+
}
|
|
9279
|
+
const requested = (typeof body.mesh === "string" ? body.mesh : null) || null;
|
|
9280
|
+
let chosen = requested;
|
|
9281
|
+
if (!chosen && opts.brokers.size === 1)
|
|
9282
|
+
chosen = opts.brokers.keys().next().value;
|
|
9283
|
+
if (!chosen) {
|
|
9284
|
+
respond(res, 400, { error: "mesh_required", attached: [...opts.brokers.keys()] });
|
|
9285
|
+
return;
|
|
9286
|
+
}
|
|
9287
|
+
const broker = opts.brokers.get(chosen);
|
|
9288
|
+
if (!broker) {
|
|
9289
|
+
respond(res, 404, { error: "mesh_not_attached", mesh: chosen });
|
|
9290
|
+
return;
|
|
9291
|
+
}
|
|
9292
|
+
broker.setState(body.key, body.value);
|
|
9293
|
+
respond(res, 200, { ok: true, key: body.key, mesh: chosen });
|
|
9294
|
+
} catch (e) {
|
|
9295
|
+
respond(res, 400, { error: String(e) });
|
|
9296
|
+
}
|
|
9297
|
+
return;
|
|
9298
|
+
}
|
|
9299
|
+
if (req.method === "GET" && url.pathname === "/v1/memory") {
|
|
9300
|
+
if (!opts.brokers || opts.brokers.size === 0) {
|
|
9301
|
+
respond(res, 503, { error: "broker not initialised" });
|
|
9302
|
+
return;
|
|
9303
|
+
}
|
|
9304
|
+
const query = url.searchParams.get("q") ?? "";
|
|
9305
|
+
const filterMesh = url.searchParams.get("mesh") ?? undefined;
|
|
9306
|
+
try {
|
|
9307
|
+
const all = [];
|
|
9308
|
+
for (const [slug, b] of opts.brokers.entries()) {
|
|
9309
|
+
if (filterMesh && filterMesh !== slug)
|
|
9310
|
+
continue;
|
|
9311
|
+
const rows = await b.recall(query).catch(() => []);
|
|
9312
|
+
for (const r of rows)
|
|
9313
|
+
all.push({ ...r, mesh: slug });
|
|
9314
|
+
}
|
|
9315
|
+
respond(res, 200, { matches: all });
|
|
9316
|
+
} catch (e) {
|
|
9317
|
+
respond(res, 502, { error: "broker_unreachable", detail: String(e) });
|
|
9318
|
+
}
|
|
9319
|
+
return;
|
|
9320
|
+
}
|
|
9321
|
+
if (req.method === "POST" && url.pathname === "/v1/memory") {
|
|
9322
|
+
if (!opts.brokers || opts.brokers.size === 0) {
|
|
9323
|
+
respond(res, 503, { error: "broker not initialised" });
|
|
9324
|
+
return;
|
|
9325
|
+
}
|
|
9326
|
+
try {
|
|
9327
|
+
const body = await readJsonBody(req, 256 * 1024);
|
|
9328
|
+
if (!body || typeof body.content !== "string") {
|
|
9329
|
+
respond(res, 400, { error: "missing 'content' (string)" });
|
|
9330
|
+
return;
|
|
9331
|
+
}
|
|
9332
|
+
const requested = (typeof body.mesh === "string" ? body.mesh : null) || null;
|
|
9333
|
+
let chosen = requested;
|
|
9334
|
+
if (!chosen && opts.brokers.size === 1)
|
|
9335
|
+
chosen = opts.brokers.keys().next().value;
|
|
9336
|
+
if (!chosen) {
|
|
9337
|
+
respond(res, 400, { error: "mesh_required", attached: [...opts.brokers.keys()] });
|
|
9338
|
+
return;
|
|
9339
|
+
}
|
|
9340
|
+
const broker = opts.brokers.get(chosen);
|
|
9341
|
+
if (!broker) {
|
|
9342
|
+
respond(res, 404, { error: "mesh_not_attached", mesh: chosen });
|
|
9343
|
+
return;
|
|
9344
|
+
}
|
|
9345
|
+
const tags = Array.isArray(body.tags) ? body.tags.filter((t) => typeof t === "string") : undefined;
|
|
9346
|
+
const id = await broker.remember(body.content, tags);
|
|
9347
|
+
if (!id) {
|
|
9348
|
+
respond(res, 502, { error: "remember_timeout" });
|
|
9349
|
+
return;
|
|
9350
|
+
}
|
|
9351
|
+
respond(res, 200, { id, mesh: chosen });
|
|
9352
|
+
} catch (e) {
|
|
9353
|
+
respond(res, 400, { error: String(e) });
|
|
9354
|
+
}
|
|
9355
|
+
return;
|
|
9356
|
+
}
|
|
9357
|
+
if (req.method === "DELETE" && url.pathname.startsWith("/v1/memory/")) {
|
|
9358
|
+
if (!opts.brokers || opts.brokers.size === 0) {
|
|
9359
|
+
respond(res, 503, { error: "broker not initialised" });
|
|
9360
|
+
return;
|
|
9361
|
+
}
|
|
9362
|
+
const id = decodeURIComponent(url.pathname.slice("/v1/memory/".length));
|
|
9363
|
+
if (!id) {
|
|
9364
|
+
respond(res, 400, { error: "missing memory id" });
|
|
9365
|
+
return;
|
|
9366
|
+
}
|
|
9367
|
+
const requested = url.searchParams.get("mesh");
|
|
9368
|
+
let chosen = requested;
|
|
9369
|
+
if (!chosen && opts.brokers.size === 1)
|
|
9370
|
+
chosen = opts.brokers.keys().next().value;
|
|
9371
|
+
if (!chosen) {
|
|
9372
|
+
respond(res, 400, { error: "mesh_required", attached: [...opts.brokers.keys()] });
|
|
9373
|
+
return;
|
|
9374
|
+
}
|
|
9375
|
+
const broker = opts.brokers.get(chosen);
|
|
9376
|
+
if (!broker) {
|
|
9377
|
+
respond(res, 404, { error: "mesh_not_attached", mesh: chosen });
|
|
9378
|
+
return;
|
|
9379
|
+
}
|
|
9380
|
+
broker.forget(id);
|
|
9381
|
+
respond(res, 200, { ok: true, id, mesh: chosen });
|
|
9382
|
+
return;
|
|
9383
|
+
}
|
|
9048
9384
|
if (req.method === "GET" && url.pathname === "/v1/skills") {
|
|
9049
9385
|
if (!opts.brokers || opts.brokers.size === 0) {
|
|
9050
9386
|
respond(res, 503, { error: "broker not initialised" });
|
|
@@ -9462,6 +9798,10 @@ class DaemonBrokerClient {
|
|
|
9462
9798
|
peerListResolvers = new Map;
|
|
9463
9799
|
skillListResolvers = new Map;
|
|
9464
9800
|
skillDataResolvers = new Map;
|
|
9801
|
+
stateGetResolvers = new Map;
|
|
9802
|
+
stateListResolvers = new Map;
|
|
9803
|
+
memoryStoreResolvers = new Map;
|
|
9804
|
+
memoryRecallResolvers = new Map;
|
|
9465
9805
|
sessionPubkey = null;
|
|
9466
9806
|
sessionSecretKey = null;
|
|
9467
9807
|
opens = [];
|
|
@@ -9602,6 +9942,46 @@ class DaemonBrokerClient {
|
|
|
9602
9942
|
}
|
|
9603
9943
|
return;
|
|
9604
9944
|
}
|
|
9945
|
+
if (msg.type === "state_value" || msg.type === "state_data") {
|
|
9946
|
+
const reqId = String(msg._reqId ?? "");
|
|
9947
|
+
const pending = this.stateGetResolvers.get(reqId);
|
|
9948
|
+
if (pending) {
|
|
9949
|
+
this.stateGetResolvers.delete(reqId);
|
|
9950
|
+
clearTimeout(pending.timer);
|
|
9951
|
+
pending.resolve(msg.state ?? msg.row ?? null);
|
|
9952
|
+
}
|
|
9953
|
+
return;
|
|
9954
|
+
}
|
|
9955
|
+
if (msg.type === "state_list") {
|
|
9956
|
+
const reqId = String(msg._reqId ?? "");
|
|
9957
|
+
const pending = this.stateListResolvers.get(reqId);
|
|
9958
|
+
if (pending) {
|
|
9959
|
+
this.stateListResolvers.delete(reqId);
|
|
9960
|
+
clearTimeout(pending.timer);
|
|
9961
|
+
pending.resolve(Array.isArray(msg.entries) ? msg.entries : []);
|
|
9962
|
+
}
|
|
9963
|
+
return;
|
|
9964
|
+
}
|
|
9965
|
+
if (msg.type === "memory_stored") {
|
|
9966
|
+
const reqId = String(msg._reqId ?? "");
|
|
9967
|
+
const pending = this.memoryStoreResolvers.get(reqId);
|
|
9968
|
+
if (pending) {
|
|
9969
|
+
this.memoryStoreResolvers.delete(reqId);
|
|
9970
|
+
clearTimeout(pending.timer);
|
|
9971
|
+
pending.resolve(typeof msg.memoryId === "string" ? msg.memoryId : null);
|
|
9972
|
+
}
|
|
9973
|
+
return;
|
|
9974
|
+
}
|
|
9975
|
+
if (msg.type === "memory_recall_result") {
|
|
9976
|
+
const reqId = String(msg._reqId ?? "");
|
|
9977
|
+
const pending = this.memoryRecallResolvers.get(reqId);
|
|
9978
|
+
if (pending) {
|
|
9979
|
+
this.memoryRecallResolvers.delete(reqId);
|
|
9980
|
+
clearTimeout(pending.timer);
|
|
9981
|
+
pending.resolve(Array.isArray(msg.matches) ? msg.matches : []);
|
|
9982
|
+
}
|
|
9983
|
+
return;
|
|
9984
|
+
}
|
|
9605
9985
|
if (msg.type === "push" || msg.type === "inbound") {
|
|
9606
9986
|
this.opts.onPush?.(msg);
|
|
9607
9987
|
return;
|
|
@@ -9722,6 +10102,96 @@ class DaemonBrokerClient {
|
|
|
9722
10102
|
}
|
|
9723
10103
|
});
|
|
9724
10104
|
}
|
|
10105
|
+
async getState(key, timeoutMs = 5000) {
|
|
10106
|
+
if (this._status !== "open" || !this.ws)
|
|
10107
|
+
return null;
|
|
10108
|
+
return new Promise((resolve) => {
|
|
10109
|
+
const reqId = `sg-${++this.reqCounter}`;
|
|
10110
|
+
const timer = setTimeout(() => {
|
|
10111
|
+
if (this.stateGetResolvers.delete(reqId))
|
|
10112
|
+
resolve(null);
|
|
10113
|
+
}, timeoutMs);
|
|
10114
|
+
this.stateGetResolvers.set(reqId, { resolve, timer });
|
|
10115
|
+
try {
|
|
10116
|
+
this.ws.send(JSON.stringify({ type: "get_state", key, _reqId: reqId }));
|
|
10117
|
+
} catch {
|
|
10118
|
+
this.stateGetResolvers.delete(reqId);
|
|
10119
|
+
clearTimeout(timer);
|
|
10120
|
+
resolve(null);
|
|
10121
|
+
}
|
|
10122
|
+
});
|
|
10123
|
+
}
|
|
10124
|
+
async listState(timeoutMs = 5000) {
|
|
10125
|
+
if (this._status !== "open" || !this.ws)
|
|
10126
|
+
return [];
|
|
10127
|
+
return new Promise((resolve) => {
|
|
10128
|
+
const reqId = `sl-${++this.reqCounter}`;
|
|
10129
|
+
const timer = setTimeout(() => {
|
|
10130
|
+
if (this.stateListResolvers.delete(reqId))
|
|
10131
|
+
resolve([]);
|
|
10132
|
+
}, timeoutMs);
|
|
10133
|
+
this.stateListResolvers.set(reqId, { resolve, timer });
|
|
10134
|
+
try {
|
|
10135
|
+
this.ws.send(JSON.stringify({ type: "list_state", _reqId: reqId }));
|
|
10136
|
+
} catch {
|
|
10137
|
+
this.stateListResolvers.delete(reqId);
|
|
10138
|
+
clearTimeout(timer);
|
|
10139
|
+
resolve([]);
|
|
10140
|
+
}
|
|
10141
|
+
});
|
|
10142
|
+
}
|
|
10143
|
+
setState(key, value) {
|
|
10144
|
+
if (this._status !== "open" || !this.ws)
|
|
10145
|
+
return;
|
|
10146
|
+
try {
|
|
10147
|
+
this.ws.send(JSON.stringify({ type: "set_state", key, value }));
|
|
10148
|
+
} catch {}
|
|
10149
|
+
}
|
|
10150
|
+
async remember(content, tags, timeoutMs = 5000) {
|
|
10151
|
+
if (this._status !== "open" || !this.ws)
|
|
10152
|
+
return null;
|
|
10153
|
+
return new Promise((resolve) => {
|
|
10154
|
+
const reqId = `mr-${++this.reqCounter}`;
|
|
10155
|
+
const timer = setTimeout(() => {
|
|
10156
|
+
if (this.memoryStoreResolvers.delete(reqId))
|
|
10157
|
+
resolve(null);
|
|
10158
|
+
}, timeoutMs);
|
|
10159
|
+
this.memoryStoreResolvers.set(reqId, { resolve, timer });
|
|
10160
|
+
try {
|
|
10161
|
+
this.ws.send(JSON.stringify({ type: "remember", content, tags, _reqId: reqId }));
|
|
10162
|
+
} catch {
|
|
10163
|
+
this.memoryStoreResolvers.delete(reqId);
|
|
10164
|
+
clearTimeout(timer);
|
|
10165
|
+
resolve(null);
|
|
10166
|
+
}
|
|
10167
|
+
});
|
|
10168
|
+
}
|
|
10169
|
+
async recall(query, timeoutMs = 5000) {
|
|
10170
|
+
if (this._status !== "open" || !this.ws)
|
|
10171
|
+
return [];
|
|
10172
|
+
return new Promise((resolve) => {
|
|
10173
|
+
const reqId = `mc-${++this.reqCounter}`;
|
|
10174
|
+
const timer = setTimeout(() => {
|
|
10175
|
+
if (this.memoryRecallResolvers.delete(reqId))
|
|
10176
|
+
resolve([]);
|
|
10177
|
+
}, timeoutMs);
|
|
10178
|
+
this.memoryRecallResolvers.set(reqId, { resolve, timer });
|
|
10179
|
+
try {
|
|
10180
|
+
this.ws.send(JSON.stringify({ type: "recall", query, _reqId: reqId }));
|
|
10181
|
+
} catch {
|
|
10182
|
+
this.memoryRecallResolvers.delete(reqId);
|
|
10183
|
+
clearTimeout(timer);
|
|
10184
|
+
resolve([]);
|
|
10185
|
+
}
|
|
10186
|
+
});
|
|
10187
|
+
}
|
|
10188
|
+
forget(memoryId) {
|
|
10189
|
+
if (this._status !== "open" || !this.ws)
|
|
10190
|
+
return;
|
|
10191
|
+
try {
|
|
10192
|
+
this.ws.send(JSON.stringify({ type: "forget", memoryId }));
|
|
10193
|
+
} catch {}
|
|
10194
|
+
}
|
|
9725
10195
|
setProfile(profile) {
|
|
9726
10196
|
if (this._status !== "open" || !this.ws)
|
|
9727
10197
|
return;
|
|
@@ -17543,7 +18013,7 @@ USAGE
|
|
|
17543
18013
|
claudemesh <invite-url> join a mesh, then launch
|
|
17544
18014
|
claudemesh launch --name <n> --join <url> join + launch in one step
|
|
17545
18015
|
|
|
17546
|
-
Mesh
|
|
18016
|
+
Mesh (alias: "workspace" — claudemesh workspace <verb> mirrors each)
|
|
17547
18017
|
claudemesh create <name> create a new mesh
|
|
17548
18018
|
claudemesh join <url> join a mesh (accepts short /i/ or long /join/ link)
|
|
17549
18019
|
claudemesh launch [slug] launch Claude Code on a mesh (alias: connect)
|
|
@@ -17817,6 +18287,47 @@ async function main() {
|
|
|
17817
18287
|
process.exit(await invite2(positionals[0], { mesh: flags.mesh, json: !!flags.json }));
|
|
17818
18288
|
break;
|
|
17819
18289
|
}
|
|
18290
|
+
case "workspace": {
|
|
18291
|
+
const sub = positionals[0];
|
|
18292
|
+
if (!sub || sub === "launch" || sub === "connect" || sub === "open") {
|
|
18293
|
+
const { runLaunch: runLaunch2 } = await Promise.resolve().then(() => (init_launch(), exports_launch));
|
|
18294
|
+
await runLaunch2({
|
|
18295
|
+
mesh: positionals[1] ?? flags.mesh,
|
|
18296
|
+
name: flags.name,
|
|
18297
|
+
join: flags.join,
|
|
18298
|
+
yes: !!flags.y || !!flags.yes,
|
|
18299
|
+
resume: flags.resume
|
|
18300
|
+
}, process.argv.slice(2));
|
|
18301
|
+
} else if (sub === "list" || sub === "ls") {
|
|
18302
|
+
const { runList: runList2 } = await Promise.resolve().then(() => (init_list2(), exports_list));
|
|
18303
|
+
await runList2();
|
|
18304
|
+
} else if (sub === "info") {
|
|
18305
|
+
const { runInfo: runInfo2 } = await Promise.resolve().then(() => (init_info2(), exports_info));
|
|
18306
|
+
await runInfo2({});
|
|
18307
|
+
} else if (sub === "create" || sub === "new") {
|
|
18308
|
+
const { newMesh: newMesh2 } = await Promise.resolve().then(() => (init_new(), exports_new));
|
|
18309
|
+
process.exit(await newMesh2(positionals[1] ?? "", { json: !!flags.json }));
|
|
18310
|
+
} else if (sub === "join" || sub === "add") {
|
|
18311
|
+
const { runJoin: runJoin2 } = await Promise.resolve().then(() => (init_join2(), exports_join));
|
|
18312
|
+
await runJoin2(positionals.slice(1));
|
|
18313
|
+
} else if (sub === "delete" || sub === "rm") {
|
|
18314
|
+
const { deleteMesh: deleteMesh2 } = await Promise.resolve().then(() => (init_delete_mesh(), exports_delete_mesh));
|
|
18315
|
+
process.exit(await deleteMesh2(positionals[1] ?? "", { yes: !!flags.y || !!flags.yes }));
|
|
18316
|
+
} else if (sub === "rename") {
|
|
18317
|
+
const { rename: rename2 } = await Promise.resolve().then(() => (init_rename2(), exports_rename));
|
|
18318
|
+
process.exit(await rename2(positionals[1] ?? "", positionals[2] ?? ""));
|
|
18319
|
+
} else if (sub === "share" || sub === "invite") {
|
|
18320
|
+
const { invite: invite2 } = await Promise.resolve().then(() => (init_invite(), exports_invite));
|
|
18321
|
+
process.exit(await invite2(positionals[1], { mesh: flags.mesh, json: !!flags.json }));
|
|
18322
|
+
} else if (sub === "overview") {
|
|
18323
|
+
const { runMe: runMe2 } = await Promise.resolve().then(() => (init_me(), exports_me));
|
|
18324
|
+
process.exit(await runMe2({ mesh: flags.mesh, json: !!flags.json }));
|
|
18325
|
+
} else {
|
|
18326
|
+
console.error("Usage: claudemesh workspace <list|info|create|join|delete|rename|share|launch|overview>");
|
|
18327
|
+
process.exit(EXIT.INVALID_ARGS);
|
|
18328
|
+
}
|
|
18329
|
+
break;
|
|
18330
|
+
}
|
|
17820
18331
|
case "disconnect": {
|
|
17821
18332
|
const { runDisconnect: runDisconnect2 } = await Promise.resolve().then(() => (init_kick(), exports_kick));
|
|
17822
18333
|
process.exit(await runDisconnect2(positionals[0], { mesh: flags.mesh, stale: flags.stale, all: !!flags.all }));
|
|
@@ -18662,4 +19173,4 @@ main().catch((err) => {
|
|
|
18662
19173
|
process.exit(EXIT.INTERNAL_ERROR);
|
|
18663
19174
|
});
|
|
18664
19175
|
|
|
18665
|
-
//# debugId=
|
|
19176
|
+
//# debugId=5CE8252722B33A8D64756E2164756E21
|