claudemesh-cli 1.15.0 → 1.16.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 +522 -395
- package/dist/entrypoints/cli.js.map +6 -6
- 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.16.0", env;
|
|
92
92
|
var init_urls = __esm(() => {
|
|
93
93
|
URLS = {
|
|
94
94
|
BROKER: process.env.CLAUDEMESH_BROKER_URL ?? "wss://ic.claudemesh.com/ws",
|
|
@@ -6956,6 +6956,416 @@ var init_state = __esm(() => {
|
|
|
6956
6956
|
init_styles();
|
|
6957
6957
|
});
|
|
6958
6958
|
|
|
6959
|
+
// src/services/api/with-rest-key.ts
|
|
6960
|
+
async function withRestKey(opts, fn) {
|
|
6961
|
+
return withMesh({ meshSlug: opts.meshSlug ?? null }, async (client, mesh) => {
|
|
6962
|
+
const result = await client.apiKeyCreate({
|
|
6963
|
+
label: `cli-${opts.purpose ?? "rest"}-${process.pid}`,
|
|
6964
|
+
capabilities: opts.capabilities ?? ["read"],
|
|
6965
|
+
topicScopes: opts.topicScopes ?? undefined,
|
|
6966
|
+
expiresAt: new Date(Date.now() + 5 * 60 * 1000).toISOString()
|
|
6967
|
+
});
|
|
6968
|
+
if (!result || !result.secret) {
|
|
6969
|
+
throw new Error("apikey mint failed — broker did not return a secret");
|
|
6970
|
+
}
|
|
6971
|
+
try {
|
|
6972
|
+
return await fn({
|
|
6973
|
+
secret: result.secret,
|
|
6974
|
+
meshId: mesh.meshId,
|
|
6975
|
+
meshSlug: mesh.slug,
|
|
6976
|
+
client,
|
|
6977
|
+
mesh
|
|
6978
|
+
});
|
|
6979
|
+
} finally {
|
|
6980
|
+
try {
|
|
6981
|
+
await client.apiKeyRevoke(result.id);
|
|
6982
|
+
} catch {}
|
|
6983
|
+
}
|
|
6984
|
+
});
|
|
6985
|
+
}
|
|
6986
|
+
var init_with_rest_key = __esm(() => {
|
|
6987
|
+
init_connect();
|
|
6988
|
+
});
|
|
6989
|
+
|
|
6990
|
+
// src/commands/me.ts
|
|
6991
|
+
var exports_me = {};
|
|
6992
|
+
__export(exports_me, {
|
|
6993
|
+
runMeTopics: () => runMeTopics,
|
|
6994
|
+
runMeTasks: () => runMeTasks,
|
|
6995
|
+
runMeState: () => runMeState,
|
|
6996
|
+
runMeSearch: () => runMeSearch,
|
|
6997
|
+
runMeNotifications: () => runMeNotifications,
|
|
6998
|
+
runMeMemory: () => runMeMemory,
|
|
6999
|
+
runMeActivity: () => runMeActivity,
|
|
7000
|
+
runMe: () => runMe
|
|
7001
|
+
});
|
|
7002
|
+
function resolveMeshForMint(explicit) {
|
|
7003
|
+
if (explicit)
|
|
7004
|
+
return explicit;
|
|
7005
|
+
const cfg = readConfig();
|
|
7006
|
+
return cfg.meshes[0]?.slug ?? null;
|
|
7007
|
+
}
|
|
7008
|
+
async function runMe(flags) {
|
|
7009
|
+
return withRestKey({
|
|
7010
|
+
meshSlug: resolveMeshForMint(flags.mesh),
|
|
7011
|
+
purpose: "workspace-overview",
|
|
7012
|
+
capabilities: ["read"]
|
|
7013
|
+
}, async ({ secret }) => {
|
|
7014
|
+
const ws = await request({
|
|
7015
|
+
path: "/api/v1/me/workspace",
|
|
7016
|
+
token: secret
|
|
7017
|
+
});
|
|
7018
|
+
if (flags.json) {
|
|
7019
|
+
console.log(JSON.stringify(ws, null, 2));
|
|
7020
|
+
return EXIT.SUCCESS;
|
|
7021
|
+
}
|
|
7022
|
+
render.section(`${clay("workspace")} — ${bold(ws.userId.slice(0, 8))} ${dim(`· ${ws.totals.meshes} mesh${ws.totals.meshes === 1 ? "" : "es"}`)}`);
|
|
7023
|
+
const totalsLine = [
|
|
7024
|
+
`${green(String(ws.totals.online))}/${ws.totals.peers} online`,
|
|
7025
|
+
`${ws.totals.topics} topic${ws.totals.topics === 1 ? "" : "s"}`,
|
|
7026
|
+
ws.totals.unreadMentions > 0 ? yellow(`${ws.totals.unreadMentions} unread @you`) : dim("0 unread @you")
|
|
7027
|
+
].join(dim(" · "));
|
|
7028
|
+
process.stdout.write(" " + totalsLine + `
|
|
7029
|
+
|
|
7030
|
+
`);
|
|
7031
|
+
if (ws.meshes.length === 0) {
|
|
7032
|
+
process.stdout.write(dim(" no meshes joined — run `claudemesh new` or accept an invite\n"));
|
|
7033
|
+
return EXIT.SUCCESS;
|
|
7034
|
+
}
|
|
7035
|
+
const slugWidth = Math.max(...ws.meshes.map((m) => m.slug.length), 8);
|
|
7036
|
+
for (const m of ws.meshes) {
|
|
7037
|
+
const slug = cyan(m.slug.padEnd(slugWidth));
|
|
7038
|
+
const peers = `${m.online}/${m.peers}`;
|
|
7039
|
+
const role = dim(m.myRole);
|
|
7040
|
+
const unread = m.unreadMentions > 0 ? " " + yellow(`${m.unreadMentions} @you`) : "";
|
|
7041
|
+
process.stdout.write(` ${slug} ${peers.padStart(5)} online ${dim(String(m.topics).padStart(2) + " topics")} ${role}${unread}
|
|
7042
|
+
`);
|
|
7043
|
+
}
|
|
7044
|
+
return EXIT.SUCCESS;
|
|
7045
|
+
});
|
|
7046
|
+
}
|
|
7047
|
+
async function runMeTopics(flags) {
|
|
7048
|
+
return withRestKey({
|
|
7049
|
+
meshSlug: resolveMeshForMint(flags.mesh),
|
|
7050
|
+
purpose: "workspace-topics",
|
|
7051
|
+
capabilities: ["read"]
|
|
7052
|
+
}, async ({ secret }) => {
|
|
7053
|
+
const ws = await request({
|
|
7054
|
+
path: "/api/v1/me/topics",
|
|
7055
|
+
token: secret
|
|
7056
|
+
});
|
|
7057
|
+
const visible = flags.unread ? ws.topics.filter((t) => t.unread > 0) : ws.topics;
|
|
7058
|
+
if (flags.json) {
|
|
7059
|
+
console.log(JSON.stringify({ topics: visible, totals: ws.totals }, null, 2));
|
|
7060
|
+
return EXIT.SUCCESS;
|
|
7061
|
+
}
|
|
7062
|
+
render.section(`${clay("topics")} — ${ws.totals.topics} across all meshes ${dim(ws.totals.unread > 0 ? `· ${ws.totals.unread} unread` : "· all read")}`);
|
|
7063
|
+
if (visible.length === 0) {
|
|
7064
|
+
process.stdout.write(dim(flags.unread ? ` no unread topics
|
|
7065
|
+
` : " no topics — run `claudemesh topic create #general`\n"));
|
|
7066
|
+
return EXIT.SUCCESS;
|
|
7067
|
+
}
|
|
7068
|
+
const slugWidth = Math.max(...visible.map((t) => t.meshSlug.length), 6);
|
|
7069
|
+
const nameWidth = Math.max(...visible.map((t) => t.name.length), 8);
|
|
7070
|
+
for (const t of visible) {
|
|
7071
|
+
const slug = dim(t.meshSlug.padEnd(slugWidth));
|
|
7072
|
+
const name = cyan(t.name.padEnd(nameWidth));
|
|
7073
|
+
const unread = t.unread > 0 ? yellow(`${t.unread} unread`.padStart(10)) : dim("·".padStart(10));
|
|
7074
|
+
const last = t.lastMessageAt ? dim(formatRelativeTime(t.lastMessageAt)) : dim("never");
|
|
7075
|
+
process.stdout.write(` ${slug} ${name} ${unread} ${last}
|
|
7076
|
+
`);
|
|
7077
|
+
}
|
|
7078
|
+
return EXIT.SUCCESS;
|
|
7079
|
+
});
|
|
7080
|
+
}
|
|
7081
|
+
async function runMeNotifications(flags) {
|
|
7082
|
+
return withRestKey({
|
|
7083
|
+
meshSlug: resolveMeshForMint(flags.mesh),
|
|
7084
|
+
purpose: "workspace-notifications",
|
|
7085
|
+
capabilities: ["read"]
|
|
7086
|
+
}, async ({ secret }) => {
|
|
7087
|
+
const params = new URLSearchParams;
|
|
7088
|
+
if (flags.all)
|
|
7089
|
+
params.set("include", "all");
|
|
7090
|
+
if (flags.since)
|
|
7091
|
+
params.set("since", flags.since);
|
|
7092
|
+
const path = "/api/v1/me/notifications" + (params.toString() ? `?${params.toString()}` : "");
|
|
7093
|
+
const ws = await request({
|
|
7094
|
+
path,
|
|
7095
|
+
token: secret
|
|
7096
|
+
});
|
|
7097
|
+
if (flags.json) {
|
|
7098
|
+
console.log(JSON.stringify(ws, null, 2));
|
|
7099
|
+
return EXIT.SUCCESS;
|
|
7100
|
+
}
|
|
7101
|
+
const headerLabel = flags.all ? "@-mentions (all)" : "@-mentions (unread)";
|
|
7102
|
+
render.section(`${clay(headerLabel)} — ${ws.totals.total} ${dim(ws.totals.unread > 0 ? `· ${ws.totals.unread} unread` : "· nothing pending")}`);
|
|
7103
|
+
if (ws.notifications.length === 0) {
|
|
7104
|
+
process.stdout.write(dim(flags.all ? ` no @-mentions in window
|
|
7105
|
+
` : ` inbox zero — nothing waiting
|
|
7106
|
+
`));
|
|
7107
|
+
return EXIT.SUCCESS;
|
|
7108
|
+
}
|
|
7109
|
+
const slugWidth = Math.max(...ws.notifications.map((n) => n.meshSlug.length), 6);
|
|
7110
|
+
for (const n of ws.notifications) {
|
|
7111
|
+
const slug = dim(n.meshSlug.padEnd(slugWidth));
|
|
7112
|
+
const topic = cyan(`#${n.topicName}`);
|
|
7113
|
+
const sender = n.senderName ? `from ${n.senderName}` : "from ?";
|
|
7114
|
+
const ago = formatRelativeTime(n.createdAt);
|
|
7115
|
+
const dot = n.read ? dim("·") : yellow("●");
|
|
7116
|
+
const snippet = n.snippet ?? (n.ciphertext ? dim("[encrypted]") : dim("[empty]"));
|
|
7117
|
+
process.stdout.write(` ${dot} ${slug} ${topic} ${dim(sender)} ${dim(ago)}
|
|
7118
|
+
` + ` ${snippet.length > 200 ? snippet.slice(0, 200) + "…" : snippet}
|
|
7119
|
+
`);
|
|
7120
|
+
}
|
|
7121
|
+
return EXIT.SUCCESS;
|
|
7122
|
+
});
|
|
7123
|
+
}
|
|
7124
|
+
async function runMeActivity(flags) {
|
|
7125
|
+
return withRestKey({
|
|
7126
|
+
meshSlug: resolveMeshForMint(flags.mesh),
|
|
7127
|
+
purpose: "workspace-activity",
|
|
7128
|
+
capabilities: ["read"]
|
|
7129
|
+
}, async ({ secret }) => {
|
|
7130
|
+
const params = new URLSearchParams;
|
|
7131
|
+
if (flags.since)
|
|
7132
|
+
params.set("since", flags.since);
|
|
7133
|
+
const path = "/api/v1/me/activity" + (params.toString() ? `?${params.toString()}` : "");
|
|
7134
|
+
const ws = await request({
|
|
7135
|
+
path,
|
|
7136
|
+
token: secret
|
|
7137
|
+
});
|
|
7138
|
+
if (flags.json) {
|
|
7139
|
+
console.log(JSON.stringify(ws, null, 2));
|
|
7140
|
+
return EXIT.SUCCESS;
|
|
7141
|
+
}
|
|
7142
|
+
render.section(`${clay("activity")} — ${ws.totals.events} ${dim(flags.since ? `since ${flags.since}` : "in the last 24h")}`);
|
|
7143
|
+
if (ws.activity.length === 0) {
|
|
7144
|
+
process.stdout.write(dim(` quiet — no activity in window
|
|
7145
|
+
`));
|
|
7146
|
+
return EXIT.SUCCESS;
|
|
7147
|
+
}
|
|
7148
|
+
const slugWidth = Math.max(...ws.activity.map((a) => a.meshSlug.length), 6);
|
|
7149
|
+
for (const a of ws.activity) {
|
|
7150
|
+
const slug = dim(a.meshSlug.padEnd(slugWidth));
|
|
7151
|
+
const topic = cyan(`#${a.topicName}`);
|
|
7152
|
+
const sender = a.senderName ?? "?";
|
|
7153
|
+
const ago = formatRelativeTime(a.createdAt);
|
|
7154
|
+
const snippet = a.snippet ?? (a.ciphertext ? dim("[encrypted]") : dim("[empty]"));
|
|
7155
|
+
process.stdout.write(` ${slug} ${topic} ${dim(sender + " ·")} ${dim(ago)}
|
|
7156
|
+
` + ` ${snippet.length > 200 ? snippet.slice(0, 200) + "…" : snippet}
|
|
7157
|
+
`);
|
|
7158
|
+
}
|
|
7159
|
+
return EXIT.SUCCESS;
|
|
7160
|
+
});
|
|
7161
|
+
}
|
|
7162
|
+
async function runMeSearch(flags) {
|
|
7163
|
+
if (!flags.query || flags.query.length < 2) {
|
|
7164
|
+
process.stderr.write(`Usage: claudemesh me search <query> (min 2 chars)
|
|
7165
|
+
`);
|
|
7166
|
+
return EXIT.INVALID_ARGS;
|
|
7167
|
+
}
|
|
7168
|
+
return withRestKey({
|
|
7169
|
+
meshSlug: resolveMeshForMint(flags.mesh),
|
|
7170
|
+
purpose: "workspace-search",
|
|
7171
|
+
capabilities: ["read"]
|
|
7172
|
+
}, async ({ secret }) => {
|
|
7173
|
+
const params = new URLSearchParams({ q: flags.query });
|
|
7174
|
+
const ws = await request({
|
|
7175
|
+
path: `/api/v1/me/search?${params.toString()}`,
|
|
7176
|
+
token: secret
|
|
7177
|
+
});
|
|
7178
|
+
if (flags.json) {
|
|
7179
|
+
console.log(JSON.stringify(ws, null, 2));
|
|
7180
|
+
return EXIT.SUCCESS;
|
|
7181
|
+
}
|
|
7182
|
+
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"}`)}`);
|
|
7183
|
+
if (ws.topics.length === 0 && ws.messages.length === 0) {
|
|
7184
|
+
process.stdout.write(dim(` no matches
|
|
7185
|
+
`));
|
|
7186
|
+
return EXIT.SUCCESS;
|
|
7187
|
+
}
|
|
7188
|
+
if (ws.topics.length > 0) {
|
|
7189
|
+
process.stdout.write(dim(`
|
|
7190
|
+
topics
|
|
7191
|
+
`));
|
|
7192
|
+
const slugWidth = Math.max(...ws.topics.map((t) => t.meshSlug.length), 6);
|
|
7193
|
+
for (const t of ws.topics) {
|
|
7194
|
+
const slug = dim(t.meshSlug.padEnd(slugWidth));
|
|
7195
|
+
const name = cyan(`#${t.name}`);
|
|
7196
|
+
const desc = t.description ? dim(` — ${t.description}`) : "";
|
|
7197
|
+
process.stdout.write(` ${slug} ${name}${desc}
|
|
7198
|
+
`);
|
|
7199
|
+
}
|
|
7200
|
+
}
|
|
7201
|
+
if (ws.messages.length > 0) {
|
|
7202
|
+
process.stdout.write(dim(`
|
|
7203
|
+
messages
|
|
7204
|
+
`));
|
|
7205
|
+
const slugWidth = Math.max(...ws.messages.map((m) => m.meshSlug.length), 6);
|
|
7206
|
+
for (const m of ws.messages) {
|
|
7207
|
+
const slug = dim(m.meshSlug.padEnd(slugWidth));
|
|
7208
|
+
const topic = cyan(`#${m.topicName}`);
|
|
7209
|
+
const sender = m.senderName;
|
|
7210
|
+
const ago = formatRelativeTime(m.createdAt);
|
|
7211
|
+
const snippet = m.snippet ?? (m.bodyVersion === 2 ? dim("[encrypted — open the topic to decrypt]") : dim("[empty]"));
|
|
7212
|
+
const highlighted = m.snippet ? highlightMatch(snippet, flags.query) : snippet;
|
|
7213
|
+
process.stdout.write(` ${slug} ${topic} ${dim(sender + " ·")} ${dim(ago)}
|
|
7214
|
+
` + ` ${highlighted}
|
|
7215
|
+
`);
|
|
7216
|
+
}
|
|
7217
|
+
}
|
|
7218
|
+
return EXIT.SUCCESS;
|
|
7219
|
+
});
|
|
7220
|
+
}
|
|
7221
|
+
function highlightMatch(text, query) {
|
|
7222
|
+
if (!query)
|
|
7223
|
+
return text;
|
|
7224
|
+
const idx = text.toLowerCase().indexOf(query.toLowerCase());
|
|
7225
|
+
if (idx === -1)
|
|
7226
|
+
return text;
|
|
7227
|
+
const before = text.slice(0, idx);
|
|
7228
|
+
const match = text.slice(idx, idx + query.length);
|
|
7229
|
+
const after = text.slice(idx + query.length);
|
|
7230
|
+
return `${before}${yellow(match)}${after}`;
|
|
7231
|
+
}
|
|
7232
|
+
async function runMeTasks(flags) {
|
|
7233
|
+
return withRestKey({
|
|
7234
|
+
meshSlug: resolveMeshForMint(flags.mesh),
|
|
7235
|
+
purpose: "workspace-tasks",
|
|
7236
|
+
capabilities: ["read"]
|
|
7237
|
+
}, async ({ secret }) => {
|
|
7238
|
+
const params = new URLSearchParams;
|
|
7239
|
+
if (flags.status)
|
|
7240
|
+
params.set("status", flags.status);
|
|
7241
|
+
const path = "/api/v1/me/tasks" + (params.toString() ? `?${params.toString()}` : "");
|
|
7242
|
+
const ws = await request({
|
|
7243
|
+
path,
|
|
7244
|
+
token: secret
|
|
7245
|
+
});
|
|
7246
|
+
if (flags.json) {
|
|
7247
|
+
console.log(JSON.stringify(ws, null, 2));
|
|
7248
|
+
return EXIT.SUCCESS;
|
|
7249
|
+
}
|
|
7250
|
+
render.section(`${clay("tasks")} — ${dim(`${ws.totals.open} open · ${ws.totals.claimed} in-flight · ${ws.totals.completed} done`)}`);
|
|
7251
|
+
if (ws.tasks.length === 0) {
|
|
7252
|
+
process.stdout.write(dim(` no tasks in window
|
|
7253
|
+
`));
|
|
7254
|
+
return EXIT.SUCCESS;
|
|
7255
|
+
}
|
|
7256
|
+
const slugWidth = Math.max(...ws.tasks.map((t) => t.meshSlug.length), 6);
|
|
7257
|
+
for (const t of ws.tasks) {
|
|
7258
|
+
const slug = dim(t.meshSlug.padEnd(slugWidth));
|
|
7259
|
+
const status = t.status === "open" ? yellow("open ") : t.status === "claimed" ? cyan("working ") : green("done ");
|
|
7260
|
+
const prio = t.priority === "urgent" ? yellow("!") : t.priority === "low" ? dim("·") : " ";
|
|
7261
|
+
const claimer = t.claimedByName ? dim(` ← ${t.claimedByName}`) : "";
|
|
7262
|
+
process.stdout.write(` ${slug} ${prio} ${status} ${t.title}${claimer}
|
|
7263
|
+
`);
|
|
7264
|
+
}
|
|
7265
|
+
return EXIT.SUCCESS;
|
|
7266
|
+
});
|
|
7267
|
+
}
|
|
7268
|
+
async function runMeState(flags) {
|
|
7269
|
+
return withRestKey({
|
|
7270
|
+
meshSlug: resolveMeshForMint(flags.mesh),
|
|
7271
|
+
purpose: "workspace-state",
|
|
7272
|
+
capabilities: ["read"]
|
|
7273
|
+
}, async ({ secret }) => {
|
|
7274
|
+
const params = new URLSearchParams;
|
|
7275
|
+
if (flags.key)
|
|
7276
|
+
params.set("key", flags.key);
|
|
7277
|
+
const path = "/api/v1/me/state" + (params.toString() ? `?${params.toString()}` : "");
|
|
7278
|
+
const ws = await request({
|
|
7279
|
+
path,
|
|
7280
|
+
token: secret
|
|
7281
|
+
});
|
|
7282
|
+
if (flags.json) {
|
|
7283
|
+
console.log(JSON.stringify(ws, null, 2));
|
|
7284
|
+
return EXIT.SUCCESS;
|
|
7285
|
+
}
|
|
7286
|
+
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"}`)}`);
|
|
7287
|
+
if (ws.entries.length === 0) {
|
|
7288
|
+
process.stdout.write(dim(` no state entries
|
|
7289
|
+
`));
|
|
7290
|
+
return EXIT.SUCCESS;
|
|
7291
|
+
}
|
|
7292
|
+
const slugWidth = Math.max(...ws.entries.map((e) => e.meshSlug.length), 6);
|
|
7293
|
+
const keyWidth = Math.max(...ws.entries.map((e) => e.key.length), 8);
|
|
7294
|
+
for (const e of ws.entries) {
|
|
7295
|
+
const slug = dim(e.meshSlug.padEnd(slugWidth));
|
|
7296
|
+
const key = cyan(e.key.padEnd(keyWidth));
|
|
7297
|
+
const valueStr = typeof e.value === "string" ? e.value : JSON.stringify(e.value);
|
|
7298
|
+
const trimmed = valueStr.length > 80 ? valueStr.slice(0, 80) + "…" : valueStr;
|
|
7299
|
+
const ago = dim(formatRelativeTime(e.updatedAt));
|
|
7300
|
+
process.stdout.write(` ${slug} ${key} ${trimmed} ${ago}
|
|
7301
|
+
`);
|
|
7302
|
+
}
|
|
7303
|
+
return EXIT.SUCCESS;
|
|
7304
|
+
});
|
|
7305
|
+
}
|
|
7306
|
+
async function runMeMemory(flags) {
|
|
7307
|
+
return withRestKey({
|
|
7308
|
+
meshSlug: resolveMeshForMint(flags.mesh),
|
|
7309
|
+
purpose: "workspace-memory",
|
|
7310
|
+
capabilities: ["read"]
|
|
7311
|
+
}, async ({ secret }) => {
|
|
7312
|
+
const params = new URLSearchParams;
|
|
7313
|
+
if (flags.query)
|
|
7314
|
+
params.set("q", flags.query);
|
|
7315
|
+
const path = "/api/v1/me/memory" + (params.toString() ? `?${params.toString()}` : "");
|
|
7316
|
+
const ws = await request({
|
|
7317
|
+
path,
|
|
7318
|
+
token: secret
|
|
7319
|
+
});
|
|
7320
|
+
if (flags.json) {
|
|
7321
|
+
console.log(JSON.stringify(ws, null, 2));
|
|
7322
|
+
return EXIT.SUCCESS;
|
|
7323
|
+
}
|
|
7324
|
+
const headerLabel = flags.query ? `recall — "${flags.query}"` : "recall — last 30 days";
|
|
7325
|
+
render.section(`${clay(headerLabel)} ${dim(`${ws.totals.entries} match${ws.totals.entries === 1 ? "" : "es"}`)}`);
|
|
7326
|
+
if (ws.memories.length === 0) {
|
|
7327
|
+
process.stdout.write(dim(` no memories
|
|
7328
|
+
`));
|
|
7329
|
+
return EXIT.SUCCESS;
|
|
7330
|
+
}
|
|
7331
|
+
const slugWidth = Math.max(...ws.memories.map((m) => m.meshSlug.length), 6);
|
|
7332
|
+
for (const m of ws.memories) {
|
|
7333
|
+
const slug = dim(m.meshSlug.padEnd(slugWidth));
|
|
7334
|
+
const ago = dim(formatRelativeTime(m.rememberedAt));
|
|
7335
|
+
const tags = m.tags.length > 0 ? " " + dim("[" + m.tags.join(", ") + "]") : "";
|
|
7336
|
+
const content = m.content.length > 240 ? m.content.slice(0, 240) + "…" : m.content;
|
|
7337
|
+
process.stdout.write(` ${slug} ${ago}${tags}
|
|
7338
|
+
${content}
|
|
7339
|
+
`);
|
|
7340
|
+
}
|
|
7341
|
+
return EXIT.SUCCESS;
|
|
7342
|
+
});
|
|
7343
|
+
}
|
|
7344
|
+
function formatRelativeTime(iso) {
|
|
7345
|
+
const then = new Date(iso).getTime();
|
|
7346
|
+
const now = Date.now();
|
|
7347
|
+
const sec = Math.max(0, Math.floor((now - then) / 1000));
|
|
7348
|
+
if (sec < 60)
|
|
7349
|
+
return `${sec}s ago`;
|
|
7350
|
+
if (sec < 3600)
|
|
7351
|
+
return `${Math.floor(sec / 60)}m ago`;
|
|
7352
|
+
if (sec < 86400)
|
|
7353
|
+
return `${Math.floor(sec / 3600)}h ago`;
|
|
7354
|
+
if (sec < 86400 * 30)
|
|
7355
|
+
return `${Math.floor(sec / 86400)}d ago`;
|
|
7356
|
+
if (sec < 86400 * 365)
|
|
7357
|
+
return `${Math.floor(sec / (86400 * 30))}mo ago`;
|
|
7358
|
+
return `${Math.floor(sec / (86400 * 365))}y ago`;
|
|
7359
|
+
}
|
|
7360
|
+
var init_me = __esm(() => {
|
|
7361
|
+
init_with_rest_key();
|
|
7362
|
+
init_client();
|
|
7363
|
+
init_facade();
|
|
7364
|
+
init_render();
|
|
7365
|
+
init_styles();
|
|
7366
|
+
init_exit_codes();
|
|
7367
|
+
});
|
|
7368
|
+
|
|
6959
7369
|
// src/commands/info.ts
|
|
6960
7370
|
var exports_info = {};
|
|
6961
7371
|
__export(exports_info, {
|
|
@@ -11590,441 +12000,146 @@ async function runTopicCreate(name, flags) {
|
|
|
11590
12000
|
}
|
|
11591
12001
|
return await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
11592
12002
|
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
|
|
12003
|
+
name,
|
|
12004
|
+
description: flags.description,
|
|
12005
|
+
visibility: flags.visibility
|
|
11832
12006
|
});
|
|
11833
|
-
|
|
11834
|
-
|
|
11835
|
-
|
|
11836
|
-
return EXIT.SUCCESS;
|
|
12007
|
+
if (!result) {
|
|
12008
|
+
render.err("topic create failed");
|
|
12009
|
+
return EXIT.INTERNAL_ERROR;
|
|
11837
12010
|
}
|
|
11838
|
-
|
|
11839
|
-
|
|
11840
|
-
process.stdout.write(dim(flags.unread ? ` no unread topics
|
|
11841
|
-
` : " no topics — run `claudemesh topic create #general`\n"));
|
|
12011
|
+
if (flags.json) {
|
|
12012
|
+
console.log(JSON.stringify(result));
|
|
11842
12013
|
return EXIT.SUCCESS;
|
|
11843
12014
|
}
|
|
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
|
-
`);
|
|
12015
|
+
if (result.created) {
|
|
12016
|
+
render.ok("created", `${clay("#" + name)} ${dim(result.id.slice(0, 8))}`);
|
|
12017
|
+
} else {
|
|
12018
|
+
render.info(dim(`already exists: #${name} ${result.id.slice(0, 8)}`));
|
|
11853
12019
|
}
|
|
11854
12020
|
return EXIT.SUCCESS;
|
|
11855
12021
|
});
|
|
11856
12022
|
}
|
|
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
|
-
});
|
|
12023
|
+
async function runTopicList(flags) {
|
|
12024
|
+
return await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
12025
|
+
const topics = await client.topicList();
|
|
11873
12026
|
if (flags.json) {
|
|
11874
|
-
console.log(JSON.stringify(
|
|
12027
|
+
console.log(JSON.stringify(topics, null, 2));
|
|
11875
12028
|
return EXIT.SUCCESS;
|
|
11876
12029
|
}
|
|
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
|
-
`));
|
|
12030
|
+
if (topics.length === 0) {
|
|
12031
|
+
render.info(dim("no topics in this mesh."));
|
|
11883
12032
|
return EXIT.SUCCESS;
|
|
11884
12033
|
}
|
|
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}
|
|
12034
|
+
render.section(`topics (${topics.length})`);
|
|
12035
|
+
for (const t of topics) {
|
|
12036
|
+
const vis = t.visibility === "public" ? green(t.visibility) : dim(t.visibility);
|
|
12037
|
+
process.stdout.write(` ${clay("#" + t.name)} ${vis} ${dim(`${t.memberCount} member${t.memberCount === 1 ? "" : "s"}`)}
|
|
12038
|
+
`);
|
|
12039
|
+
if (t.description)
|
|
12040
|
+
process.stdout.write(` ${dim(t.description)}
|
|
11895
12041
|
`);
|
|
11896
12042
|
}
|
|
11897
12043
|
return EXIT.SUCCESS;
|
|
11898
12044
|
});
|
|
11899
12045
|
}
|
|
11900
|
-
async function
|
|
11901
|
-
|
|
11902
|
-
|
|
11903
|
-
|
|
11904
|
-
|
|
11905
|
-
|
|
11906
|
-
|
|
11907
|
-
if (flags.
|
|
11908
|
-
|
|
11909
|
-
|
|
11910
|
-
|
|
11911
|
-
|
|
11912
|
-
|
|
11913
|
-
|
|
12046
|
+
async function runTopicJoin(topic, flags) {
|
|
12047
|
+
if (!topic) {
|
|
12048
|
+
render.err("Usage: claudemesh topic join <topic> [--role lead|member|observer]");
|
|
12049
|
+
return EXIT.INVALID_ARGS;
|
|
12050
|
+
}
|
|
12051
|
+
return await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
12052
|
+
await client.topicJoin(topic, flags.role);
|
|
12053
|
+
if (flags.json)
|
|
12054
|
+
console.log(JSON.stringify({ joined: topic }));
|
|
12055
|
+
else
|
|
12056
|
+
render.ok("joined", clay("#" + topic));
|
|
12057
|
+
return EXIT.SUCCESS;
|
|
12058
|
+
});
|
|
12059
|
+
}
|
|
12060
|
+
async function runTopicLeave(topic, flags) {
|
|
12061
|
+
if (!topic) {
|
|
12062
|
+
render.err("Usage: claudemesh topic leave <topic>");
|
|
12063
|
+
return EXIT.INVALID_ARGS;
|
|
12064
|
+
}
|
|
12065
|
+
return await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
12066
|
+
await client.topicLeave(topic);
|
|
12067
|
+
if (flags.json)
|
|
12068
|
+
console.log(JSON.stringify({ left: topic }));
|
|
12069
|
+
else
|
|
12070
|
+
render.ok("left", clay("#" + topic));
|
|
12071
|
+
return EXIT.SUCCESS;
|
|
12072
|
+
});
|
|
12073
|
+
}
|
|
12074
|
+
async function runTopicMembers(topic, flags) {
|
|
12075
|
+
if (!topic) {
|
|
12076
|
+
render.err("Usage: claudemesh topic members <topic>");
|
|
12077
|
+
return EXIT.INVALID_ARGS;
|
|
12078
|
+
}
|
|
12079
|
+
return await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
12080
|
+
const members = await client.topicMembers(topic);
|
|
11914
12081
|
if (flags.json) {
|
|
11915
|
-
console.log(JSON.stringify(
|
|
12082
|
+
console.log(JSON.stringify(members, null, 2));
|
|
11916
12083
|
return EXIT.SUCCESS;
|
|
11917
12084
|
}
|
|
11918
|
-
|
|
11919
|
-
|
|
11920
|
-
process.stdout.write(dim(` quiet — no activity in window
|
|
11921
|
-
`));
|
|
12085
|
+
if (members.length === 0) {
|
|
12086
|
+
render.info(dim(`no members in ${clay("#" + topic)}.`));
|
|
11922
12087
|
return EXIT.SUCCESS;
|
|
11923
12088
|
}
|
|
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}
|
|
12089
|
+
render.section(`${clay("#" + topic)} members (${members.length})`);
|
|
12090
|
+
for (const m of members) {
|
|
12091
|
+
process.stdout.write(` ${bold(m.displayName)} ${dim(m.role)} ${dim(m.pubkey.slice(0, 8))}
|
|
11933
12092
|
`);
|
|
11934
12093
|
}
|
|
11935
12094
|
return EXIT.SUCCESS;
|
|
11936
12095
|
});
|
|
11937
12096
|
}
|
|
11938
|
-
async function
|
|
11939
|
-
if (!
|
|
11940
|
-
|
|
11941
|
-
`);
|
|
12097
|
+
async function runTopicHistory(topic, flags) {
|
|
12098
|
+
if (!topic) {
|
|
12099
|
+
render.err("Usage: claudemesh topic history <topic> [--limit N] [--before <id>]");
|
|
11942
12100
|
return EXIT.INVALID_ARGS;
|
|
11943
12101
|
}
|
|
11944
|
-
return
|
|
11945
|
-
|
|
11946
|
-
|
|
11947
|
-
|
|
11948
|
-
|
|
11949
|
-
|
|
11950
|
-
const ws = await request({
|
|
11951
|
-
path: `/api/v1/me/search?${params.toString()}`,
|
|
11952
|
-
token: secret
|
|
12102
|
+
return await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
12103
|
+
const limit = flags.limit ? Number(flags.limit) : undefined;
|
|
12104
|
+
const messages = await client.topicHistory({
|
|
12105
|
+
topic,
|
|
12106
|
+
limit,
|
|
12107
|
+
beforeId: flags.before
|
|
11953
12108
|
});
|
|
11954
12109
|
if (flags.json) {
|
|
11955
|
-
console.log(JSON.stringify(
|
|
12110
|
+
console.log(JSON.stringify(messages, null, 2));
|
|
11956
12111
|
return EXIT.SUCCESS;
|
|
11957
12112
|
}
|
|
11958
|
-
|
|
11959
|
-
|
|
11960
|
-
process.stdout.write(dim(` no matches
|
|
11961
|
-
`));
|
|
12113
|
+
if (messages.length === 0) {
|
|
12114
|
+
render.info(dim(`no messages in ${clay("#" + topic)}.`));
|
|
11962
12115
|
return EXIT.SUCCESS;
|
|
11963
12116
|
}
|
|
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}
|
|
12117
|
+
const ordered = [...messages].reverse();
|
|
12118
|
+
render.section(`${clay("#" + topic)} history (${ordered.length})`);
|
|
12119
|
+
for (const m of ordered) {
|
|
12120
|
+
const t = new Date(m.createdAt).toLocaleString();
|
|
12121
|
+
process.stdout.write(` ${dim(t)} ${bold(m.senderPubkey.slice(0, 8))} ${dim("(encrypted, " + m.ciphertext.length + "b)")}
|
|
11991
12122
|
`);
|
|
11992
|
-
}
|
|
11993
12123
|
}
|
|
11994
12124
|
return EXIT.SUCCESS;
|
|
11995
12125
|
});
|
|
11996
12126
|
}
|
|
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`;
|
|
12127
|
+
async function runTopicMarkRead(topic, flags) {
|
|
12128
|
+
if (!topic) {
|
|
12129
|
+
render.err("Usage: claudemesh topic read <topic>");
|
|
12130
|
+
return EXIT.INVALID_ARGS;
|
|
12131
|
+
}
|
|
12132
|
+
return await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
12133
|
+
await client.topicMarkRead(topic);
|
|
12134
|
+
if (flags.json)
|
|
12135
|
+
console.log(JSON.stringify({ read: topic }));
|
|
12136
|
+
else
|
|
12137
|
+
render.ok("marked read", clay("#" + topic));
|
|
12138
|
+
return EXIT.SUCCESS;
|
|
12139
|
+
});
|
|
12023
12140
|
}
|
|
12024
|
-
var
|
|
12025
|
-
|
|
12026
|
-
init_client();
|
|
12027
|
-
init_facade();
|
|
12141
|
+
var init_topic = __esm(() => {
|
|
12142
|
+
init_connect();
|
|
12028
12143
|
init_render();
|
|
12029
12144
|
init_styles();
|
|
12030
12145
|
init_exit_codes();
|
|
@@ -14437,6 +14552,10 @@ async function main() {
|
|
|
14437
14552
|
const { runStateSet: runStateSet2 } = await Promise.resolve().then(() => (init_state(), exports_state));
|
|
14438
14553
|
await runStateSet2({}, positionals[1] ?? "", positionals[2] ?? "");
|
|
14439
14554
|
} else if (sub === "list") {
|
|
14555
|
+
if (!flags.mesh) {
|
|
14556
|
+
const { runMeState: runMeState2 } = await Promise.resolve().then(() => (init_me(), exports_me));
|
|
14557
|
+
process.exit(await runMeState2({ json: !!flags.json, key: flags.key }));
|
|
14558
|
+
}
|
|
14440
14559
|
const { runStateList: runStateList2 } = await Promise.resolve().then(() => (init_state(), exports_state));
|
|
14441
14560
|
await runStateList2({});
|
|
14442
14561
|
} else {
|
|
@@ -14456,6 +14575,10 @@ async function main() {
|
|
|
14456
14575
|
break;
|
|
14457
14576
|
}
|
|
14458
14577
|
case "recall": {
|
|
14578
|
+
if (!flags.mesh) {
|
|
14579
|
+
const { runMeMemory: runMeMemory2 } = await Promise.resolve().then(() => (init_me(), exports_me));
|
|
14580
|
+
process.exit(await runMeMemory2({ json: !!flags.json, query: positionals.join(" ") }));
|
|
14581
|
+
}
|
|
14459
14582
|
const { recall: recall2 } = await Promise.resolve().then(() => (init_recall(), exports_recall));
|
|
14460
14583
|
process.exit(await recall2(positionals.join(" "), { mesh: flags.mesh, json: !!flags.json }));
|
|
14461
14584
|
break;
|
|
@@ -15132,6 +15255,10 @@ async function main() {
|
|
|
15132
15255
|
const { runTaskComplete: runTaskComplete2 } = await Promise.resolve().then(() => (init_broker_actions(), exports_broker_actions));
|
|
15133
15256
|
process.exit(await runTaskComplete2(positionals[1], positionals.slice(2).join(" ") || undefined, f));
|
|
15134
15257
|
} else if (sub === "list") {
|
|
15258
|
+
if (!f.mesh) {
|
|
15259
|
+
const { runMeTasks: runMeTasks2 } = await Promise.resolve().then(() => (init_me(), exports_me));
|
|
15260
|
+
process.exit(await runMeTasks2({ json: f.json, status: flags.status }));
|
|
15261
|
+
}
|
|
15135
15262
|
const { runTaskList: runTaskList2 } = await Promise.resolve().then(() => (init_platform_actions(), exports_platform_actions));
|
|
15136
15263
|
process.exit(await runTaskList2({ ...f, status: flags.status, assignee: flags.assignee }));
|
|
15137
15264
|
} else if (sub === "create") {
|
|
@@ -15170,4 +15297,4 @@ main().catch((err) => {
|
|
|
15170
15297
|
process.exit(EXIT.INTERNAL_ERROR);
|
|
15171
15298
|
});
|
|
15172
15299
|
|
|
15173
|
-
//# debugId=
|
|
15300
|
+
//# debugId=BDE3C231AF7C585064756E2164756E21
|