claudemesh-cli 1.15.0 → 1.17.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 +547 -402
- package/dist/entrypoints/cli.js.map +8 -8
- 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
|
@@ -88,7 +88,7 @@ __export(exports_urls, {
|
|
|
88
88
|
VERSION: () => VERSION,
|
|
89
89
|
URLS: () => URLS
|
|
90
90
|
});
|
|
91
|
-
var URLS, VERSION = "1.
|
|
91
|
+
var URLS, VERSION = "1.17.0", env;
|
|
92
92
|
var init_urls = __esm(() => {
|
|
93
93
|
URLS = {
|
|
94
94
|
BROKER: process.env.CLAUDEMESH_BROKER_URL ?? "wss://ic.claudemesh.com/ws",
|
|
@@ -6698,18 +6698,27 @@ function projectFields(record, fields) {
|
|
|
6698
6698
|
return out;
|
|
6699
6699
|
}
|
|
6700
6700
|
async function listPeersForMesh(slug) {
|
|
6701
|
+
const config = readConfig();
|
|
6702
|
+
const joined = config.meshes.find((m) => m.slug === slug);
|
|
6703
|
+
const selfMemberPubkey = joined?.pubkey ?? null;
|
|
6701
6704
|
const bridged = await tryBridge(slug, "peers");
|
|
6702
6705
|
if (bridged && bridged.ok) {
|
|
6703
|
-
|
|
6706
|
+
const peers = bridged.result;
|
|
6707
|
+
return peers.map((p) => annotateSelf(p, selfMemberPubkey, null));
|
|
6704
6708
|
}
|
|
6705
6709
|
let result = [];
|
|
6706
6710
|
await withMesh({ meshSlug: slug }, async (client) => {
|
|
6707
6711
|
const all = await client.listPeers();
|
|
6708
|
-
const
|
|
6709
|
-
result =
|
|
6712
|
+
const selfSessionPubkey = client.getSessionPubkey();
|
|
6713
|
+
result = all.map((p) => annotateSelf(p, selfMemberPubkey, selfSessionPubkey));
|
|
6710
6714
|
});
|
|
6711
6715
|
return result;
|
|
6712
6716
|
}
|
|
6717
|
+
function annotateSelf(peer, selfMemberPubkey, selfSessionPubkey) {
|
|
6718
|
+
const isSelf = !!(selfMemberPubkey && peer.memberPubkey && peer.memberPubkey === selfMemberPubkey);
|
|
6719
|
+
const isThisSession = !!(isSelf && selfSessionPubkey && peer.pubkey === selfSessionPubkey);
|
|
6720
|
+
return { ...peer, isSelf, isThisSession };
|
|
6721
|
+
}
|
|
6713
6722
|
async function runPeers(flags) {
|
|
6714
6723
|
const config = readConfig();
|
|
6715
6724
|
const slugs = flags.mesh ? [flags.mesh] : config.meshes.map((m) => m.slug);
|
|
@@ -6748,7 +6757,8 @@ async function runPeers(flags) {
|
|
|
6748
6757
|
const metaStr = meta.length ? dim(` (${meta.join(", ")})`) : "";
|
|
6749
6758
|
const summary = p.summary ? dim(` — ${p.summary}`) : "";
|
|
6750
6759
|
const pubkeyTag = dim(` · ${p.pubkey.slice(0, 16)}…`);
|
|
6751
|
-
|
|
6760
|
+
const selfTag = p.isThisSession ? dim(" ") + yellow("(this session)") : p.isSelf ? dim(" ") + yellow("(your other session)") : "";
|
|
6761
|
+
render.info(`${statusDot} ${name}${selfTag}${groups}${metaStr}${pubkeyTag}${summary}`);
|
|
6752
6762
|
if (p.cwd)
|
|
6753
6763
|
render.info(dim(` cwd: ${p.cwd}`));
|
|
6754
6764
|
}
|
|
@@ -6786,6 +6796,14 @@ async function runSend(flags, to, message) {
|
|
|
6786
6796
|
const priority = flags.priority === "now" ? "now" : flags.priority === "low" ? "low" : "next";
|
|
6787
6797
|
const config = readConfig();
|
|
6788
6798
|
const meshSlug = flags.mesh ?? (config.meshes.length === 1 ? config.meshes[0].slug : null);
|
|
6799
|
+
if (!flags.self && meshSlug) {
|
|
6800
|
+
const joined = config.meshes.find((m) => m.slug === meshSlug);
|
|
6801
|
+
if (joined && /^[0-9a-f]{64}$/i.test(to) && to.toLowerCase() === joined.pubkey.toLowerCase()) {
|
|
6802
|
+
render.err(`Target "${to.slice(0, 16)}…" is your own member pubkey on mesh "${meshSlug}".`);
|
|
6803
|
+
render.hint("Pass --self to message a sibling session of your own member, or pick a different peer's pubkey.");
|
|
6804
|
+
process.exit(1);
|
|
6805
|
+
}
|
|
6806
|
+
}
|
|
6789
6807
|
if (meshSlug) {
|
|
6790
6808
|
const bridged = await tryBridge(meshSlug, "send", { to, message, priority });
|
|
6791
6809
|
if (bridged !== null) {
|
|
@@ -6950,10 +6968,420 @@ async function runStateList(flags) {
|
|
|
6950
6968
|
}
|
|
6951
6969
|
});
|
|
6952
6970
|
}
|
|
6953
|
-
var init_state = __esm(() => {
|
|
6954
|
-
init_connect();
|
|
6971
|
+
var init_state = __esm(() => {
|
|
6972
|
+
init_connect();
|
|
6973
|
+
init_render();
|
|
6974
|
+
init_styles();
|
|
6975
|
+
});
|
|
6976
|
+
|
|
6977
|
+
// src/services/api/with-rest-key.ts
|
|
6978
|
+
async function withRestKey(opts, fn) {
|
|
6979
|
+
return withMesh({ meshSlug: opts.meshSlug ?? null }, async (client, mesh) => {
|
|
6980
|
+
const result = await client.apiKeyCreate({
|
|
6981
|
+
label: `cli-${opts.purpose ?? "rest"}-${process.pid}`,
|
|
6982
|
+
capabilities: opts.capabilities ?? ["read"],
|
|
6983
|
+
topicScopes: opts.topicScopes ?? undefined,
|
|
6984
|
+
expiresAt: new Date(Date.now() + 5 * 60 * 1000).toISOString()
|
|
6985
|
+
});
|
|
6986
|
+
if (!result || !result.secret) {
|
|
6987
|
+
throw new Error("apikey mint failed — broker did not return a secret");
|
|
6988
|
+
}
|
|
6989
|
+
try {
|
|
6990
|
+
return await fn({
|
|
6991
|
+
secret: result.secret,
|
|
6992
|
+
meshId: mesh.meshId,
|
|
6993
|
+
meshSlug: mesh.slug,
|
|
6994
|
+
client,
|
|
6995
|
+
mesh
|
|
6996
|
+
});
|
|
6997
|
+
} finally {
|
|
6998
|
+
try {
|
|
6999
|
+
await client.apiKeyRevoke(result.id);
|
|
7000
|
+
} catch {}
|
|
7001
|
+
}
|
|
7002
|
+
});
|
|
7003
|
+
}
|
|
7004
|
+
var init_with_rest_key = __esm(() => {
|
|
7005
|
+
init_connect();
|
|
7006
|
+
});
|
|
7007
|
+
|
|
7008
|
+
// src/commands/me.ts
|
|
7009
|
+
var exports_me = {};
|
|
7010
|
+
__export(exports_me, {
|
|
7011
|
+
runMeTopics: () => runMeTopics,
|
|
7012
|
+
runMeTasks: () => runMeTasks,
|
|
7013
|
+
runMeState: () => runMeState,
|
|
7014
|
+
runMeSearch: () => runMeSearch,
|
|
7015
|
+
runMeNotifications: () => runMeNotifications,
|
|
7016
|
+
runMeMemory: () => runMeMemory,
|
|
7017
|
+
runMeActivity: () => runMeActivity,
|
|
7018
|
+
runMe: () => runMe
|
|
7019
|
+
});
|
|
7020
|
+
function resolveMeshForMint(explicit) {
|
|
7021
|
+
if (explicit)
|
|
7022
|
+
return explicit;
|
|
7023
|
+
const cfg = readConfig();
|
|
7024
|
+
return cfg.meshes[0]?.slug ?? null;
|
|
7025
|
+
}
|
|
7026
|
+
async function runMe(flags) {
|
|
7027
|
+
return withRestKey({
|
|
7028
|
+
meshSlug: resolveMeshForMint(flags.mesh),
|
|
7029
|
+
purpose: "workspace-overview",
|
|
7030
|
+
capabilities: ["read"]
|
|
7031
|
+
}, async ({ secret }) => {
|
|
7032
|
+
const ws = await request({
|
|
7033
|
+
path: "/api/v1/me/workspace",
|
|
7034
|
+
token: secret
|
|
7035
|
+
});
|
|
7036
|
+
if (flags.json) {
|
|
7037
|
+
console.log(JSON.stringify(ws, null, 2));
|
|
7038
|
+
return EXIT.SUCCESS;
|
|
7039
|
+
}
|
|
7040
|
+
render.section(`${clay("workspace")} — ${bold(ws.userId.slice(0, 8))} ${dim(`· ${ws.totals.meshes} mesh${ws.totals.meshes === 1 ? "" : "es"}`)}`);
|
|
7041
|
+
const totalsLine = [
|
|
7042
|
+
`${green(String(ws.totals.online))}/${ws.totals.peers} online`,
|
|
7043
|
+
`${ws.totals.topics} topic${ws.totals.topics === 1 ? "" : "s"}`,
|
|
7044
|
+
ws.totals.unreadMentions > 0 ? yellow(`${ws.totals.unreadMentions} unread @you`) : dim("0 unread @you")
|
|
7045
|
+
].join(dim(" · "));
|
|
7046
|
+
process.stdout.write(" " + totalsLine + `
|
|
7047
|
+
|
|
7048
|
+
`);
|
|
7049
|
+
if (ws.meshes.length === 0) {
|
|
7050
|
+
process.stdout.write(dim(" no meshes joined — run `claudemesh new` or accept an invite\n"));
|
|
7051
|
+
return EXIT.SUCCESS;
|
|
7052
|
+
}
|
|
7053
|
+
const slugWidth = Math.max(...ws.meshes.map((m) => m.slug.length), 8);
|
|
7054
|
+
for (const m of ws.meshes) {
|
|
7055
|
+
const slug = cyan(m.slug.padEnd(slugWidth));
|
|
7056
|
+
const peers = `${m.online}/${m.peers}`;
|
|
7057
|
+
const role = dim(m.myRole);
|
|
7058
|
+
const unread = m.unreadMentions > 0 ? " " + yellow(`${m.unreadMentions} @you`) : "";
|
|
7059
|
+
process.stdout.write(` ${slug} ${peers.padStart(5)} online ${dim(String(m.topics).padStart(2) + " topics")} ${role}${unread}
|
|
7060
|
+
`);
|
|
7061
|
+
}
|
|
7062
|
+
return EXIT.SUCCESS;
|
|
7063
|
+
});
|
|
7064
|
+
}
|
|
7065
|
+
async function runMeTopics(flags) {
|
|
7066
|
+
return withRestKey({
|
|
7067
|
+
meshSlug: resolveMeshForMint(flags.mesh),
|
|
7068
|
+
purpose: "workspace-topics",
|
|
7069
|
+
capabilities: ["read"]
|
|
7070
|
+
}, async ({ secret }) => {
|
|
7071
|
+
const ws = await request({
|
|
7072
|
+
path: "/api/v1/me/topics",
|
|
7073
|
+
token: secret
|
|
7074
|
+
});
|
|
7075
|
+
const visible = flags.unread ? ws.topics.filter((t) => t.unread > 0) : ws.topics;
|
|
7076
|
+
if (flags.json) {
|
|
7077
|
+
console.log(JSON.stringify({ topics: visible, totals: ws.totals }, null, 2));
|
|
7078
|
+
return EXIT.SUCCESS;
|
|
7079
|
+
}
|
|
7080
|
+
render.section(`${clay("topics")} — ${ws.totals.topics} across all meshes ${dim(ws.totals.unread > 0 ? `· ${ws.totals.unread} unread` : "· all read")}`);
|
|
7081
|
+
if (visible.length === 0) {
|
|
7082
|
+
process.stdout.write(dim(flags.unread ? ` no unread topics
|
|
7083
|
+
` : " no topics — run `claudemesh topic create #general`\n"));
|
|
7084
|
+
return EXIT.SUCCESS;
|
|
7085
|
+
}
|
|
7086
|
+
const slugWidth = Math.max(...visible.map((t) => t.meshSlug.length), 6);
|
|
7087
|
+
const nameWidth = Math.max(...visible.map((t) => t.name.length), 8);
|
|
7088
|
+
for (const t of visible) {
|
|
7089
|
+
const slug = dim(t.meshSlug.padEnd(slugWidth));
|
|
7090
|
+
const name = cyan(t.name.padEnd(nameWidth));
|
|
7091
|
+
const unread = t.unread > 0 ? yellow(`${t.unread} unread`.padStart(10)) : dim("·".padStart(10));
|
|
7092
|
+
const last = t.lastMessageAt ? dim(formatRelativeTime(t.lastMessageAt)) : dim("never");
|
|
7093
|
+
process.stdout.write(` ${slug} ${name} ${unread} ${last}
|
|
7094
|
+
`);
|
|
7095
|
+
}
|
|
7096
|
+
return EXIT.SUCCESS;
|
|
7097
|
+
});
|
|
7098
|
+
}
|
|
7099
|
+
async function runMeNotifications(flags) {
|
|
7100
|
+
return withRestKey({
|
|
7101
|
+
meshSlug: resolveMeshForMint(flags.mesh),
|
|
7102
|
+
purpose: "workspace-notifications",
|
|
7103
|
+
capabilities: ["read"]
|
|
7104
|
+
}, async ({ secret }) => {
|
|
7105
|
+
const params = new URLSearchParams;
|
|
7106
|
+
if (flags.all)
|
|
7107
|
+
params.set("include", "all");
|
|
7108
|
+
if (flags.since)
|
|
7109
|
+
params.set("since", flags.since);
|
|
7110
|
+
const path = "/api/v1/me/notifications" + (params.toString() ? `?${params.toString()}` : "");
|
|
7111
|
+
const ws = await request({
|
|
7112
|
+
path,
|
|
7113
|
+
token: secret
|
|
7114
|
+
});
|
|
7115
|
+
if (flags.json) {
|
|
7116
|
+
console.log(JSON.stringify(ws, null, 2));
|
|
7117
|
+
return EXIT.SUCCESS;
|
|
7118
|
+
}
|
|
7119
|
+
const headerLabel = flags.all ? "@-mentions (all)" : "@-mentions (unread)";
|
|
7120
|
+
render.section(`${clay(headerLabel)} — ${ws.totals.total} ${dim(ws.totals.unread > 0 ? `· ${ws.totals.unread} unread` : "· nothing pending")}`);
|
|
7121
|
+
if (ws.notifications.length === 0) {
|
|
7122
|
+
process.stdout.write(dim(flags.all ? ` no @-mentions in window
|
|
7123
|
+
` : ` inbox zero — nothing waiting
|
|
7124
|
+
`));
|
|
7125
|
+
return EXIT.SUCCESS;
|
|
7126
|
+
}
|
|
7127
|
+
const slugWidth = Math.max(...ws.notifications.map((n) => n.meshSlug.length), 6);
|
|
7128
|
+
for (const n of ws.notifications) {
|
|
7129
|
+
const slug = dim(n.meshSlug.padEnd(slugWidth));
|
|
7130
|
+
const topic = cyan(`#${n.topicName}`);
|
|
7131
|
+
const sender = n.senderName ? `from ${n.senderName}` : "from ?";
|
|
7132
|
+
const ago = formatRelativeTime(n.createdAt);
|
|
7133
|
+
const dot = n.read ? dim("·") : yellow("●");
|
|
7134
|
+
const snippet = n.snippet ?? (n.ciphertext ? dim("[encrypted]") : dim("[empty]"));
|
|
7135
|
+
process.stdout.write(` ${dot} ${slug} ${topic} ${dim(sender)} ${dim(ago)}
|
|
7136
|
+
` + ` ${snippet.length > 200 ? snippet.slice(0, 200) + "…" : snippet}
|
|
7137
|
+
`);
|
|
7138
|
+
}
|
|
7139
|
+
return EXIT.SUCCESS;
|
|
7140
|
+
});
|
|
7141
|
+
}
|
|
7142
|
+
async function runMeActivity(flags) {
|
|
7143
|
+
return withRestKey({
|
|
7144
|
+
meshSlug: resolveMeshForMint(flags.mesh),
|
|
7145
|
+
purpose: "workspace-activity",
|
|
7146
|
+
capabilities: ["read"]
|
|
7147
|
+
}, async ({ secret }) => {
|
|
7148
|
+
const params = new URLSearchParams;
|
|
7149
|
+
if (flags.since)
|
|
7150
|
+
params.set("since", flags.since);
|
|
7151
|
+
const path = "/api/v1/me/activity" + (params.toString() ? `?${params.toString()}` : "");
|
|
7152
|
+
const ws = await request({
|
|
7153
|
+
path,
|
|
7154
|
+
token: secret
|
|
7155
|
+
});
|
|
7156
|
+
if (flags.json) {
|
|
7157
|
+
console.log(JSON.stringify(ws, null, 2));
|
|
7158
|
+
return EXIT.SUCCESS;
|
|
7159
|
+
}
|
|
7160
|
+
render.section(`${clay("activity")} — ${ws.totals.events} ${dim(flags.since ? `since ${flags.since}` : "in the last 24h")}`);
|
|
7161
|
+
if (ws.activity.length === 0) {
|
|
7162
|
+
process.stdout.write(dim(` quiet — no activity in window
|
|
7163
|
+
`));
|
|
7164
|
+
return EXIT.SUCCESS;
|
|
7165
|
+
}
|
|
7166
|
+
const slugWidth = Math.max(...ws.activity.map((a) => a.meshSlug.length), 6);
|
|
7167
|
+
for (const a of ws.activity) {
|
|
7168
|
+
const slug = dim(a.meshSlug.padEnd(slugWidth));
|
|
7169
|
+
const topic = cyan(`#${a.topicName}`);
|
|
7170
|
+
const sender = a.senderName ?? "?";
|
|
7171
|
+
const ago = formatRelativeTime(a.createdAt);
|
|
7172
|
+
const snippet = a.snippet ?? (a.ciphertext ? dim("[encrypted]") : dim("[empty]"));
|
|
7173
|
+
process.stdout.write(` ${slug} ${topic} ${dim(sender + " ·")} ${dim(ago)}
|
|
7174
|
+
` + ` ${snippet.length > 200 ? snippet.slice(0, 200) + "…" : snippet}
|
|
7175
|
+
`);
|
|
7176
|
+
}
|
|
7177
|
+
return EXIT.SUCCESS;
|
|
7178
|
+
});
|
|
7179
|
+
}
|
|
7180
|
+
async function runMeSearch(flags) {
|
|
7181
|
+
if (!flags.query || flags.query.length < 2) {
|
|
7182
|
+
process.stderr.write(`Usage: claudemesh me search <query> (min 2 chars)
|
|
7183
|
+
`);
|
|
7184
|
+
return EXIT.INVALID_ARGS;
|
|
7185
|
+
}
|
|
7186
|
+
return withRestKey({
|
|
7187
|
+
meshSlug: resolveMeshForMint(flags.mesh),
|
|
7188
|
+
purpose: "workspace-search",
|
|
7189
|
+
capabilities: ["read"]
|
|
7190
|
+
}, async ({ secret }) => {
|
|
7191
|
+
const params = new URLSearchParams({ q: flags.query });
|
|
7192
|
+
const ws = await request({
|
|
7193
|
+
path: `/api/v1/me/search?${params.toString()}`,
|
|
7194
|
+
token: secret
|
|
7195
|
+
});
|
|
7196
|
+
if (flags.json) {
|
|
7197
|
+
console.log(JSON.stringify(ws, null, 2));
|
|
7198
|
+
return EXIT.SUCCESS;
|
|
7199
|
+
}
|
|
7200
|
+
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"}`)}`);
|
|
7201
|
+
if (ws.topics.length === 0 && ws.messages.length === 0) {
|
|
7202
|
+
process.stdout.write(dim(` no matches
|
|
7203
|
+
`));
|
|
7204
|
+
return EXIT.SUCCESS;
|
|
7205
|
+
}
|
|
7206
|
+
if (ws.topics.length > 0) {
|
|
7207
|
+
process.stdout.write(dim(`
|
|
7208
|
+
topics
|
|
7209
|
+
`));
|
|
7210
|
+
const slugWidth = Math.max(...ws.topics.map((t) => t.meshSlug.length), 6);
|
|
7211
|
+
for (const t of ws.topics) {
|
|
7212
|
+
const slug = dim(t.meshSlug.padEnd(slugWidth));
|
|
7213
|
+
const name = cyan(`#${t.name}`);
|
|
7214
|
+
const desc = t.description ? dim(` — ${t.description}`) : "";
|
|
7215
|
+
process.stdout.write(` ${slug} ${name}${desc}
|
|
7216
|
+
`);
|
|
7217
|
+
}
|
|
7218
|
+
}
|
|
7219
|
+
if (ws.messages.length > 0) {
|
|
7220
|
+
process.stdout.write(dim(`
|
|
7221
|
+
messages
|
|
7222
|
+
`));
|
|
7223
|
+
const slugWidth = Math.max(...ws.messages.map((m) => m.meshSlug.length), 6);
|
|
7224
|
+
for (const m of ws.messages) {
|
|
7225
|
+
const slug = dim(m.meshSlug.padEnd(slugWidth));
|
|
7226
|
+
const topic = cyan(`#${m.topicName}`);
|
|
7227
|
+
const sender = m.senderName;
|
|
7228
|
+
const ago = formatRelativeTime(m.createdAt);
|
|
7229
|
+
const snippet = m.snippet ?? (m.bodyVersion === 2 ? dim("[encrypted — open the topic to decrypt]") : dim("[empty]"));
|
|
7230
|
+
const highlighted = m.snippet ? highlightMatch(snippet, flags.query) : snippet;
|
|
7231
|
+
process.stdout.write(` ${slug} ${topic} ${dim(sender + " ·")} ${dim(ago)}
|
|
7232
|
+
` + ` ${highlighted}
|
|
7233
|
+
`);
|
|
7234
|
+
}
|
|
7235
|
+
}
|
|
7236
|
+
return EXIT.SUCCESS;
|
|
7237
|
+
});
|
|
7238
|
+
}
|
|
7239
|
+
function highlightMatch(text, query) {
|
|
7240
|
+
if (!query)
|
|
7241
|
+
return text;
|
|
7242
|
+
const idx = text.toLowerCase().indexOf(query.toLowerCase());
|
|
7243
|
+
if (idx === -1)
|
|
7244
|
+
return text;
|
|
7245
|
+
const before = text.slice(0, idx);
|
|
7246
|
+
const match = text.slice(idx, idx + query.length);
|
|
7247
|
+
const after = text.slice(idx + query.length);
|
|
7248
|
+
return `${before}${yellow(match)}${after}`;
|
|
7249
|
+
}
|
|
7250
|
+
async function runMeTasks(flags) {
|
|
7251
|
+
return withRestKey({
|
|
7252
|
+
meshSlug: resolveMeshForMint(flags.mesh),
|
|
7253
|
+
purpose: "workspace-tasks",
|
|
7254
|
+
capabilities: ["read"]
|
|
7255
|
+
}, async ({ secret }) => {
|
|
7256
|
+
const params = new URLSearchParams;
|
|
7257
|
+
if (flags.status)
|
|
7258
|
+
params.set("status", flags.status);
|
|
7259
|
+
const path = "/api/v1/me/tasks" + (params.toString() ? `?${params.toString()}` : "");
|
|
7260
|
+
const ws = await request({
|
|
7261
|
+
path,
|
|
7262
|
+
token: secret
|
|
7263
|
+
});
|
|
7264
|
+
if (flags.json) {
|
|
7265
|
+
console.log(JSON.stringify(ws, null, 2));
|
|
7266
|
+
return EXIT.SUCCESS;
|
|
7267
|
+
}
|
|
7268
|
+
render.section(`${clay("tasks")} — ${dim(`${ws.totals.open} open · ${ws.totals.claimed} in-flight · ${ws.totals.completed} done`)}`);
|
|
7269
|
+
if (ws.tasks.length === 0) {
|
|
7270
|
+
process.stdout.write(dim(` no tasks in window
|
|
7271
|
+
`));
|
|
7272
|
+
return EXIT.SUCCESS;
|
|
7273
|
+
}
|
|
7274
|
+
const slugWidth = Math.max(...ws.tasks.map((t) => t.meshSlug.length), 6);
|
|
7275
|
+
for (const t of ws.tasks) {
|
|
7276
|
+
const slug = dim(t.meshSlug.padEnd(slugWidth));
|
|
7277
|
+
const status = t.status === "open" ? yellow("open ") : t.status === "claimed" ? cyan("working ") : green("done ");
|
|
7278
|
+
const prio = t.priority === "urgent" ? yellow("!") : t.priority === "low" ? dim("·") : " ";
|
|
7279
|
+
const claimer = t.claimedByName ? dim(` ← ${t.claimedByName}`) : "";
|
|
7280
|
+
process.stdout.write(` ${slug} ${prio} ${status} ${t.title}${claimer}
|
|
7281
|
+
`);
|
|
7282
|
+
}
|
|
7283
|
+
return EXIT.SUCCESS;
|
|
7284
|
+
});
|
|
7285
|
+
}
|
|
7286
|
+
async function runMeState(flags) {
|
|
7287
|
+
return withRestKey({
|
|
7288
|
+
meshSlug: resolveMeshForMint(flags.mesh),
|
|
7289
|
+
purpose: "workspace-state",
|
|
7290
|
+
capabilities: ["read"]
|
|
7291
|
+
}, async ({ secret }) => {
|
|
7292
|
+
const params = new URLSearchParams;
|
|
7293
|
+
if (flags.key)
|
|
7294
|
+
params.set("key", flags.key);
|
|
7295
|
+
const path = "/api/v1/me/state" + (params.toString() ? `?${params.toString()}` : "");
|
|
7296
|
+
const ws = await request({
|
|
7297
|
+
path,
|
|
7298
|
+
token: secret
|
|
7299
|
+
});
|
|
7300
|
+
if (flags.json) {
|
|
7301
|
+
console.log(JSON.stringify(ws, null, 2));
|
|
7302
|
+
return EXIT.SUCCESS;
|
|
7303
|
+
}
|
|
7304
|
+
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"}`)}`);
|
|
7305
|
+
if (ws.entries.length === 0) {
|
|
7306
|
+
process.stdout.write(dim(` no state entries
|
|
7307
|
+
`));
|
|
7308
|
+
return EXIT.SUCCESS;
|
|
7309
|
+
}
|
|
7310
|
+
const slugWidth = Math.max(...ws.entries.map((e) => e.meshSlug.length), 6);
|
|
7311
|
+
const keyWidth = Math.max(...ws.entries.map((e) => e.key.length), 8);
|
|
7312
|
+
for (const e of ws.entries) {
|
|
7313
|
+
const slug = dim(e.meshSlug.padEnd(slugWidth));
|
|
7314
|
+
const key = cyan(e.key.padEnd(keyWidth));
|
|
7315
|
+
const valueStr = typeof e.value === "string" ? e.value : JSON.stringify(e.value);
|
|
7316
|
+
const trimmed = valueStr.length > 80 ? valueStr.slice(0, 80) + "…" : valueStr;
|
|
7317
|
+
const ago = dim(formatRelativeTime(e.updatedAt));
|
|
7318
|
+
process.stdout.write(` ${slug} ${key} ${trimmed} ${ago}
|
|
7319
|
+
`);
|
|
7320
|
+
}
|
|
7321
|
+
return EXIT.SUCCESS;
|
|
7322
|
+
});
|
|
7323
|
+
}
|
|
7324
|
+
async function runMeMemory(flags) {
|
|
7325
|
+
return withRestKey({
|
|
7326
|
+
meshSlug: resolveMeshForMint(flags.mesh),
|
|
7327
|
+
purpose: "workspace-memory",
|
|
7328
|
+
capabilities: ["read"]
|
|
7329
|
+
}, async ({ secret }) => {
|
|
7330
|
+
const params = new URLSearchParams;
|
|
7331
|
+
if (flags.query)
|
|
7332
|
+
params.set("q", flags.query);
|
|
7333
|
+
const path = "/api/v1/me/memory" + (params.toString() ? `?${params.toString()}` : "");
|
|
7334
|
+
const ws = await request({
|
|
7335
|
+
path,
|
|
7336
|
+
token: secret
|
|
7337
|
+
});
|
|
7338
|
+
if (flags.json) {
|
|
7339
|
+
console.log(JSON.stringify(ws, null, 2));
|
|
7340
|
+
return EXIT.SUCCESS;
|
|
7341
|
+
}
|
|
7342
|
+
const headerLabel = flags.query ? `recall — "${flags.query}"` : "recall — last 30 days";
|
|
7343
|
+
render.section(`${clay(headerLabel)} ${dim(`${ws.totals.entries} match${ws.totals.entries === 1 ? "" : "es"}`)}`);
|
|
7344
|
+
if (ws.memories.length === 0) {
|
|
7345
|
+
process.stdout.write(dim(` no memories
|
|
7346
|
+
`));
|
|
7347
|
+
return EXIT.SUCCESS;
|
|
7348
|
+
}
|
|
7349
|
+
const slugWidth = Math.max(...ws.memories.map((m) => m.meshSlug.length), 6);
|
|
7350
|
+
for (const m of ws.memories) {
|
|
7351
|
+
const slug = dim(m.meshSlug.padEnd(slugWidth));
|
|
7352
|
+
const ago = dim(formatRelativeTime(m.rememberedAt));
|
|
7353
|
+
const tags = m.tags.length > 0 ? " " + dim("[" + m.tags.join(", ") + "]") : "";
|
|
7354
|
+
const content = m.content.length > 240 ? m.content.slice(0, 240) + "…" : m.content;
|
|
7355
|
+
process.stdout.write(` ${slug} ${ago}${tags}
|
|
7356
|
+
${content}
|
|
7357
|
+
`);
|
|
7358
|
+
}
|
|
7359
|
+
return EXIT.SUCCESS;
|
|
7360
|
+
});
|
|
7361
|
+
}
|
|
7362
|
+
function formatRelativeTime(iso) {
|
|
7363
|
+
const then = new Date(iso).getTime();
|
|
7364
|
+
const now = Date.now();
|
|
7365
|
+
const sec = Math.max(0, Math.floor((now - then) / 1000));
|
|
7366
|
+
if (sec < 60)
|
|
7367
|
+
return `${sec}s ago`;
|
|
7368
|
+
if (sec < 3600)
|
|
7369
|
+
return `${Math.floor(sec / 60)}m ago`;
|
|
7370
|
+
if (sec < 86400)
|
|
7371
|
+
return `${Math.floor(sec / 3600)}h ago`;
|
|
7372
|
+
if (sec < 86400 * 30)
|
|
7373
|
+
return `${Math.floor(sec / 86400)}d ago`;
|
|
7374
|
+
if (sec < 86400 * 365)
|
|
7375
|
+
return `${Math.floor(sec / (86400 * 30))}mo ago`;
|
|
7376
|
+
return `${Math.floor(sec / (86400 * 365))}y ago`;
|
|
7377
|
+
}
|
|
7378
|
+
var init_me = __esm(() => {
|
|
7379
|
+
init_with_rest_key();
|
|
7380
|
+
init_client();
|
|
7381
|
+
init_facade();
|
|
6955
7382
|
init_render();
|
|
6956
7383
|
init_styles();
|
|
7384
|
+
init_exit_codes();
|
|
6957
7385
|
});
|
|
6958
7386
|
|
|
6959
7387
|
// src/commands/info.ts
|
|
@@ -11590,441 +12018,146 @@ async function runTopicCreate(name, flags) {
|
|
|
11590
12018
|
}
|
|
11591
12019
|
return await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
11592
12020
|
const result = await client.topicCreate({
|
|
11593
|
-
name,
|
|
11594
|
-
description: flags.description,
|
|
11595
|
-
visibility: flags.visibility
|
|
11596
|
-
});
|
|
11597
|
-
if (!result) {
|
|
11598
|
-
render.err("topic create failed");
|
|
11599
|
-
return EXIT.INTERNAL_ERROR;
|
|
11600
|
-
}
|
|
11601
|
-
if (flags.json) {
|
|
11602
|
-
console.log(JSON.stringify(result));
|
|
11603
|
-
return EXIT.SUCCESS;
|
|
11604
|
-
}
|
|
11605
|
-
if (result.created) {
|
|
11606
|
-
render.ok("created", `${clay("#" + name)} ${dim(result.id.slice(0, 8))}`);
|
|
11607
|
-
} else {
|
|
11608
|
-
render.info(dim(`already exists: #${name} ${result.id.slice(0, 8)}`));
|
|
11609
|
-
}
|
|
11610
|
-
return EXIT.SUCCESS;
|
|
11611
|
-
});
|
|
11612
|
-
}
|
|
11613
|
-
async function runTopicList(flags) {
|
|
11614
|
-
return await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
11615
|
-
const topics = await client.topicList();
|
|
11616
|
-
if (flags.json) {
|
|
11617
|
-
console.log(JSON.stringify(topics, null, 2));
|
|
11618
|
-
return EXIT.SUCCESS;
|
|
11619
|
-
}
|
|
11620
|
-
if (topics.length === 0) {
|
|
11621
|
-
render.info(dim("no topics in this mesh."));
|
|
11622
|
-
return EXIT.SUCCESS;
|
|
11623
|
-
}
|
|
11624
|
-
render.section(`topics (${topics.length})`);
|
|
11625
|
-
for (const t of topics) {
|
|
11626
|
-
const vis = t.visibility === "public" ? green(t.visibility) : dim(t.visibility);
|
|
11627
|
-
process.stdout.write(` ${clay("#" + t.name)} ${vis} ${dim(`${t.memberCount} member${t.memberCount === 1 ? "" : "s"}`)}
|
|
11628
|
-
`);
|
|
11629
|
-
if (t.description)
|
|
11630
|
-
process.stdout.write(` ${dim(t.description)}
|
|
11631
|
-
`);
|
|
11632
|
-
}
|
|
11633
|
-
return EXIT.SUCCESS;
|
|
11634
|
-
});
|
|
11635
|
-
}
|
|
11636
|
-
async function runTopicJoin(topic, flags) {
|
|
11637
|
-
if (!topic) {
|
|
11638
|
-
render.err("Usage: claudemesh topic join <topic> [--role lead|member|observer]");
|
|
11639
|
-
return EXIT.INVALID_ARGS;
|
|
11640
|
-
}
|
|
11641
|
-
return await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
11642
|
-
await client.topicJoin(topic, flags.role);
|
|
11643
|
-
if (flags.json)
|
|
11644
|
-
console.log(JSON.stringify({ joined: topic }));
|
|
11645
|
-
else
|
|
11646
|
-
render.ok("joined", clay("#" + topic));
|
|
11647
|
-
return EXIT.SUCCESS;
|
|
11648
|
-
});
|
|
11649
|
-
}
|
|
11650
|
-
async function runTopicLeave(topic, flags) {
|
|
11651
|
-
if (!topic) {
|
|
11652
|
-
render.err("Usage: claudemesh topic leave <topic>");
|
|
11653
|
-
return EXIT.INVALID_ARGS;
|
|
11654
|
-
}
|
|
11655
|
-
return await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
11656
|
-
await client.topicLeave(topic);
|
|
11657
|
-
if (flags.json)
|
|
11658
|
-
console.log(JSON.stringify({ left: topic }));
|
|
11659
|
-
else
|
|
11660
|
-
render.ok("left", clay("#" + topic));
|
|
11661
|
-
return EXIT.SUCCESS;
|
|
11662
|
-
});
|
|
11663
|
-
}
|
|
11664
|
-
async function runTopicMembers(topic, flags) {
|
|
11665
|
-
if (!topic) {
|
|
11666
|
-
render.err("Usage: claudemesh topic members <topic>");
|
|
11667
|
-
return EXIT.INVALID_ARGS;
|
|
11668
|
-
}
|
|
11669
|
-
return await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
11670
|
-
const members = await client.topicMembers(topic);
|
|
11671
|
-
if (flags.json) {
|
|
11672
|
-
console.log(JSON.stringify(members, null, 2));
|
|
11673
|
-
return EXIT.SUCCESS;
|
|
11674
|
-
}
|
|
11675
|
-
if (members.length === 0) {
|
|
11676
|
-
render.info(dim(`no members in ${clay("#" + topic)}.`));
|
|
11677
|
-
return EXIT.SUCCESS;
|
|
11678
|
-
}
|
|
11679
|
-
render.section(`${clay("#" + topic)} members (${members.length})`);
|
|
11680
|
-
for (const m of members) {
|
|
11681
|
-
process.stdout.write(` ${bold(m.displayName)} ${dim(m.role)} ${dim(m.pubkey.slice(0, 8))}
|
|
11682
|
-
`);
|
|
11683
|
-
}
|
|
11684
|
-
return EXIT.SUCCESS;
|
|
11685
|
-
});
|
|
11686
|
-
}
|
|
11687
|
-
async function runTopicHistory(topic, flags) {
|
|
11688
|
-
if (!topic) {
|
|
11689
|
-
render.err("Usage: claudemesh topic history <topic> [--limit N] [--before <id>]");
|
|
11690
|
-
return EXIT.INVALID_ARGS;
|
|
11691
|
-
}
|
|
11692
|
-
return await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
11693
|
-
const limit = flags.limit ? Number(flags.limit) : undefined;
|
|
11694
|
-
const messages = await client.topicHistory({
|
|
11695
|
-
topic,
|
|
11696
|
-
limit,
|
|
11697
|
-
beforeId: flags.before
|
|
11698
|
-
});
|
|
11699
|
-
if (flags.json) {
|
|
11700
|
-
console.log(JSON.stringify(messages, null, 2));
|
|
11701
|
-
return EXIT.SUCCESS;
|
|
11702
|
-
}
|
|
11703
|
-
if (messages.length === 0) {
|
|
11704
|
-
render.info(dim(`no messages in ${clay("#" + topic)}.`));
|
|
11705
|
-
return EXIT.SUCCESS;
|
|
11706
|
-
}
|
|
11707
|
-
const ordered = [...messages].reverse();
|
|
11708
|
-
render.section(`${clay("#" + topic)} history (${ordered.length})`);
|
|
11709
|
-
for (const m of ordered) {
|
|
11710
|
-
const t = new Date(m.createdAt).toLocaleString();
|
|
11711
|
-
process.stdout.write(` ${dim(t)} ${bold(m.senderPubkey.slice(0, 8))} ${dim("(encrypted, " + m.ciphertext.length + "b)")}
|
|
11712
|
-
`);
|
|
11713
|
-
}
|
|
11714
|
-
return EXIT.SUCCESS;
|
|
11715
|
-
});
|
|
11716
|
-
}
|
|
11717
|
-
async function runTopicMarkRead(topic, flags) {
|
|
11718
|
-
if (!topic) {
|
|
11719
|
-
render.err("Usage: claudemesh topic read <topic>");
|
|
11720
|
-
return EXIT.INVALID_ARGS;
|
|
11721
|
-
}
|
|
11722
|
-
return await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
11723
|
-
await client.topicMarkRead(topic);
|
|
11724
|
-
if (flags.json)
|
|
11725
|
-
console.log(JSON.stringify({ read: topic }));
|
|
11726
|
-
else
|
|
11727
|
-
render.ok("marked read", clay("#" + topic));
|
|
11728
|
-
return EXIT.SUCCESS;
|
|
11729
|
-
});
|
|
11730
|
-
}
|
|
11731
|
-
var init_topic = __esm(() => {
|
|
11732
|
-
init_connect();
|
|
11733
|
-
init_render();
|
|
11734
|
-
init_styles();
|
|
11735
|
-
init_exit_codes();
|
|
11736
|
-
});
|
|
11737
|
-
|
|
11738
|
-
// src/services/api/with-rest-key.ts
|
|
11739
|
-
async function withRestKey(opts, fn) {
|
|
11740
|
-
return withMesh({ meshSlug: opts.meshSlug ?? null }, async (client, mesh) => {
|
|
11741
|
-
const result = await client.apiKeyCreate({
|
|
11742
|
-
label: `cli-${opts.purpose ?? "rest"}-${process.pid}`,
|
|
11743
|
-
capabilities: opts.capabilities ?? ["read"],
|
|
11744
|
-
topicScopes: opts.topicScopes ?? undefined,
|
|
11745
|
-
expiresAt: new Date(Date.now() + 5 * 60 * 1000).toISOString()
|
|
11746
|
-
});
|
|
11747
|
-
if (!result || !result.secret) {
|
|
11748
|
-
throw new Error("apikey mint failed — broker did not return a secret");
|
|
11749
|
-
}
|
|
11750
|
-
try {
|
|
11751
|
-
return await fn({
|
|
11752
|
-
secret: result.secret,
|
|
11753
|
-
meshId: mesh.meshId,
|
|
11754
|
-
meshSlug: mesh.slug,
|
|
11755
|
-
client,
|
|
11756
|
-
mesh
|
|
11757
|
-
});
|
|
11758
|
-
} finally {
|
|
11759
|
-
try {
|
|
11760
|
-
await client.apiKeyRevoke(result.id);
|
|
11761
|
-
} catch {}
|
|
11762
|
-
}
|
|
11763
|
-
});
|
|
11764
|
-
}
|
|
11765
|
-
var init_with_rest_key = __esm(() => {
|
|
11766
|
-
init_connect();
|
|
11767
|
-
});
|
|
11768
|
-
|
|
11769
|
-
// src/commands/me.ts
|
|
11770
|
-
var exports_me = {};
|
|
11771
|
-
__export(exports_me, {
|
|
11772
|
-
runMeTopics: () => runMeTopics,
|
|
11773
|
-
runMeSearch: () => runMeSearch,
|
|
11774
|
-
runMeNotifications: () => runMeNotifications,
|
|
11775
|
-
runMeActivity: () => runMeActivity,
|
|
11776
|
-
runMe: () => runMe
|
|
11777
|
-
});
|
|
11778
|
-
function resolveMeshForMint(explicit) {
|
|
11779
|
-
if (explicit)
|
|
11780
|
-
return explicit;
|
|
11781
|
-
const cfg = readConfig();
|
|
11782
|
-
return cfg.meshes[0]?.slug ?? null;
|
|
11783
|
-
}
|
|
11784
|
-
async function runMe(flags) {
|
|
11785
|
-
return withRestKey({
|
|
11786
|
-
meshSlug: resolveMeshForMint(flags.mesh),
|
|
11787
|
-
purpose: "workspace-overview",
|
|
11788
|
-
capabilities: ["read"]
|
|
11789
|
-
}, async ({ secret }) => {
|
|
11790
|
-
const ws = await request({
|
|
11791
|
-
path: "/api/v1/me/workspace",
|
|
11792
|
-
token: secret
|
|
11793
|
-
});
|
|
11794
|
-
if (flags.json) {
|
|
11795
|
-
console.log(JSON.stringify(ws, null, 2));
|
|
11796
|
-
return EXIT.SUCCESS;
|
|
11797
|
-
}
|
|
11798
|
-
render.section(`${clay("workspace")} — ${bold(ws.userId.slice(0, 8))} ${dim(`· ${ws.totals.meshes} mesh${ws.totals.meshes === 1 ? "" : "es"}`)}`);
|
|
11799
|
-
const totalsLine = [
|
|
11800
|
-
`${green(String(ws.totals.online))}/${ws.totals.peers} online`,
|
|
11801
|
-
`${ws.totals.topics} topic${ws.totals.topics === 1 ? "" : "s"}`,
|
|
11802
|
-
ws.totals.unreadMentions > 0 ? yellow(`${ws.totals.unreadMentions} unread @you`) : dim("0 unread @you")
|
|
11803
|
-
].join(dim(" · "));
|
|
11804
|
-
process.stdout.write(" " + totalsLine + `
|
|
11805
|
-
|
|
11806
|
-
`);
|
|
11807
|
-
if (ws.meshes.length === 0) {
|
|
11808
|
-
process.stdout.write(dim(" no meshes joined — run `claudemesh new` or accept an invite\n"));
|
|
11809
|
-
return EXIT.SUCCESS;
|
|
11810
|
-
}
|
|
11811
|
-
const slugWidth = Math.max(...ws.meshes.map((m) => m.slug.length), 8);
|
|
11812
|
-
for (const m of ws.meshes) {
|
|
11813
|
-
const slug = cyan(m.slug.padEnd(slugWidth));
|
|
11814
|
-
const peers = `${m.online}/${m.peers}`;
|
|
11815
|
-
const role = dim(m.myRole);
|
|
11816
|
-
const unread = m.unreadMentions > 0 ? " " + yellow(`${m.unreadMentions} @you`) : "";
|
|
11817
|
-
process.stdout.write(` ${slug} ${peers.padStart(5)} online ${dim(String(m.topics).padStart(2) + " topics")} ${role}${unread}
|
|
11818
|
-
`);
|
|
11819
|
-
}
|
|
11820
|
-
return EXIT.SUCCESS;
|
|
11821
|
-
});
|
|
11822
|
-
}
|
|
11823
|
-
async function runMeTopics(flags) {
|
|
11824
|
-
return withRestKey({
|
|
11825
|
-
meshSlug: resolveMeshForMint(flags.mesh),
|
|
11826
|
-
purpose: "workspace-topics",
|
|
11827
|
-
capabilities: ["read"]
|
|
11828
|
-
}, async ({ secret }) => {
|
|
11829
|
-
const ws = await request({
|
|
11830
|
-
path: "/api/v1/me/topics",
|
|
11831
|
-
token: secret
|
|
12021
|
+
name,
|
|
12022
|
+
description: flags.description,
|
|
12023
|
+
visibility: flags.visibility
|
|
11832
12024
|
});
|
|
11833
|
-
|
|
11834
|
-
|
|
11835
|
-
|
|
11836
|
-
return EXIT.SUCCESS;
|
|
12025
|
+
if (!result) {
|
|
12026
|
+
render.err("topic create failed");
|
|
12027
|
+
return EXIT.INTERNAL_ERROR;
|
|
11837
12028
|
}
|
|
11838
|
-
|
|
11839
|
-
|
|
11840
|
-
process.stdout.write(dim(flags.unread ? ` no unread topics
|
|
11841
|
-
` : " no topics — run `claudemesh topic create #general`\n"));
|
|
12029
|
+
if (flags.json) {
|
|
12030
|
+
console.log(JSON.stringify(result));
|
|
11842
12031
|
return EXIT.SUCCESS;
|
|
11843
12032
|
}
|
|
11844
|
-
|
|
11845
|
-
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
const name = cyan(t.name.padEnd(nameWidth));
|
|
11849
|
-
const unread = t.unread > 0 ? yellow(`${t.unread} unread`.padStart(10)) : dim("·".padStart(10));
|
|
11850
|
-
const last = t.lastMessageAt ? dim(formatRelativeTime(t.lastMessageAt)) : dim("never");
|
|
11851
|
-
process.stdout.write(` ${slug} ${name} ${unread} ${last}
|
|
11852
|
-
`);
|
|
12033
|
+
if (result.created) {
|
|
12034
|
+
render.ok("created", `${clay("#" + name)} ${dim(result.id.slice(0, 8))}`);
|
|
12035
|
+
} else {
|
|
12036
|
+
render.info(dim(`already exists: #${name} ${result.id.slice(0, 8)}`));
|
|
11853
12037
|
}
|
|
11854
12038
|
return EXIT.SUCCESS;
|
|
11855
12039
|
});
|
|
11856
12040
|
}
|
|
11857
|
-
async function
|
|
11858
|
-
return
|
|
11859
|
-
|
|
11860
|
-
purpose: "workspace-notifications",
|
|
11861
|
-
capabilities: ["read"]
|
|
11862
|
-
}, async ({ secret }) => {
|
|
11863
|
-
const params = new URLSearchParams;
|
|
11864
|
-
if (flags.all)
|
|
11865
|
-
params.set("include", "all");
|
|
11866
|
-
if (flags.since)
|
|
11867
|
-
params.set("since", flags.since);
|
|
11868
|
-
const path = "/api/v1/me/notifications" + (params.toString() ? `?${params.toString()}` : "");
|
|
11869
|
-
const ws = await request({
|
|
11870
|
-
path,
|
|
11871
|
-
token: secret
|
|
11872
|
-
});
|
|
12041
|
+
async function runTopicList(flags) {
|
|
12042
|
+
return await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
12043
|
+
const topics = await client.topicList();
|
|
11873
12044
|
if (flags.json) {
|
|
11874
|
-
console.log(JSON.stringify(
|
|
12045
|
+
console.log(JSON.stringify(topics, null, 2));
|
|
11875
12046
|
return EXIT.SUCCESS;
|
|
11876
12047
|
}
|
|
11877
|
-
|
|
11878
|
-
|
|
11879
|
-
if (ws.notifications.length === 0) {
|
|
11880
|
-
process.stdout.write(dim(flags.all ? ` no @-mentions in window
|
|
11881
|
-
` : ` inbox zero — nothing waiting
|
|
11882
|
-
`));
|
|
12048
|
+
if (topics.length === 0) {
|
|
12049
|
+
render.info(dim("no topics in this mesh."));
|
|
11883
12050
|
return EXIT.SUCCESS;
|
|
11884
12051
|
}
|
|
11885
|
-
|
|
11886
|
-
for (const
|
|
11887
|
-
const
|
|
11888
|
-
|
|
11889
|
-
|
|
11890
|
-
|
|
11891
|
-
|
|
11892
|
-
const snippet = n.snippet ?? (n.ciphertext ? dim("[encrypted]") : dim("[empty]"));
|
|
11893
|
-
process.stdout.write(` ${dot} ${slug} ${topic} ${dim(sender)} ${dim(ago)}
|
|
11894
|
-
` + ` ${snippet.length > 200 ? snippet.slice(0, 200) + "…" : snippet}
|
|
12052
|
+
render.section(`topics (${topics.length})`);
|
|
12053
|
+
for (const t of topics) {
|
|
12054
|
+
const vis = t.visibility === "public" ? green(t.visibility) : dim(t.visibility);
|
|
12055
|
+
process.stdout.write(` ${clay("#" + t.name)} ${vis} ${dim(`${t.memberCount} member${t.memberCount === 1 ? "" : "s"}`)}
|
|
12056
|
+
`);
|
|
12057
|
+
if (t.description)
|
|
12058
|
+
process.stdout.write(` ${dim(t.description)}
|
|
11895
12059
|
`);
|
|
11896
12060
|
}
|
|
11897
12061
|
return EXIT.SUCCESS;
|
|
11898
12062
|
});
|
|
11899
12063
|
}
|
|
11900
|
-
async function
|
|
11901
|
-
|
|
11902
|
-
|
|
11903
|
-
|
|
11904
|
-
|
|
11905
|
-
|
|
11906
|
-
|
|
11907
|
-
if (flags.
|
|
11908
|
-
|
|
11909
|
-
|
|
11910
|
-
|
|
11911
|
-
|
|
11912
|
-
|
|
11913
|
-
|
|
12064
|
+
async function runTopicJoin(topic, flags) {
|
|
12065
|
+
if (!topic) {
|
|
12066
|
+
render.err("Usage: claudemesh topic join <topic> [--role lead|member|observer]");
|
|
12067
|
+
return EXIT.INVALID_ARGS;
|
|
12068
|
+
}
|
|
12069
|
+
return await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
12070
|
+
await client.topicJoin(topic, flags.role);
|
|
12071
|
+
if (flags.json)
|
|
12072
|
+
console.log(JSON.stringify({ joined: topic }));
|
|
12073
|
+
else
|
|
12074
|
+
render.ok("joined", clay("#" + topic));
|
|
12075
|
+
return EXIT.SUCCESS;
|
|
12076
|
+
});
|
|
12077
|
+
}
|
|
12078
|
+
async function runTopicLeave(topic, flags) {
|
|
12079
|
+
if (!topic) {
|
|
12080
|
+
render.err("Usage: claudemesh topic leave <topic>");
|
|
12081
|
+
return EXIT.INVALID_ARGS;
|
|
12082
|
+
}
|
|
12083
|
+
return await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
12084
|
+
await client.topicLeave(topic);
|
|
12085
|
+
if (flags.json)
|
|
12086
|
+
console.log(JSON.stringify({ left: topic }));
|
|
12087
|
+
else
|
|
12088
|
+
render.ok("left", clay("#" + topic));
|
|
12089
|
+
return EXIT.SUCCESS;
|
|
12090
|
+
});
|
|
12091
|
+
}
|
|
12092
|
+
async function runTopicMembers(topic, flags) {
|
|
12093
|
+
if (!topic) {
|
|
12094
|
+
render.err("Usage: claudemesh topic members <topic>");
|
|
12095
|
+
return EXIT.INVALID_ARGS;
|
|
12096
|
+
}
|
|
12097
|
+
return await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
12098
|
+
const members = await client.topicMembers(topic);
|
|
11914
12099
|
if (flags.json) {
|
|
11915
|
-
console.log(JSON.stringify(
|
|
12100
|
+
console.log(JSON.stringify(members, null, 2));
|
|
11916
12101
|
return EXIT.SUCCESS;
|
|
11917
12102
|
}
|
|
11918
|
-
|
|
11919
|
-
|
|
11920
|
-
process.stdout.write(dim(` quiet — no activity in window
|
|
11921
|
-
`));
|
|
12103
|
+
if (members.length === 0) {
|
|
12104
|
+
render.info(dim(`no members in ${clay("#" + topic)}.`));
|
|
11922
12105
|
return EXIT.SUCCESS;
|
|
11923
12106
|
}
|
|
11924
|
-
|
|
11925
|
-
for (const
|
|
11926
|
-
|
|
11927
|
-
const topic = cyan(`#${a.topicName}`);
|
|
11928
|
-
const sender = a.senderName ?? "?";
|
|
11929
|
-
const ago = formatRelativeTime(a.createdAt);
|
|
11930
|
-
const snippet = a.snippet ?? (a.ciphertext ? dim("[encrypted]") : dim("[empty]"));
|
|
11931
|
-
process.stdout.write(` ${slug} ${topic} ${dim(sender + " ·")} ${dim(ago)}
|
|
11932
|
-
` + ` ${snippet.length > 200 ? snippet.slice(0, 200) + "…" : snippet}
|
|
12107
|
+
render.section(`${clay("#" + topic)} members (${members.length})`);
|
|
12108
|
+
for (const m of members) {
|
|
12109
|
+
process.stdout.write(` ${bold(m.displayName)} ${dim(m.role)} ${dim(m.pubkey.slice(0, 8))}
|
|
11933
12110
|
`);
|
|
11934
12111
|
}
|
|
11935
12112
|
return EXIT.SUCCESS;
|
|
11936
12113
|
});
|
|
11937
12114
|
}
|
|
11938
|
-
async function
|
|
11939
|
-
if (!
|
|
11940
|
-
|
|
11941
|
-
`);
|
|
12115
|
+
async function runTopicHistory(topic, flags) {
|
|
12116
|
+
if (!topic) {
|
|
12117
|
+
render.err("Usage: claudemesh topic history <topic> [--limit N] [--before <id>]");
|
|
11942
12118
|
return EXIT.INVALID_ARGS;
|
|
11943
12119
|
}
|
|
11944
|
-
return
|
|
11945
|
-
|
|
11946
|
-
|
|
11947
|
-
|
|
11948
|
-
|
|
11949
|
-
|
|
11950
|
-
const ws = await request({
|
|
11951
|
-
path: `/api/v1/me/search?${params.toString()}`,
|
|
11952
|
-
token: secret
|
|
12120
|
+
return await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
12121
|
+
const limit = flags.limit ? Number(flags.limit) : undefined;
|
|
12122
|
+
const messages = await client.topicHistory({
|
|
12123
|
+
topic,
|
|
12124
|
+
limit,
|
|
12125
|
+
beforeId: flags.before
|
|
11953
12126
|
});
|
|
11954
12127
|
if (flags.json) {
|
|
11955
|
-
console.log(JSON.stringify(
|
|
12128
|
+
console.log(JSON.stringify(messages, null, 2));
|
|
11956
12129
|
return EXIT.SUCCESS;
|
|
11957
12130
|
}
|
|
11958
|
-
|
|
11959
|
-
|
|
11960
|
-
process.stdout.write(dim(` no matches
|
|
11961
|
-
`));
|
|
12131
|
+
if (messages.length === 0) {
|
|
12132
|
+
render.info(dim(`no messages in ${clay("#" + topic)}.`));
|
|
11962
12133
|
return EXIT.SUCCESS;
|
|
11963
12134
|
}
|
|
11964
|
-
|
|
11965
|
-
|
|
11966
|
-
|
|
11967
|
-
|
|
11968
|
-
|
|
11969
|
-
for (const t of ws.topics) {
|
|
11970
|
-
const slug = dim(t.meshSlug.padEnd(slugWidth));
|
|
11971
|
-
const name = cyan(`#${t.name}`);
|
|
11972
|
-
const desc = t.description ? dim(` — ${t.description}`) : "";
|
|
11973
|
-
process.stdout.write(` ${slug} ${name}${desc}
|
|
11974
|
-
`);
|
|
11975
|
-
}
|
|
11976
|
-
}
|
|
11977
|
-
if (ws.messages.length > 0) {
|
|
11978
|
-
process.stdout.write(dim(`
|
|
11979
|
-
messages
|
|
11980
|
-
`));
|
|
11981
|
-
const slugWidth = Math.max(...ws.messages.map((m) => m.meshSlug.length), 6);
|
|
11982
|
-
for (const m of ws.messages) {
|
|
11983
|
-
const slug = dim(m.meshSlug.padEnd(slugWidth));
|
|
11984
|
-
const topic = cyan(`#${m.topicName}`);
|
|
11985
|
-
const sender = m.senderName;
|
|
11986
|
-
const ago = formatRelativeTime(m.createdAt);
|
|
11987
|
-
const snippet = m.snippet ?? (m.bodyVersion === 2 ? dim("[encrypted — open the topic to decrypt]") : dim("[empty]"));
|
|
11988
|
-
const highlighted = m.snippet ? highlightMatch(snippet, flags.query) : snippet;
|
|
11989
|
-
process.stdout.write(` ${slug} ${topic} ${dim(sender + " ·")} ${dim(ago)}
|
|
11990
|
-
` + ` ${highlighted}
|
|
12135
|
+
const ordered = [...messages].reverse();
|
|
12136
|
+
render.section(`${clay("#" + topic)} history (${ordered.length})`);
|
|
12137
|
+
for (const m of ordered) {
|
|
12138
|
+
const t = new Date(m.createdAt).toLocaleString();
|
|
12139
|
+
process.stdout.write(` ${dim(t)} ${bold(m.senderPubkey.slice(0, 8))} ${dim("(encrypted, " + m.ciphertext.length + "b)")}
|
|
11991
12140
|
`);
|
|
11992
|
-
}
|
|
11993
12141
|
}
|
|
11994
12142
|
return EXIT.SUCCESS;
|
|
11995
12143
|
});
|
|
11996
12144
|
}
|
|
11997
|
-
function
|
|
11998
|
-
if (!
|
|
11999
|
-
|
|
12000
|
-
|
|
12001
|
-
|
|
12002
|
-
|
|
12003
|
-
|
|
12004
|
-
|
|
12005
|
-
|
|
12006
|
-
|
|
12007
|
-
|
|
12008
|
-
|
|
12009
|
-
|
|
12010
|
-
const now = Date.now();
|
|
12011
|
-
const sec = Math.max(0, Math.floor((now - then) / 1000));
|
|
12012
|
-
if (sec < 60)
|
|
12013
|
-
return `${sec}s ago`;
|
|
12014
|
-
if (sec < 3600)
|
|
12015
|
-
return `${Math.floor(sec / 60)}m ago`;
|
|
12016
|
-
if (sec < 86400)
|
|
12017
|
-
return `${Math.floor(sec / 3600)}h ago`;
|
|
12018
|
-
if (sec < 86400 * 30)
|
|
12019
|
-
return `${Math.floor(sec / 86400)}d ago`;
|
|
12020
|
-
if (sec < 86400 * 365)
|
|
12021
|
-
return `${Math.floor(sec / (86400 * 30))}mo ago`;
|
|
12022
|
-
return `${Math.floor(sec / (86400 * 365))}y ago`;
|
|
12145
|
+
async function runTopicMarkRead(topic, flags) {
|
|
12146
|
+
if (!topic) {
|
|
12147
|
+
render.err("Usage: claudemesh topic read <topic>");
|
|
12148
|
+
return EXIT.INVALID_ARGS;
|
|
12149
|
+
}
|
|
12150
|
+
return await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
12151
|
+
await client.topicMarkRead(topic);
|
|
12152
|
+
if (flags.json)
|
|
12153
|
+
console.log(JSON.stringify({ read: topic }));
|
|
12154
|
+
else
|
|
12155
|
+
render.ok("marked read", clay("#" + topic));
|
|
12156
|
+
return EXIT.SUCCESS;
|
|
12157
|
+
});
|
|
12023
12158
|
}
|
|
12024
|
-
var
|
|
12025
|
-
|
|
12026
|
-
init_client();
|
|
12027
|
-
init_facade();
|
|
12159
|
+
var init_topic = __esm(() => {
|
|
12160
|
+
init_connect();
|
|
12028
12161
|
init_render();
|
|
12029
12162
|
init_styles();
|
|
12030
12163
|
init_exit_codes();
|
|
@@ -14423,7 +14556,7 @@ async function main() {
|
|
|
14423
14556
|
}
|
|
14424
14557
|
case "send": {
|
|
14425
14558
|
const { runSend: runSend2 } = await Promise.resolve().then(() => (init_send(), exports_send));
|
|
14426
|
-
await runSend2({ mesh: flags.mesh, priority: flags.priority, json: !!flags.json }, positionals[0] ?? "", positionals.slice(1).join(" "));
|
|
14559
|
+
await runSend2({ mesh: flags.mesh, priority: flags.priority, json: !!flags.json, self: !!flags.self }, positionals[0] ?? "", positionals.slice(1).join(" "));
|
|
14427
14560
|
break;
|
|
14428
14561
|
}
|
|
14429
14562
|
case "inbox": {
|
|
@@ -14437,6 +14570,10 @@ async function main() {
|
|
|
14437
14570
|
const { runStateSet: runStateSet2 } = await Promise.resolve().then(() => (init_state(), exports_state));
|
|
14438
14571
|
await runStateSet2({}, positionals[1] ?? "", positionals[2] ?? "");
|
|
14439
14572
|
} else if (sub === "list") {
|
|
14573
|
+
if (!flags.mesh) {
|
|
14574
|
+
const { runMeState: runMeState2 } = await Promise.resolve().then(() => (init_me(), exports_me));
|
|
14575
|
+
process.exit(await runMeState2({ json: !!flags.json, key: flags.key }));
|
|
14576
|
+
}
|
|
14440
14577
|
const { runStateList: runStateList2 } = await Promise.resolve().then(() => (init_state(), exports_state));
|
|
14441
14578
|
await runStateList2({});
|
|
14442
14579
|
} else {
|
|
@@ -14456,6 +14593,10 @@ async function main() {
|
|
|
14456
14593
|
break;
|
|
14457
14594
|
}
|
|
14458
14595
|
case "recall": {
|
|
14596
|
+
if (!flags.mesh) {
|
|
14597
|
+
const { runMeMemory: runMeMemory2 } = await Promise.resolve().then(() => (init_me(), exports_me));
|
|
14598
|
+
process.exit(await runMeMemory2({ json: !!flags.json, query: positionals.join(" ") }));
|
|
14599
|
+
}
|
|
14459
14600
|
const { recall: recall2 } = await Promise.resolve().then(() => (init_recall(), exports_recall));
|
|
14460
14601
|
process.exit(await recall2(positionals.join(" "), { mesh: flags.mesh, json: !!flags.json }));
|
|
14461
14602
|
break;
|
|
@@ -15132,6 +15273,10 @@ async function main() {
|
|
|
15132
15273
|
const { runTaskComplete: runTaskComplete2 } = await Promise.resolve().then(() => (init_broker_actions(), exports_broker_actions));
|
|
15133
15274
|
process.exit(await runTaskComplete2(positionals[1], positionals.slice(2).join(" ") || undefined, f));
|
|
15134
15275
|
} else if (sub === "list") {
|
|
15276
|
+
if (!f.mesh) {
|
|
15277
|
+
const { runMeTasks: runMeTasks2 } = await Promise.resolve().then(() => (init_me(), exports_me));
|
|
15278
|
+
process.exit(await runMeTasks2({ json: f.json, status: flags.status }));
|
|
15279
|
+
}
|
|
15135
15280
|
const { runTaskList: runTaskList2 } = await Promise.resolve().then(() => (init_platform_actions(), exports_platform_actions));
|
|
15136
15281
|
process.exit(await runTaskList2({ ...f, status: flags.status, assignee: flags.assignee }));
|
|
15137
15282
|
} else if (sub === "create") {
|
|
@@ -15170,4 +15315,4 @@ main().catch((err) => {
|
|
|
15170
15315
|
process.exit(EXIT.INTERNAL_ERROR);
|
|
15171
15316
|
});
|
|
15172
15317
|
|
|
15173
|
-
//# debugId=
|
|
15318
|
+
//# debugId=E54B2ED5C4F2639E64756E2164756E21
|