@hasna/conversations 0.1.17 → 0.1.19
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/bin/hook.js +51 -0
- package/bin/index.js +619 -304
- package/bin/mcp.js +312 -89
- package/dashboard/dist/assets/index-Bw0wMcXE.js +186 -0
- package/dashboard/dist/assets/index-CF_GDtNp.css +1 -0
- package/dashboard/dist/index.html +2 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +289 -16
- package/dist/lib/messages.d.ts +3 -0
- package/dist/lib/reactions.d.ts +10 -0
- package/dist/lib/reactions.test.d.ts +1 -0
- package/dist/lib/terminal-markdown.d.ts +11 -0
- package/dist/lib/webhooks.d.ts +11 -0
- package/dist/lib/webhooks.test.d.ts +1 -0
- package/dist/types.d.ts +21 -0
- package/package.json +1 -1
- package/dashboard/dist/assets/index-CCdh63JU.js +0 -186
- package/dashboard/dist/assets/index-VFT0_0LI.css +0 -1
package/bin/index.js
CHANGED
|
@@ -1974,6 +1974,17 @@ function getDb() {
|
|
|
1974
1974
|
metadata TEXT
|
|
1975
1975
|
)
|
|
1976
1976
|
`);
|
|
1977
|
+
db.exec(`
|
|
1978
|
+
CREATE TABLE IF NOT EXISTS reactions (
|
|
1979
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1980
|
+
message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE,
|
|
1981
|
+
agent TEXT NOT NULL,
|
|
1982
|
+
emoji TEXT NOT NULL,
|
|
1983
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
|
|
1984
|
+
UNIQUE(message_id, agent, emoji)
|
|
1985
|
+
)
|
|
1986
|
+
`);
|
|
1987
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_reactions_message ON reactions(message_id)");
|
|
1977
1988
|
const existingTables = db.prepare("SELECT name FROM sqlite_master WHERE type='table'").all();
|
|
1978
1989
|
const tableNames = existingTables.map((t) => t.name);
|
|
1979
1990
|
if (tableNames.includes("channels") && tableNames.includes("spaces")) {
|
|
@@ -2031,6 +2042,46 @@ function getDb() {
|
|
|
2031
2042
|
db.exec("ALTER TABLE messages ADD COLUMN blocking INTEGER NOT NULL DEFAULT 0");
|
|
2032
2043
|
db.exec("CREATE INDEX IF NOT EXISTS idx_messages_blocking ON messages(blocking)");
|
|
2033
2044
|
}
|
|
2045
|
+
if (!colNames2.includes("attachments")) {
|
|
2046
|
+
db.exec("ALTER TABLE messages ADD COLUMN attachments TEXT");
|
|
2047
|
+
}
|
|
2048
|
+
if (!colNames2.includes("reply_to")) {
|
|
2049
|
+
db.exec("ALTER TABLE messages ADD COLUMN reply_to INTEGER REFERENCES messages(id)");
|
|
2050
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_messages_reply_to ON messages(reply_to)");
|
|
2051
|
+
}
|
|
2052
|
+
const ftsExists = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='messages_fts'").get();
|
|
2053
|
+
if (!ftsExists) {
|
|
2054
|
+
db.exec(`
|
|
2055
|
+
CREATE VIRTUAL TABLE messages_fts USING fts5(
|
|
2056
|
+
content, from_agent, to_agent, space,
|
|
2057
|
+
content_rowid='id', content='messages'
|
|
2058
|
+
)
|
|
2059
|
+
`);
|
|
2060
|
+
db.exec(`
|
|
2061
|
+
INSERT INTO messages_fts(rowid, content, from_agent, to_agent, space)
|
|
2062
|
+
SELECT id, content, from_agent, to_agent, space FROM messages
|
|
2063
|
+
`);
|
|
2064
|
+
db.exec(`
|
|
2065
|
+
CREATE TRIGGER IF NOT EXISTS messages_fts_insert AFTER INSERT ON messages BEGIN
|
|
2066
|
+
INSERT INTO messages_fts(rowid, content, from_agent, to_agent, space)
|
|
2067
|
+
VALUES (new.id, new.content, new.from_agent, new.to_agent, new.space);
|
|
2068
|
+
END
|
|
2069
|
+
`);
|
|
2070
|
+
db.exec(`
|
|
2071
|
+
CREATE TRIGGER IF NOT EXISTS messages_fts_delete AFTER DELETE ON messages BEGIN
|
|
2072
|
+
INSERT INTO messages_fts(messages_fts, rowid, content, from_agent, to_agent, space)
|
|
2073
|
+
VALUES ('delete', old.id, old.content, old.from_agent, old.to_agent, old.space);
|
|
2074
|
+
END
|
|
2075
|
+
`);
|
|
2076
|
+
db.exec(`
|
|
2077
|
+
CREATE TRIGGER IF NOT EXISTS messages_fts_update AFTER UPDATE OF content ON messages BEGIN
|
|
2078
|
+
INSERT INTO messages_fts(messages_fts, rowid, content, from_agent, to_agent, space)
|
|
2079
|
+
VALUES ('delete', old.id, old.content, old.from_agent, old.to_agent, old.space);
|
|
2080
|
+
INSERT INTO messages_fts(rowid, content, from_agent, to_agent, space)
|
|
2081
|
+
VALUES (new.id, new.content, new.from_agent, new.to_agent, new.space);
|
|
2082
|
+
END
|
|
2083
|
+
`);
|
|
2084
|
+
}
|
|
2034
2085
|
return db;
|
|
2035
2086
|
}
|
|
2036
2087
|
function closeDb() {
|
|
@@ -2042,8 +2093,84 @@ function closeDb() {
|
|
|
2042
2093
|
var db = null;
|
|
2043
2094
|
var init_db = () => {};
|
|
2044
2095
|
|
|
2096
|
+
// src/lib/webhooks.ts
|
|
2097
|
+
import { readFileSync } from "fs";
|
|
2098
|
+
import { join as join2 } from "path";
|
|
2099
|
+
import { homedir as homedir2 } from "os";
|
|
2100
|
+
function getConfigPath() {
|
|
2101
|
+
return process.env.CONVERSATIONS_CONFIG_PATH || join2(homedir2(), ".conversations", "config.json");
|
|
2102
|
+
}
|
|
2103
|
+
function loadConfig() {
|
|
2104
|
+
const now = Date.now();
|
|
2105
|
+
if (cachedConfig && now - configLoadedAt < CONFIG_CACHE_MS)
|
|
2106
|
+
return cachedConfig;
|
|
2107
|
+
try {
|
|
2108
|
+
const raw = readFileSync(getConfigPath(), "utf-8");
|
|
2109
|
+
cachedConfig = JSON.parse(raw);
|
|
2110
|
+
configLoadedAt = now;
|
|
2111
|
+
return cachedConfig;
|
|
2112
|
+
} catch {
|
|
2113
|
+
cachedConfig = {};
|
|
2114
|
+
configLoadedAt = now;
|
|
2115
|
+
return cachedConfig;
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
2118
|
+
function matchesEvent(webhook, msg) {
|
|
2119
|
+
for (const event of webhook.events) {
|
|
2120
|
+
if (event === "dm" && !msg.space)
|
|
2121
|
+
return true;
|
|
2122
|
+
if (event === "blocker" && msg.blocking)
|
|
2123
|
+
return true;
|
|
2124
|
+
if (event === "space" && msg.space)
|
|
2125
|
+
return true;
|
|
2126
|
+
if (event === "mention" && webhook.agent && msg.content.includes(`@${webhook.agent}`))
|
|
2127
|
+
return true;
|
|
2128
|
+
}
|
|
2129
|
+
return false;
|
|
2130
|
+
}
|
|
2131
|
+
function fireWebhooks(msg) {
|
|
2132
|
+
const config = loadConfig();
|
|
2133
|
+
if (!config.webhooks || config.webhooks.length === 0)
|
|
2134
|
+
return;
|
|
2135
|
+
for (const webhook of config.webhooks) {
|
|
2136
|
+
if (webhook.agent && msg.to_agent !== webhook.agent && !msg.space)
|
|
2137
|
+
continue;
|
|
2138
|
+
if (!matchesEvent(webhook, msg))
|
|
2139
|
+
continue;
|
|
2140
|
+
fetch(webhook.url, {
|
|
2141
|
+
method: "POST",
|
|
2142
|
+
headers: { "Content-Type": "application/json" },
|
|
2143
|
+
body: JSON.stringify({
|
|
2144
|
+
id: msg.id,
|
|
2145
|
+
from: msg.from_agent,
|
|
2146
|
+
to: msg.to_agent,
|
|
2147
|
+
space: msg.space,
|
|
2148
|
+
content: msg.content,
|
|
2149
|
+
priority: msg.priority,
|
|
2150
|
+
blocking: msg.blocking,
|
|
2151
|
+
created_at: msg.created_at
|
|
2152
|
+
})
|
|
2153
|
+
}).catch(() => {});
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
var cachedConfig = null, configLoadedAt = 0, CONFIG_CACHE_MS = 1e4;
|
|
2157
|
+
var init_webhooks = () => {};
|
|
2158
|
+
|
|
2045
2159
|
// src/lib/messages.ts
|
|
2046
2160
|
import { randomUUID } from "crypto";
|
|
2161
|
+
import { mkdirSync as mkdirSync2, copyFileSync, statSync } from "fs";
|
|
2162
|
+
import { join as join3 } from "path";
|
|
2163
|
+
import { homedir as homedir3 } from "os";
|
|
2164
|
+
function compactMessage(msg) {
|
|
2165
|
+
const result = {};
|
|
2166
|
+
for (const key of Object.keys(msg)) {
|
|
2167
|
+
const val = msg[key];
|
|
2168
|
+
if (val !== null && val !== undefined) {
|
|
2169
|
+
result[key] = val;
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
return result;
|
|
2173
|
+
}
|
|
2047
2174
|
function parseMessage(row) {
|
|
2048
2175
|
let metadata = null;
|
|
2049
2176
|
if (row.metadata) {
|
|
@@ -2053,11 +2180,53 @@ function parseMessage(row) {
|
|
|
2053
2180
|
metadata = null;
|
|
2054
2181
|
}
|
|
2055
2182
|
}
|
|
2183
|
+
let attachments = null;
|
|
2184
|
+
if (row.attachments) {
|
|
2185
|
+
try {
|
|
2186
|
+
attachments = JSON.parse(row.attachments);
|
|
2187
|
+
} catch {
|
|
2188
|
+
attachments = null;
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
2056
2191
|
return {
|
|
2057
2192
|
...row,
|
|
2058
2193
|
metadata,
|
|
2059
|
-
|
|
2060
|
-
|
|
2194
|
+
attachments,
|
|
2195
|
+
blocking: !!row.blocking,
|
|
2196
|
+
reply_to: row.reply_to || null
|
|
2197
|
+
};
|
|
2198
|
+
}
|
|
2199
|
+
function getAttachmentsDir() {
|
|
2200
|
+
if (process.env.CONVERSATIONS_ATTACHMENTS_DIR)
|
|
2201
|
+
return process.env.CONVERSATIONS_ATTACHMENTS_DIR;
|
|
2202
|
+
return join3(homedir3(), ".conversations", "attachments");
|
|
2203
|
+
}
|
|
2204
|
+
function guessMimeType(name) {
|
|
2205
|
+
const ext = name.split(".").pop()?.toLowerCase();
|
|
2206
|
+
const mimeMap = {
|
|
2207
|
+
txt: "text/plain",
|
|
2208
|
+
md: "text/markdown",
|
|
2209
|
+
json: "application/json",
|
|
2210
|
+
js: "text/javascript",
|
|
2211
|
+
ts: "text/typescript",
|
|
2212
|
+
py: "text/x-python",
|
|
2213
|
+
html: "text/html",
|
|
2214
|
+
css: "text/css",
|
|
2215
|
+
xml: "application/xml",
|
|
2216
|
+
png: "image/png",
|
|
2217
|
+
jpg: "image/jpeg",
|
|
2218
|
+
jpeg: "image/jpeg",
|
|
2219
|
+
gif: "image/gif",
|
|
2220
|
+
svg: "image/svg+xml",
|
|
2221
|
+
webp: "image/webp",
|
|
2222
|
+
pdf: "application/pdf",
|
|
2223
|
+
zip: "application/zip",
|
|
2224
|
+
gz: "application/gzip",
|
|
2225
|
+
csv: "text/csv",
|
|
2226
|
+
yaml: "text/yaml",
|
|
2227
|
+
yml: "text/yaml"
|
|
2228
|
+
};
|
|
2229
|
+
return mimeMap[ext || ""] || "application/octet-stream";
|
|
2061
2230
|
}
|
|
2062
2231
|
function sendMessage(opts) {
|
|
2063
2232
|
const db2 = getDb();
|
|
@@ -2066,13 +2235,35 @@ function sendMessage(opts) {
|
|
|
2066
2235
|
const metadata = opts.metadata ? JSON.stringify(opts.metadata) : null;
|
|
2067
2236
|
const normalizedPriority = opts.priority === "low" || opts.priority === "normal" || opts.priority === "high" || opts.priority === "urgent" ? opts.priority : "normal";
|
|
2068
2237
|
const blocking = opts.blocking ? 1 : 0;
|
|
2238
|
+
const replyTo = opts.reply_to || null;
|
|
2069
2239
|
const stmt = db2.prepare(`
|
|
2070
|
-
INSERT INTO messages (session_id, from_agent, to_agent, space, content, priority, working_dir, repository, branch, metadata, blocking)
|
|
2071
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
2240
|
+
INSERT INTO messages (session_id, from_agent, to_agent, space, content, priority, working_dir, repository, branch, metadata, blocking, reply_to)
|
|
2241
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
2072
2242
|
RETURNING *
|
|
2073
2243
|
`);
|
|
2074
|
-
const row = stmt.get(sessionId, opts.from, opts.to, opts.space || null, opts.content, normalizedPriority, opts.working_dir || null, opts.repository || null, opts.branch || null, metadata, blocking);
|
|
2075
|
-
|
|
2244
|
+
const row = stmt.get(sessionId, opts.from, opts.to, opts.space || null, opts.content, normalizedPriority, opts.working_dir || null, opts.repository || null, opts.branch || null, metadata, blocking, replyTo);
|
|
2245
|
+
const message = parseMessage(row);
|
|
2246
|
+
if (opts.attachments && opts.attachments.length > 0) {
|
|
2247
|
+
const attachmentsDir = join3(getAttachmentsDir(), String(message.id));
|
|
2248
|
+
mkdirSync2(attachmentsDir, { recursive: true });
|
|
2249
|
+
const attachmentInfos = [];
|
|
2250
|
+
for (const att of opts.attachments) {
|
|
2251
|
+
const destPath = join3(attachmentsDir, att.name);
|
|
2252
|
+
copyFileSync(att.source_path, destPath);
|
|
2253
|
+
const stat = statSync(destPath);
|
|
2254
|
+
attachmentInfos.push({
|
|
2255
|
+
name: att.name,
|
|
2256
|
+
path: destPath,
|
|
2257
|
+
size: stat.size,
|
|
2258
|
+
mime_type: guessMimeType(att.name)
|
|
2259
|
+
});
|
|
2260
|
+
}
|
|
2261
|
+
const attachmentsJson = JSON.stringify(attachmentInfos);
|
|
2262
|
+
db2.prepare("UPDATE messages SET attachments = ? WHERE id = ?").run(attachmentsJson, message.id);
|
|
2263
|
+
message.attachments = attachmentInfos;
|
|
2264
|
+
}
|
|
2265
|
+
fireWebhooks(message);
|
|
2266
|
+
return message;
|
|
2076
2267
|
}
|
|
2077
2268
|
function readMessages(opts = {}) {
|
|
2078
2269
|
const db2 = getDb();
|
|
@@ -2106,10 +2297,13 @@ function readMessages(opts = {}) {
|
|
|
2106
2297
|
conditions.push("read_at IS NULL");
|
|
2107
2298
|
}
|
|
2108
2299
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2109
|
-
const
|
|
2300
|
+
const resolvedLimit = Number.isFinite(opts.limit) && opts.limit > 0 ? Math.floor(opts.limit) : 20;
|
|
2110
2301
|
const order = opts.order?.toLowerCase() === "desc" ? "DESC" : "ASC";
|
|
2111
|
-
const rows = db2.prepare(`SELECT * FROM messages ${where} ORDER BY created_at ${order}, id ${order} ${
|
|
2112
|
-
|
|
2302
|
+
const rows = db2.prepare(`SELECT * FROM messages ${where} ORDER BY created_at ${order}, id ${order} LIMIT ${resolvedLimit}`).all(...params);
|
|
2303
|
+
const messages = rows.map(parseMessage);
|
|
2304
|
+
if (opts.compact)
|
|
2305
|
+
return messages.map(compactMessage);
|
|
2306
|
+
return messages;
|
|
2113
2307
|
}
|
|
2114
2308
|
function markRead(ids, reader) {
|
|
2115
2309
|
const db2 = getDb();
|
|
@@ -2255,6 +2449,33 @@ function getUnreadBlockers(agent) {
|
|
|
2255
2449
|
}
|
|
2256
2450
|
function searchMessages(opts) {
|
|
2257
2451
|
const db2 = getDb();
|
|
2452
|
+
const limit = Number.isFinite(opts.limit) && opts.limit > 0 ? Math.floor(opts.limit) : 20;
|
|
2453
|
+
try {
|
|
2454
|
+
const ftsConditions = [];
|
|
2455
|
+
const ftsParams = [];
|
|
2456
|
+
const words = opts.query.trim().split(/\s+/).filter(Boolean);
|
|
2457
|
+
const ftsQuery = words.map((w) => `"${w.replace(/"/g, '""')}"`).join(" ");
|
|
2458
|
+
ftsConditions.push("messages_fts MATCH ?");
|
|
2459
|
+
ftsParams.push(ftsQuery);
|
|
2460
|
+
let extraWhere = "";
|
|
2461
|
+
if (opts.space) {
|
|
2462
|
+
extraWhere += " AND m.space = ?";
|
|
2463
|
+
ftsParams.push(opts.space);
|
|
2464
|
+
}
|
|
2465
|
+
if (opts.from) {
|
|
2466
|
+
extraWhere += " AND m.from_agent = ?";
|
|
2467
|
+
ftsParams.push(opts.from);
|
|
2468
|
+
}
|
|
2469
|
+
if (opts.to) {
|
|
2470
|
+
extraWhere += " AND m.to_agent = ?";
|
|
2471
|
+
ftsParams.push(opts.to);
|
|
2472
|
+
}
|
|
2473
|
+
const rows2 = db2.prepare(`SELECT m.* FROM messages m
|
|
2474
|
+
JOIN messages_fts ON messages_fts.rowid = m.id
|
|
2475
|
+
WHERE ${ftsConditions.join(" AND ")}${extraWhere}
|
|
2476
|
+
ORDER BY m.created_at DESC, m.id DESC LIMIT ${limit}`).all(...ftsParams);
|
|
2477
|
+
return rows2.map(parseMessage);
|
|
2478
|
+
} catch {}
|
|
2258
2479
|
const conditions = ["content LIKE ?"];
|
|
2259
2480
|
const params = [`%${opts.query}%`];
|
|
2260
2481
|
if (opts.space) {
|
|
@@ -2269,13 +2490,13 @@ function searchMessages(opts) {
|
|
|
2269
2490
|
conditions.push("to_agent = ?");
|
|
2270
2491
|
params.push(opts.to);
|
|
2271
2492
|
}
|
|
2272
|
-
const limit = Number.isFinite(opts.limit) && opts.limit > 0 ? Math.floor(opts.limit) : 50;
|
|
2273
2493
|
const where = `WHERE ${conditions.join(" AND ")}`;
|
|
2274
2494
|
const rows = db2.prepare(`SELECT * FROM messages ${where} ORDER BY created_at DESC, id DESC LIMIT ${limit}`).all(...params);
|
|
2275
2495
|
return rows.map(parseMessage);
|
|
2276
2496
|
}
|
|
2277
2497
|
var init_messages = __esm(() => {
|
|
2278
2498
|
init_db();
|
|
2499
|
+
init_webhooks();
|
|
2279
2500
|
});
|
|
2280
2501
|
|
|
2281
2502
|
// src/lib/sessions.ts
|
|
@@ -3012,9 +3233,9 @@ var init_names = __esm(() => {
|
|
|
3012
3233
|
});
|
|
3013
3234
|
|
|
3014
3235
|
// src/lib/identity.ts
|
|
3015
|
-
import { readFileSync, writeFileSync, mkdirSync as
|
|
3016
|
-
import { join as
|
|
3017
|
-
import { homedir as
|
|
3236
|
+
import { readFileSync as readFileSync2, writeFileSync, mkdirSync as mkdirSync3 } from "fs";
|
|
3237
|
+
import { join as join4, dirname as dirname2 } from "path";
|
|
3238
|
+
import { homedir as homedir4 } from "os";
|
|
3018
3239
|
function isNameTaken(name) {
|
|
3019
3240
|
try {
|
|
3020
3241
|
const { getDb: getDb2 } = (init_db(), __toCommonJS(exports_db));
|
|
@@ -3029,7 +3250,7 @@ function getAutoName() {
|
|
|
3029
3250
|
if (cachedAutoName)
|
|
3030
3251
|
return cachedAutoName;
|
|
3031
3252
|
try {
|
|
3032
|
-
const name2 =
|
|
3253
|
+
const name2 = readFileSync2(AGENT_ID_FILE, "utf-8").trim();
|
|
3033
3254
|
if (name2) {
|
|
3034
3255
|
cachedAutoName = name2;
|
|
3035
3256
|
return name2;
|
|
@@ -3045,7 +3266,7 @@ function getAutoName() {
|
|
|
3045
3266
|
}
|
|
3046
3267
|
cachedAutoName = name;
|
|
3047
3268
|
try {
|
|
3048
|
-
|
|
3269
|
+
mkdirSync3(dirname2(AGENT_ID_FILE), { recursive: true });
|
|
3049
3270
|
writeFileSync(AGENT_ID_FILE, name + `
|
|
3050
3271
|
`, "utf-8");
|
|
3051
3272
|
} catch {}
|
|
@@ -3063,7 +3284,7 @@ function resolveIdentity(explicit) {
|
|
|
3063
3284
|
var AGENT_ID_FILE, cachedAutoName = null;
|
|
3064
3285
|
var init_identity = __esm(() => {
|
|
3065
3286
|
init_names();
|
|
3066
|
-
AGENT_ID_FILE =
|
|
3287
|
+
AGENT_ID_FILE = join4(homedir4(), ".conversations", "agent-id");
|
|
3067
3288
|
});
|
|
3068
3289
|
|
|
3069
3290
|
// src/lib/presence.ts
|
|
@@ -3101,6 +3322,11 @@ function heartbeat(agent, status, metadata) {
|
|
|
3101
3322
|
metadata = excluded.metadata
|
|
3102
3323
|
`).run(agent, resolvedStatus, metadataJson);
|
|
3103
3324
|
}
|
|
3325
|
+
function getPresence(agent) {
|
|
3326
|
+
const db2 = getDb();
|
|
3327
|
+
const row = db2.prepare("SELECT * FROM agent_presence WHERE agent = ?").get(agent);
|
|
3328
|
+
return row ? parsePresence(row) : null;
|
|
3329
|
+
}
|
|
3104
3330
|
function listAgents(opts) {
|
|
3105
3331
|
const db2 = getDb();
|
|
3106
3332
|
let query = "SELECT * FROM agent_presence";
|
|
@@ -3133,6 +3359,52 @@ var init_presence = __esm(() => {
|
|
|
3133
3359
|
init_db();
|
|
3134
3360
|
});
|
|
3135
3361
|
|
|
3362
|
+
// src/lib/terminal-markdown.ts
|
|
3363
|
+
var exports_terminal_markdown = {};
|
|
3364
|
+
__export(exports_terminal_markdown, {
|
|
3365
|
+
renderInline: () => renderInline,
|
|
3366
|
+
renderContent: () => renderContent
|
|
3367
|
+
});
|
|
3368
|
+
import chalk from "chalk";
|
|
3369
|
+
var renderInline = (text) => {
|
|
3370
|
+
return text.replace(/`([^`]+)`/g, (_, code) => chalk.bgGray.white(` ${code} `)).replace(/\*\*\*(.+?)\*\*\*/g, (_, t) => chalk.bold.italic(t)).replace(/\*\*(.+?)\*\*/g, (_, t) => chalk.bold(t)).replace(/\*(.+?)\*/g, (_, t) => chalk.italic(t)).replace(/~~(.+?)~~/g, (_, t) => chalk.strikethrough(t));
|
|
3371
|
+
}, renderContent = (content) => {
|
|
3372
|
+
const lines = content.split(`
|
|
3373
|
+
`);
|
|
3374
|
+
const rendered = [];
|
|
3375
|
+
for (const line of lines) {
|
|
3376
|
+
let l = line;
|
|
3377
|
+
const h = l.match(/^(#{1,3})\s+(.+)/);
|
|
3378
|
+
if (h) {
|
|
3379
|
+
rendered.push(chalk.bold(h[2]));
|
|
3380
|
+
continue;
|
|
3381
|
+
}
|
|
3382
|
+
if (/^\s*[-*+]\s/.test(l)) {
|
|
3383
|
+
rendered.push(" " + chalk.dim("\u2022") + " " + renderInline(l.replace(/^\s*[-*+]\s/, "")));
|
|
3384
|
+
continue;
|
|
3385
|
+
}
|
|
3386
|
+
const ol = l.match(/^\s*(\d+)[.)]\s(.*)/);
|
|
3387
|
+
if (ol) {
|
|
3388
|
+
rendered.push(" " + chalk.dim(ol[1] + ".") + " " + renderInline(ol[2]));
|
|
3389
|
+
continue;
|
|
3390
|
+
}
|
|
3391
|
+
if (l.startsWith(">")) {
|
|
3392
|
+
rendered.push(chalk.dim(" \u2502 ") + chalk.italic(renderInline(l.replace(/^>\s?/, ""))));
|
|
3393
|
+
continue;
|
|
3394
|
+
}
|
|
3395
|
+
if (l.trimStart().startsWith("```"))
|
|
3396
|
+
continue;
|
|
3397
|
+
if (l.trim() === "") {
|
|
3398
|
+
rendered.push("");
|
|
3399
|
+
continue;
|
|
3400
|
+
}
|
|
3401
|
+
rendered.push(renderInline(l));
|
|
3402
|
+
}
|
|
3403
|
+
return rendered.join(`
|
|
3404
|
+
`);
|
|
3405
|
+
};
|
|
3406
|
+
var init_terminal_markdown = () => {};
|
|
3407
|
+
|
|
3136
3408
|
// src/lib/poll.ts
|
|
3137
3409
|
var exports_poll = {};
|
|
3138
3410
|
__export(exports_poll, {
|
|
@@ -3231,7 +3503,7 @@ var init_poll = __esm(() => {
|
|
|
3231
3503
|
var require_package = __commonJS((exports, module) => {
|
|
3232
3504
|
module.exports = {
|
|
3233
3505
|
name: "@hasna/conversations",
|
|
3234
|
-
version: "0.1.
|
|
3506
|
+
version: "0.1.19",
|
|
3235
3507
|
description: "Real-time CLI messaging for AI agents",
|
|
3236
3508
|
type: "module",
|
|
3237
3509
|
bin: {
|
|
@@ -32203,9 +32475,9 @@ var init_mcp2 = __esm(() => {
|
|
|
32203
32475
|
});
|
|
32204
32476
|
server.registerTool("send_message", {
|
|
32205
32477
|
title: "Send Message",
|
|
32206
|
-
description: "Send a direct message to another agent.
|
|
32478
|
+
description: "Send a direct message to another agent.",
|
|
32207
32479
|
inputSchema: {
|
|
32208
|
-
from: exports_external.string().optional().describe("Your agent ID
|
|
32480
|
+
from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
|
|
32209
32481
|
to: exports_external.string().describe("Recipient agent ID"),
|
|
32210
32482
|
content: exports_external.string().describe("Message content"),
|
|
32211
32483
|
session_id: exports_external.string().optional().describe("Session ID (auto-generated if omitted)"),
|
|
@@ -32214,7 +32486,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32214
32486
|
repository: exports_external.string().optional().describe("Repository context"),
|
|
32215
32487
|
branch: exports_external.string().optional().describe("Branch context"),
|
|
32216
32488
|
metadata: exports_external.string().optional().describe("JSON metadata string"),
|
|
32217
|
-
blocking: exports_external.boolean().optional().describe("
|
|
32489
|
+
blocking: exports_external.boolean().optional().describe("Blocking message \u2014 recipients must acknowledge before continuing")
|
|
32218
32490
|
}
|
|
32219
32491
|
}, async ({ from: fromParam, to, content, session_id, priority, working_dir, repository, branch, metadata, blocking }) => {
|
|
32220
32492
|
const from = resolveIdentity(fromParam);
|
|
@@ -32224,7 +32496,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32224
32496
|
parsedMetadata = JSON.parse(metadata);
|
|
32225
32497
|
} catch {
|
|
32226
32498
|
return {
|
|
32227
|
-
content: [{ type: "text", text: "
|
|
32499
|
+
content: [{ type: "text", text: "invalid JSON" }],
|
|
32228
32500
|
isError: true
|
|
32229
32501
|
};
|
|
32230
32502
|
}
|
|
@@ -32250,12 +32522,12 @@ var init_mcp2 = __esm(() => {
|
|
|
32250
32522
|
description: "Read messages with optional filters. Returns messages sorted by time.",
|
|
32251
32523
|
inputSchema: {
|
|
32252
32524
|
session_id: exports_external.string().optional().describe("Filter by session ID"),
|
|
32253
|
-
from: exports_external.string().optional().describe("Filter by sender
|
|
32254
|
-
to: exports_external.string().optional().describe("Filter by recipient
|
|
32525
|
+
from: exports_external.string().optional().describe("Filter by sender"),
|
|
32526
|
+
to: exports_external.string().optional().describe("Filter by recipient"),
|
|
32255
32527
|
space: exports_external.string().optional().describe("Filter by space name"),
|
|
32256
|
-
since: exports_external.string().optional().describe("
|
|
32257
|
-
limit: exports_external.number().optional().describe("Max messages to return"),
|
|
32258
|
-
unread_only: exports_external.boolean().optional().describe("Only
|
|
32528
|
+
since: exports_external.string().optional().describe("ISO timestamp lower bound"),
|
|
32529
|
+
limit: exports_external.number().optional().describe("Max messages to return (default 20)"),
|
|
32530
|
+
unread_only: exports_external.boolean().optional().describe("Only unread messages")
|
|
32259
32531
|
}
|
|
32260
32532
|
}, async (opts) => {
|
|
32261
32533
|
const messages = readMessages(opts);
|
|
@@ -32277,7 +32549,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32277
32549
|
});
|
|
32278
32550
|
server.registerTool("reply", {
|
|
32279
32551
|
title: "Reply to Message",
|
|
32280
|
-
description: "Reply to a message by
|
|
32552
|
+
description: "Reply to a message by ID. Uses the same session and sends to the original sender.",
|
|
32281
32553
|
inputSchema: {
|
|
32282
32554
|
from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
|
|
32283
32555
|
message_id: exports_external.number().describe("ID of the message to reply to"),
|
|
@@ -32309,7 +32581,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32309
32581
|
});
|
|
32310
32582
|
server.registerTool("mark_read", {
|
|
32311
32583
|
title: "Mark Read",
|
|
32312
|
-
description: "Mark
|
|
32584
|
+
description: "Mark messages as read. Provide IDs or set 'all' to true.",
|
|
32313
32585
|
inputSchema: {
|
|
32314
32586
|
from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
|
|
32315
32587
|
ids: exports_external.array(exports_external.number()).optional().describe("Message IDs to mark as read"),
|
|
@@ -32324,7 +32596,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32324
32596
|
count = markRead(ids, agent);
|
|
32325
32597
|
} else {
|
|
32326
32598
|
return {
|
|
32327
|
-
content: [{ type: "text", text: "
|
|
32599
|
+
content: [{ type: "text", text: "provide ids or set all=true" }],
|
|
32328
32600
|
isError: true
|
|
32329
32601
|
};
|
|
32330
32602
|
}
|
|
@@ -32334,13 +32606,13 @@ var init_mcp2 = __esm(() => {
|
|
|
32334
32606
|
});
|
|
32335
32607
|
server.registerTool("search_messages", {
|
|
32336
32608
|
title: "Search Messages",
|
|
32337
|
-
description: "Full-text search across message content
|
|
32609
|
+
description: "Full-text search across message content, newest first.",
|
|
32338
32610
|
inputSchema: {
|
|
32339
|
-
query: exports_external.string().describe("Search query
|
|
32340
|
-
space: exports_external.string().optional().describe("Filter by space
|
|
32341
|
-
from: exports_external.string().optional().describe("Filter by sender
|
|
32342
|
-
to: exports_external.string().optional().describe("Filter by recipient
|
|
32343
|
-
limit: exports_external.number().optional().describe("Max results
|
|
32611
|
+
query: exports_external.string().describe("Search query"),
|
|
32612
|
+
space: exports_external.string().optional().describe("Filter by space"),
|
|
32613
|
+
from: exports_external.string().optional().describe("Filter by sender"),
|
|
32614
|
+
to: exports_external.string().optional().describe("Filter by recipient"),
|
|
32615
|
+
limit: exports_external.number().optional().describe("Max results (default 20)")
|
|
32344
32616
|
}
|
|
32345
32617
|
}, async ({ query, space, from, to, limit }) => {
|
|
32346
32618
|
const messages = searchMessages({ query, space, from, to, limit });
|
|
@@ -32352,11 +32624,11 @@ var init_mcp2 = __esm(() => {
|
|
|
32352
32624
|
title: "Export Messages",
|
|
32353
32625
|
description: "Export messages as JSON or CSV with optional filters.",
|
|
32354
32626
|
inputSchema: {
|
|
32355
|
-
space: exports_external.string().optional().describe("Filter by space
|
|
32627
|
+
space: exports_external.string().optional().describe("Filter by space"),
|
|
32356
32628
|
session_id: exports_external.string().optional().describe("Filter by session ID"),
|
|
32357
|
-
from: exports_external.string().optional().describe("Filter by sender
|
|
32358
|
-
since: exports_external.string().optional().describe("
|
|
32359
|
-
until: exports_external.string().optional().describe("
|
|
32629
|
+
from: exports_external.string().optional().describe("Filter by sender"),
|
|
32630
|
+
since: exports_external.string().optional().describe("ISO date lower bound"),
|
|
32631
|
+
until: exports_external.string().optional().describe("ISO date upper bound"),
|
|
32360
32632
|
format: exports_external.enum(["json", "csv"]).optional().describe("Output format (default: json)")
|
|
32361
32633
|
}
|
|
32362
32634
|
}, async ({ space, session_id, from, since, until, format }) => {
|
|
@@ -32367,13 +32639,13 @@ var init_mcp2 = __esm(() => {
|
|
|
32367
32639
|
});
|
|
32368
32640
|
server.registerTool("create_space", {
|
|
32369
32641
|
title: "Create Space",
|
|
32370
|
-
description: "Create a new space.
|
|
32642
|
+
description: "Create a new space. Creator is auto-joined. Supports nesting (max 3 levels) and project association.",
|
|
32371
32643
|
inputSchema: {
|
|
32372
32644
|
from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
|
|
32373
|
-
name: exports_external.string().describe("Space name
|
|
32645
|
+
name: exports_external.string().describe("Space name"),
|
|
32374
32646
|
description: exports_external.string().optional().describe("Space description"),
|
|
32375
|
-
parent_id: exports_external.string().optional().describe("Parent space name
|
|
32376
|
-
project_id: exports_external.string().optional().describe("Project ID to associate
|
|
32647
|
+
parent_id: exports_external.string().optional().describe("Parent space name (max 3 levels deep)"),
|
|
32648
|
+
project_id: exports_external.string().optional().describe("Project ID to associate with")
|
|
32377
32649
|
}
|
|
32378
32650
|
}, async ({ from: fromParam, name, description, parent_id, project_id }) => {
|
|
32379
32651
|
const agent = resolveIdentity(fromParam);
|
|
@@ -32385,7 +32657,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32385
32657
|
} catch (e) {
|
|
32386
32658
|
if (e.message?.includes("UNIQUE constraint")) {
|
|
32387
32659
|
return {
|
|
32388
|
-
content: [{ type: "text", text: `
|
|
32660
|
+
content: [{ type: "text", text: `space "${name}" already exists` }],
|
|
32389
32661
|
isError: true
|
|
32390
32662
|
};
|
|
32391
32663
|
}
|
|
@@ -32397,11 +32669,11 @@ var init_mcp2 = __esm(() => {
|
|
|
32397
32669
|
});
|
|
32398
32670
|
server.registerTool("list_spaces", {
|
|
32399
32671
|
title: "List Spaces",
|
|
32400
|
-
description: "List
|
|
32672
|
+
description: "List spaces with member/message counts. Archived spaces excluded by default.",
|
|
32401
32673
|
inputSchema: {
|
|
32402
32674
|
project_id: exports_external.string().optional().describe("Filter by project ID"),
|
|
32403
|
-
parent_id: exports_external.string().optional().describe("Filter by parent space
|
|
32404
|
-
include_archived: exports_external.boolean().optional().describe("Include archived spaces
|
|
32675
|
+
parent_id: exports_external.string().optional().describe("Filter by parent space. Use 'null' for top-level only."),
|
|
32676
|
+
include_archived: exports_external.boolean().optional().describe("Include archived spaces")
|
|
32405
32677
|
}
|
|
32406
32678
|
}, async ({ project_id, parent_id, include_archived }) => {
|
|
32407
32679
|
const opts = {};
|
|
@@ -32427,14 +32699,14 @@ var init_mcp2 = __esm(() => {
|
|
|
32427
32699
|
space: exports_external.string().describe("Space name"),
|
|
32428
32700
|
content: exports_external.string().describe("Message content"),
|
|
32429
32701
|
priority: exports_external.enum(["low", "normal", "high", "urgent"]).optional().describe("Message priority"),
|
|
32430
|
-
blocking: exports_external.boolean().optional().describe("
|
|
32702
|
+
blocking: exports_external.boolean().optional().describe("Blocking message \u2014 all space members must acknowledge")
|
|
32431
32703
|
}
|
|
32432
32704
|
}, async ({ from: fromParam, space, content, priority, blocking }) => {
|
|
32433
32705
|
const from = resolveIdentity(fromParam);
|
|
32434
32706
|
const sp = getSpace(space);
|
|
32435
32707
|
if (!sp) {
|
|
32436
32708
|
return {
|
|
32437
|
-
content: [{ type: "text", text: `
|
|
32709
|
+
content: [{ type: "text", text: `space "${space}" not found` }],
|
|
32438
32710
|
isError: true
|
|
32439
32711
|
};
|
|
32440
32712
|
}
|
|
@@ -32456,7 +32728,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32456
32728
|
description: "Read messages from a space.",
|
|
32457
32729
|
inputSchema: {
|
|
32458
32730
|
space: exports_external.string().describe("Space name"),
|
|
32459
|
-
since: exports_external.string().optional().describe("
|
|
32731
|
+
since: exports_external.string().optional().describe("ISO timestamp lower bound"),
|
|
32460
32732
|
limit: exports_external.number().optional().describe("Max messages to return")
|
|
32461
32733
|
}
|
|
32462
32734
|
}, async ({ space, since, limit }) => {
|
|
@@ -32477,7 +32749,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32477
32749
|
const ok = joinSpace(space, agent);
|
|
32478
32750
|
if (!ok) {
|
|
32479
32751
|
return {
|
|
32480
|
-
content: [{ type: "text", text: `
|
|
32752
|
+
content: [{ type: "text", text: `space "${space}" not found` }],
|
|
32481
32753
|
isError: true
|
|
32482
32754
|
};
|
|
32483
32755
|
}
|
|
@@ -32501,12 +32773,12 @@ var init_mcp2 = __esm(() => {
|
|
|
32501
32773
|
});
|
|
32502
32774
|
server.registerTool("update_space", {
|
|
32503
32775
|
title: "Update Space",
|
|
32504
|
-
description: "Update a space's description, parent, or project
|
|
32776
|
+
description: "Update a space's description, parent, or project.",
|
|
32505
32777
|
inputSchema: {
|
|
32506
|
-
name: exports_external.string().describe("Space name
|
|
32778
|
+
name: exports_external.string().describe("Space name"),
|
|
32507
32779
|
description: exports_external.string().optional().describe("New description"),
|
|
32508
|
-
parent_id: exports_external.string().optional().describe("New parent space
|
|
32509
|
-
project_id: exports_external.string().optional().describe("New project ID (use 'null' to remove
|
|
32780
|
+
parent_id: exports_external.string().optional().describe("New parent space (use 'null' to remove)"),
|
|
32781
|
+
project_id: exports_external.string().optional().describe("New project ID (use 'null' to remove)")
|
|
32510
32782
|
}
|
|
32511
32783
|
}, async ({ name, description, parent_id, project_id }) => {
|
|
32512
32784
|
const updates = {};
|
|
@@ -32530,7 +32802,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32530
32802
|
});
|
|
32531
32803
|
server.registerTool("archive_space", {
|
|
32532
32804
|
title: "Archive Space",
|
|
32533
|
-
description: "Archive a space.
|
|
32805
|
+
description: "Archive a space. Hidden from list by default.",
|
|
32534
32806
|
inputSchema: {
|
|
32535
32807
|
name: exports_external.string().describe("Space name to archive")
|
|
32536
32808
|
}
|
|
@@ -32568,16 +32840,16 @@ var init_mcp2 = __esm(() => {
|
|
|
32568
32840
|
});
|
|
32569
32841
|
server.registerTool("create_project", {
|
|
32570
32842
|
title: "Create Project",
|
|
32571
|
-
description: "Create a new project
|
|
32843
|
+
description: "Create a new project to organize spaces and agent collaboration.",
|
|
32572
32844
|
inputSchema: {
|
|
32573
32845
|
from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
|
|
32574
32846
|
name: exports_external.string().describe("Project name (unique)"),
|
|
32575
32847
|
description: exports_external.string().optional().describe("Project description"),
|
|
32576
|
-
path: exports_external.string().optional().describe("Absolute path
|
|
32848
|
+
path: exports_external.string().optional().describe("Absolute path on disk"),
|
|
32577
32849
|
repository: exports_external.string().optional().describe("Repository URL"),
|
|
32578
|
-
tags: exports_external.string().optional().describe(
|
|
32579
|
-
metadata: exports_external.string().optional().describe("JSON metadata
|
|
32580
|
-
settings: exports_external.string().optional().describe("JSON settings
|
|
32850
|
+
tags: exports_external.string().optional().describe("JSON array of tags"),
|
|
32851
|
+
metadata: exports_external.string().optional().describe("JSON metadata"),
|
|
32852
|
+
settings: exports_external.string().optional().describe("JSON settings")
|
|
32581
32853
|
}
|
|
32582
32854
|
}, async ({ from: fromParam, name, description, path, repository, tags, metadata, settings }) => {
|
|
32583
32855
|
const agent = resolveIdentity(fromParam);
|
|
@@ -32587,7 +32859,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32587
32859
|
parsedTags = JSON.parse(tags);
|
|
32588
32860
|
} catch {
|
|
32589
32861
|
return {
|
|
32590
|
-
content: [{ type: "text", text: "
|
|
32862
|
+
content: [{ type: "text", text: "invalid tags JSON (expected array)" }],
|
|
32591
32863
|
isError: true
|
|
32592
32864
|
};
|
|
32593
32865
|
}
|
|
@@ -32598,7 +32870,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32598
32870
|
parsedMetadata = JSON.parse(metadata);
|
|
32599
32871
|
} catch {
|
|
32600
32872
|
return {
|
|
32601
|
-
content: [{ type: "text", text: "
|
|
32873
|
+
content: [{ type: "text", text: "invalid JSON" }],
|
|
32602
32874
|
isError: true
|
|
32603
32875
|
};
|
|
32604
32876
|
}
|
|
@@ -32609,7 +32881,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32609
32881
|
parsedSettings = JSON.parse(settings);
|
|
32610
32882
|
} catch {
|
|
32611
32883
|
return {
|
|
32612
|
-
content: [{ type: "text", text: "
|
|
32884
|
+
content: [{ type: "text", text: "invalid JSON" }],
|
|
32613
32885
|
isError: true
|
|
32614
32886
|
};
|
|
32615
32887
|
}
|
|
@@ -32631,7 +32903,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32631
32903
|
} catch (e) {
|
|
32632
32904
|
if (e.message?.includes("UNIQUE constraint")) {
|
|
32633
32905
|
return {
|
|
32634
|
-
content: [{ type: "text", text: `
|
|
32906
|
+
content: [{ type: "text", text: `project "${name}" already exists` }],
|
|
32635
32907
|
isError: true
|
|
32636
32908
|
};
|
|
32637
32909
|
}
|
|
@@ -32645,7 +32917,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32645
32917
|
title: "List Projects",
|
|
32646
32918
|
description: "List all registered projects.",
|
|
32647
32919
|
inputSchema: {
|
|
32648
|
-
status: exports_external.enum(["active", "archived"]).optional().describe("Filter by
|
|
32920
|
+
status: exports_external.enum(["active", "archived"]).optional().describe("Filter by status")
|
|
32649
32921
|
}
|
|
32650
32922
|
}, async ({ status }) => {
|
|
32651
32923
|
const projects = listProjects(status ? { status } : undefined);
|
|
@@ -32666,7 +32938,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32666
32938
|
}
|
|
32667
32939
|
if (!project) {
|
|
32668
32940
|
return {
|
|
32669
|
-
content: [{ type: "text", text: `
|
|
32941
|
+
content: [{ type: "text", text: `project "${id}" not found` }],
|
|
32670
32942
|
isError: true
|
|
32671
32943
|
};
|
|
32672
32944
|
}
|
|
@@ -32679,14 +32951,14 @@ var init_mcp2 = __esm(() => {
|
|
|
32679
32951
|
description: "Update a project's fields.",
|
|
32680
32952
|
inputSchema: {
|
|
32681
32953
|
id: exports_external.string().describe("Project ID (UUID)"),
|
|
32682
|
-
name: exports_external.string().optional().describe("New
|
|
32954
|
+
name: exports_external.string().optional().describe("New name"),
|
|
32683
32955
|
description: exports_external.string().optional().describe("New description"),
|
|
32684
32956
|
path: exports_external.string().optional().describe("New path"),
|
|
32685
32957
|
status: exports_external.enum(["active", "archived"]).optional().describe("New status"),
|
|
32686
32958
|
repository: exports_external.string().optional().describe("New repository URL"),
|
|
32687
32959
|
tags: exports_external.string().optional().describe("JSON array of tags"),
|
|
32688
|
-
metadata: exports_external.string().optional().describe("JSON metadata
|
|
32689
|
-
settings: exports_external.string().optional().describe("JSON settings
|
|
32960
|
+
metadata: exports_external.string().optional().describe("JSON metadata"),
|
|
32961
|
+
settings: exports_external.string().optional().describe("JSON settings")
|
|
32690
32962
|
}
|
|
32691
32963
|
}, async ({ id, name, description, path, status, repository, tags, metadata, settings }) => {
|
|
32692
32964
|
const updates = {};
|
|
@@ -32705,7 +32977,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32705
32977
|
updates.tags = JSON.parse(tags);
|
|
32706
32978
|
} catch {
|
|
32707
32979
|
return {
|
|
32708
|
-
content: [{ type: "text", text: "
|
|
32980
|
+
content: [{ type: "text", text: "invalid tags JSON" }],
|
|
32709
32981
|
isError: true
|
|
32710
32982
|
};
|
|
32711
32983
|
}
|
|
@@ -32715,7 +32987,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32715
32987
|
updates.metadata = JSON.parse(metadata);
|
|
32716
32988
|
} catch {
|
|
32717
32989
|
return {
|
|
32718
|
-
content: [{ type: "text", text: "
|
|
32990
|
+
content: [{ type: "text", text: "invalid JSON" }],
|
|
32719
32991
|
isError: true
|
|
32720
32992
|
};
|
|
32721
32993
|
}
|
|
@@ -32725,7 +32997,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32725
32997
|
updates.settings = JSON.parse(settings);
|
|
32726
32998
|
} catch {
|
|
32727
32999
|
return {
|
|
32728
|
-
content: [{ type: "text", text: "
|
|
33000
|
+
content: [{ type: "text", text: "invalid JSON" }],
|
|
32729
33001
|
isError: true
|
|
32730
33002
|
};
|
|
32731
33003
|
}
|
|
@@ -32744,7 +33016,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32744
33016
|
});
|
|
32745
33017
|
server.registerTool("delete_project", {
|
|
32746
33018
|
title: "Delete Project",
|
|
32747
|
-
description: "Delete a project permanently. Fails if spaces
|
|
33019
|
+
description: "Delete a project permanently. Fails if spaces reference it.",
|
|
32748
33020
|
inputSchema: {
|
|
32749
33021
|
id: exports_external.string().describe("Project ID (UUID)")
|
|
32750
33022
|
}
|
|
@@ -32753,7 +33025,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32753
33025
|
const deleted = deleteProject(id);
|
|
32754
33026
|
if (!deleted) {
|
|
32755
33027
|
return {
|
|
32756
|
-
content: [{ type: "text", text: `
|
|
33028
|
+
content: [{ type: "text", text: `project "${id}" not found` }],
|
|
32757
33029
|
isError: true
|
|
32758
33030
|
};
|
|
32759
33031
|
}
|
|
@@ -32779,7 +33051,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32779
33051
|
const deleted = deleteMessage(id, agent);
|
|
32780
33052
|
if (!deleted) {
|
|
32781
33053
|
return {
|
|
32782
|
-
content: [{ type: "text", text: `
|
|
33054
|
+
content: [{ type: "text", text: `not found or forbidden` }],
|
|
32783
33055
|
isError: true
|
|
32784
33056
|
};
|
|
32785
33057
|
}
|
|
@@ -32800,7 +33072,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32800
33072
|
const msg = editMessage(id, agent, content);
|
|
32801
33073
|
if (!msg) {
|
|
32802
33074
|
return {
|
|
32803
|
-
content: [{ type: "text", text: `
|
|
33075
|
+
content: [{ type: "text", text: `not found or forbidden` }],
|
|
32804
33076
|
isError: true
|
|
32805
33077
|
};
|
|
32806
33078
|
}
|
|
@@ -32810,7 +33082,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32810
33082
|
});
|
|
32811
33083
|
server.registerTool("pin_message", {
|
|
32812
33084
|
title: "Pin Message",
|
|
32813
|
-
description: "Pin a message.
|
|
33085
|
+
description: "Pin a message. Retrieve pinned messages with get_pinned_messages.",
|
|
32814
33086
|
inputSchema: {
|
|
32815
33087
|
id: exports_external.number().describe("Message ID to pin")
|
|
32816
33088
|
}
|
|
@@ -32818,7 +33090,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32818
33090
|
const msg = pinMessage(id);
|
|
32819
33091
|
if (!msg) {
|
|
32820
33092
|
return {
|
|
32821
|
-
content: [{ type: "text", text: `
|
|
33093
|
+
content: [{ type: "text", text: `message #${id} not found` }],
|
|
32822
33094
|
isError: true
|
|
32823
33095
|
};
|
|
32824
33096
|
}
|
|
@@ -32836,7 +33108,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32836
33108
|
const msg = unpinMessage(id);
|
|
32837
33109
|
if (!msg) {
|
|
32838
33110
|
return {
|
|
32839
|
-
content: [{ type: "text", text: `
|
|
33111
|
+
content: [{ type: "text", text: `message #${id} not found` }],
|
|
32840
33112
|
isError: true
|
|
32841
33113
|
};
|
|
32842
33114
|
}
|
|
@@ -32848,7 +33120,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32848
33120
|
title: "Get Pinned Messages",
|
|
32849
33121
|
description: "Retrieve pinned messages, optionally filtered by space or session.",
|
|
32850
33122
|
inputSchema: {
|
|
32851
|
-
space: exports_external.string().optional().describe("Filter by space
|
|
33123
|
+
space: exports_external.string().optional().describe("Filter by space"),
|
|
32852
33124
|
session_id: exports_external.string().optional().describe("Filter by session ID"),
|
|
32853
33125
|
limit: exports_external.number().optional().describe("Max messages to return")
|
|
32854
33126
|
}
|
|
@@ -32874,9 +33146,9 @@ var init_mcp2 = __esm(() => {
|
|
|
32874
33146
|
});
|
|
32875
33147
|
server.registerTool("list_agents", {
|
|
32876
33148
|
title: "List Agents",
|
|
32877
|
-
description: "List
|
|
33149
|
+
description: "List agents with presence status (name, status, last_seen, online).",
|
|
32878
33150
|
inputSchema: {
|
|
32879
|
-
online_only: exports_external.boolean().optional().describe("Only return agents
|
|
33151
|
+
online_only: exports_external.boolean().optional().describe("Only return agents online within last 60s")
|
|
32880
33152
|
}
|
|
32881
33153
|
}, async ({ online_only }) => {
|
|
32882
33154
|
const agents = listAgents({ online_only });
|
|
@@ -32886,7 +33158,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32886
33158
|
});
|
|
32887
33159
|
server.registerTool("get_blockers", {
|
|
32888
33160
|
title: "Get Blockers",
|
|
32889
|
-
description: "Check for unread blocking messages targeting you.
|
|
33161
|
+
description: "Check for unread blocking messages targeting you. Must acknowledge before continuing.",
|
|
32890
33162
|
inputSchema: {
|
|
32891
33163
|
from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var.")
|
|
32892
33164
|
}
|
|
@@ -32899,7 +33171,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32899
33171
|
});
|
|
32900
33172
|
server.registerTool("remove_agent", {
|
|
32901
33173
|
title: "Remove Agent",
|
|
32902
|
-
description: "Remove an agent from the presence list.
|
|
33174
|
+
description: "Remove an agent from the presence list.",
|
|
32903
33175
|
inputSchema: {
|
|
32904
33176
|
from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
|
|
32905
33177
|
agent: exports_external.string().optional().describe("Agent to remove (defaults to yourself)")
|
|
@@ -32910,7 +33182,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32910
33182
|
const removed = removePresence(agent);
|
|
32911
33183
|
if (!removed) {
|
|
32912
33184
|
return {
|
|
32913
|
-
content: [{ type: "text", text: `
|
|
33185
|
+
content: [{ type: "text", text: `agent "${agent}" not found` }],
|
|
32914
33186
|
isError: true
|
|
32915
33187
|
};
|
|
32916
33188
|
}
|
|
@@ -32920,7 +33192,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32920
33192
|
});
|
|
32921
33193
|
server.registerTool("rename_agent", {
|
|
32922
33194
|
title: "Rename Agent",
|
|
32923
|
-
description: "Rename an agent in the presence list.
|
|
33195
|
+
description: "Rename an agent in the presence list. Defaults to renaming yourself.",
|
|
32924
33196
|
inputSchema: {
|
|
32925
33197
|
from: exports_external.string().optional().describe("Your current agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
|
|
32926
33198
|
new_name: exports_external.string().describe("The new name for the agent")
|
|
@@ -32930,7 +33202,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32930
33202
|
const newName = new_name.trim();
|
|
32931
33203
|
if (!newName) {
|
|
32932
33204
|
return {
|
|
32933
|
-
content: [{ type: "text", text: "
|
|
33205
|
+
content: [{ type: "text", text: "new name cannot be empty" }],
|
|
32934
33206
|
isError: true
|
|
32935
33207
|
};
|
|
32936
33208
|
}
|
|
@@ -32938,7 +33210,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32938
33210
|
const renamed = renameAgent(oldName, newName);
|
|
32939
33211
|
if (!renamed) {
|
|
32940
33212
|
return {
|
|
32941
|
-
content: [{ type: "text", text: `
|
|
33213
|
+
content: [{ type: "text", text: `agent "${oldName}" not found` }],
|
|
32942
33214
|
isError: true
|
|
32943
33215
|
};
|
|
32944
33216
|
}
|
|
@@ -32966,7 +33238,7 @@ var exports_serve = {};
|
|
|
32966
33238
|
__export(exports_serve, {
|
|
32967
33239
|
startDashboardServer: () => startDashboardServer
|
|
32968
33240
|
});
|
|
32969
|
-
import { join as
|
|
33241
|
+
import { join as join5, resolve, sep } from "path";
|
|
32970
33242
|
import { existsSync } from "fs";
|
|
32971
33243
|
function securityHeaders(base) {
|
|
32972
33244
|
const headers = new Headers(base);
|
|
@@ -33037,7 +33309,7 @@ function isSameOrigin(req) {
|
|
|
33037
33309
|
function startDashboardServer(port = 0, host) {
|
|
33038
33310
|
const resolvedPort = normalizePort(port, 0);
|
|
33039
33311
|
const resolvedHost = normalizeHost(host ?? process.env.CONVERSATIONS_DASHBOARD_HOST);
|
|
33040
|
-
const dashboardDist =
|
|
33312
|
+
const dashboardDist = join5(import.meta.dir, "../../dashboard/dist");
|
|
33041
33313
|
const hasDist = existsSync(dashboardDist);
|
|
33042
33314
|
const server2 = Bun.serve({
|
|
33043
33315
|
port: resolvedPort,
|
|
@@ -33421,7 +33693,7 @@ function startDashboardServer(port = 0, host) {
|
|
|
33421
33693
|
headers.set("Content-Type", file2.type);
|
|
33422
33694
|
return new Response(file2, { headers });
|
|
33423
33695
|
}
|
|
33424
|
-
file2 = Bun.file(
|
|
33696
|
+
file2 = Bun.file(join5(dashboardDist, "index.html"));
|
|
33425
33697
|
if (await file2.exists()) {
|
|
33426
33698
|
const headers = securityHeaders();
|
|
33427
33699
|
if (file2.type)
|
|
@@ -33477,7 +33749,8 @@ init_projects();
|
|
|
33477
33749
|
init_db();
|
|
33478
33750
|
init_identity();
|
|
33479
33751
|
init_presence();
|
|
33480
|
-
|
|
33752
|
+
init_terminal_markdown();
|
|
33753
|
+
import chalk3 from "chalk";
|
|
33481
33754
|
import { render } from "ink";
|
|
33482
33755
|
import React8 from "react";
|
|
33483
33756
|
|
|
@@ -33488,7 +33761,7 @@ import { Box as Box6, Text as Text7, useApp, useInput as useInput5 } from "ink";
|
|
|
33488
33761
|
// node_modules/ink-text-input/build/index.js
|
|
33489
33762
|
import React, { useState, useEffect } from "react";
|
|
33490
33763
|
import { Text, useInput } from "ink";
|
|
33491
|
-
import
|
|
33764
|
+
import chalk2 from "chalk";
|
|
33492
33765
|
function TextInput({ value: originalValue, placeholder = "", focus = true, mask, highlightPastedText = false, showCursor = true, onChange, onSubmit }) {
|
|
33493
33766
|
const [state, setState] = useState({
|
|
33494
33767
|
cursorOffset: (originalValue || "").length,
|
|
@@ -33513,17 +33786,17 @@ function TextInput({ value: originalValue, placeholder = "", focus = true, mask,
|
|
|
33513
33786
|
const cursorActualWidth = highlightPastedText ? cursorWidth : 0;
|
|
33514
33787
|
const value = mask ? mask.repeat(originalValue.length) : originalValue;
|
|
33515
33788
|
let renderedValue = value;
|
|
33516
|
-
let renderedPlaceholder = placeholder ?
|
|
33789
|
+
let renderedPlaceholder = placeholder ? chalk2.grey(placeholder) : undefined;
|
|
33517
33790
|
if (showCursor && focus) {
|
|
33518
|
-
renderedPlaceholder = placeholder.length > 0 ?
|
|
33519
|
-
renderedValue = value.length > 0 ? "" :
|
|
33791
|
+
renderedPlaceholder = placeholder.length > 0 ? chalk2.inverse(placeholder[0]) + chalk2.grey(placeholder.slice(1)) : chalk2.inverse(" ");
|
|
33792
|
+
renderedValue = value.length > 0 ? "" : chalk2.inverse(" ");
|
|
33520
33793
|
let i = 0;
|
|
33521
33794
|
for (const char of value) {
|
|
33522
|
-
renderedValue += i >= cursorOffset - cursorActualWidth && i <= cursorOffset ?
|
|
33795
|
+
renderedValue += i >= cursorOffset - cursorActualWidth && i <= cursorOffset ? chalk2.inverse(char) : char;
|
|
33523
33796
|
i++;
|
|
33524
33797
|
}
|
|
33525
33798
|
if (value.length > 0 && cursorOffset === value.length) {
|
|
33526
|
-
renderedValue +=
|
|
33799
|
+
renderedValue += chalk2.inverse(" ");
|
|
33527
33800
|
}
|
|
33528
33801
|
}
|
|
33529
33802
|
useInput((input, key) => {
|
|
@@ -34424,15 +34697,15 @@ program2.command("send").description("Send a message to an agent").argument("<me
|
|
|
34424
34697
|
const content = typeof message === "string" ? message : "";
|
|
34425
34698
|
const session = typeof opts.session === "string" && opts.session.trim() ? opts.session.trim() : undefined;
|
|
34426
34699
|
if (!from) {
|
|
34427
|
-
console.error(
|
|
34700
|
+
console.error(chalk3.red("Sender identity is required."));
|
|
34428
34701
|
process.exit(1);
|
|
34429
34702
|
}
|
|
34430
34703
|
if (!to) {
|
|
34431
|
-
console.error(
|
|
34704
|
+
console.error(chalk3.red("Recipient is required."));
|
|
34432
34705
|
process.exit(1);
|
|
34433
34706
|
}
|
|
34434
34707
|
if (!content.trim()) {
|
|
34435
|
-
console.error(
|
|
34708
|
+
console.error(chalk3.red("Message content cannot be empty."));
|
|
34436
34709
|
process.exit(1);
|
|
34437
34710
|
}
|
|
34438
34711
|
let metadata;
|
|
@@ -34440,7 +34713,7 @@ program2.command("send").description("Send a message to an agent").argument("<me
|
|
|
34440
34713
|
try {
|
|
34441
34714
|
metadata = JSON.parse(opts.metadata);
|
|
34442
34715
|
} catch {
|
|
34443
|
-
console.error(
|
|
34716
|
+
console.error(chalk3.red("Invalid --metadata JSON."));
|
|
34444
34717
|
process.exit(1);
|
|
34445
34718
|
}
|
|
34446
34719
|
}
|
|
@@ -34459,7 +34732,7 @@ program2.command("send").description("Send a message to an agent").argument("<me
|
|
|
34459
34732
|
if (opts.json) {
|
|
34460
34733
|
console.log(JSON.stringify(msg, null, 2));
|
|
34461
34734
|
} else {
|
|
34462
|
-
console.log(
|
|
34735
|
+
console.log(chalk3.green(`Message sent`) + chalk3.dim(` (id: ${msg.id}, session: ${msg.session_id})`));
|
|
34463
34736
|
}
|
|
34464
34737
|
closeDb();
|
|
34465
34738
|
});
|
|
@@ -34489,15 +34762,20 @@ program2.command("read").description("Read messages").option("--session <id>", "
|
|
|
34489
34762
|
console.log(JSON.stringify(messages, null, 2));
|
|
34490
34763
|
} else {
|
|
34491
34764
|
if (messages.length === 0) {
|
|
34492
|
-
console.log(
|
|
34765
|
+
console.log(chalk3.dim("No messages found."));
|
|
34493
34766
|
} else {
|
|
34494
34767
|
for (const msg of messages) {
|
|
34495
|
-
const time3 =
|
|
34496
|
-
const from =
|
|
34497
|
-
const to = msg.space ?
|
|
34498
|
-
const priority = msg.priority !== "normal" ?
|
|
34499
|
-
const unread = !msg.read_at ?
|
|
34500
|
-
console.log(`${time3} ${from} \u2192 ${to}${priority}${unread}
|
|
34768
|
+
const time3 = chalk3.dim(msg.created_at.slice(11, 19));
|
|
34769
|
+
const from = chalk3.cyan(msg.from_agent);
|
|
34770
|
+
const to = msg.space ? chalk3.magenta(`#${msg.space}`) : chalk3.yellow(msg.to_agent);
|
|
34771
|
+
const priority = msg.priority !== "normal" ? chalk3.red(` [${msg.priority}]`) : "";
|
|
34772
|
+
const unread = !msg.read_at ? chalk3.green(" *") : "";
|
|
34773
|
+
console.log(`${time3} ${from} \u2192 ${to}${priority}${unread}`);
|
|
34774
|
+
const rendered = renderContent(msg.content);
|
|
34775
|
+
const indented = rendered.split(`
|
|
34776
|
+
`).map((l) => " " + l).join(`
|
|
34777
|
+
`);
|
|
34778
|
+
console.log(indented);
|
|
34501
34779
|
}
|
|
34502
34780
|
}
|
|
34503
34781
|
}
|
|
@@ -34506,7 +34784,7 @@ program2.command("read").description("Read messages").option("--session <id>", "
|
|
|
34506
34784
|
program2.command("search").description("Search messages by content").argument("<query>", "Search query string").option("--space <name>", "Filter by space").option("--from <agent>", "Filter by sender").option("--to <agent>", "Filter by recipient").option("--limit <n>", "Max results to return", parseInt).option("--json", "Output as JSON").action((query, opts) => {
|
|
34507
34785
|
const q = typeof query === "string" ? query.trim() : "";
|
|
34508
34786
|
if (!q) {
|
|
34509
|
-
console.error(
|
|
34787
|
+
console.error(chalk3.red("Search query cannot be empty."));
|
|
34510
34788
|
process.exit(1);
|
|
34511
34789
|
}
|
|
34512
34790
|
const messages = searchMessages({
|
|
@@ -34520,16 +34798,16 @@ program2.command("search").description("Search messages by content").argument("<
|
|
|
34520
34798
|
console.log(JSON.stringify(messages, null, 2));
|
|
34521
34799
|
} else {
|
|
34522
34800
|
if (messages.length === 0) {
|
|
34523
|
-
console.log(
|
|
34801
|
+
console.log(chalk3.dim("No messages found."));
|
|
34524
34802
|
} else {
|
|
34525
|
-
console.log(
|
|
34803
|
+
console.log(chalk3.dim(`Found ${messages.length} result(s) for "${q}":
|
|
34526
34804
|
`));
|
|
34527
34805
|
for (const msg of messages) {
|
|
34528
|
-
const time3 =
|
|
34529
|
-
const from =
|
|
34530
|
-
const to = msg.space ?
|
|
34531
|
-
const priority = msg.priority !== "normal" ?
|
|
34532
|
-
const unread = !msg.read_at ?
|
|
34806
|
+
const time3 = chalk3.dim(msg.created_at.slice(11, 19));
|
|
34807
|
+
const from = chalk3.cyan(msg.from_agent);
|
|
34808
|
+
const to = msg.space ? chalk3.magenta(`#${msg.space}`) : chalk3.yellow(msg.to_agent);
|
|
34809
|
+
const priority = msg.priority !== "normal" ? chalk3.red(` [${msg.priority}]`) : "";
|
|
34810
|
+
const unread = !msg.read_at ? chalk3.green(" *") : "";
|
|
34533
34811
|
console.log(`${time3} ${from} \u2192 ${to}${priority}${unread}: ${msg.content}`);
|
|
34534
34812
|
}
|
|
34535
34813
|
}
|
|
@@ -34542,12 +34820,12 @@ program2.command("sessions").description("List conversation sessions").option("-
|
|
|
34542
34820
|
console.log(JSON.stringify(sessions, null, 2));
|
|
34543
34821
|
} else {
|
|
34544
34822
|
if (sessions.length === 0) {
|
|
34545
|
-
console.log(
|
|
34823
|
+
console.log(chalk3.dim("No sessions found."));
|
|
34546
34824
|
} else {
|
|
34547
34825
|
for (const s of sessions) {
|
|
34548
|
-
const unread = s.unread_count > 0 ?
|
|
34826
|
+
const unread = s.unread_count > 0 ? chalk3.green(` (${s.unread_count} unread)`) : "";
|
|
34549
34827
|
const participants = s.participants.join(", ");
|
|
34550
|
-
console.log(`${
|
|
34828
|
+
console.log(`${chalk3.bold(s.session_id)} \u2014 ${participants} \u2014 ${s.message_count} messages${unread}`);
|
|
34551
34829
|
}
|
|
34552
34830
|
}
|
|
34553
34831
|
}
|
|
@@ -34556,17 +34834,17 @@ program2.command("sessions").description("List conversation sessions").option("-
|
|
|
34556
34834
|
program2.command("reply").description("Reply to a message (uses same session)").argument("<message>", "Reply content").requiredOption("--to <message-id>", "Message ID to reply to", parseInt).option("--from <agent>", "Sender agent ID").option("--priority <level>", "Priority: low, normal, high, urgent", "normal").option("--json", "Output as JSON").action((message, opts) => {
|
|
34557
34835
|
const original = getMessageById(opts.to);
|
|
34558
34836
|
if (!original) {
|
|
34559
|
-
console.error(
|
|
34837
|
+
console.error(chalk3.red(`Message #${opts.to} not found.`));
|
|
34560
34838
|
process.exit(1);
|
|
34561
34839
|
}
|
|
34562
34840
|
const from = resolveIdentity(opts.from).trim();
|
|
34563
34841
|
const content = typeof message === "string" ? message : "";
|
|
34564
34842
|
if (!from) {
|
|
34565
|
-
console.error(
|
|
34843
|
+
console.error(chalk3.red("Sender identity is required."));
|
|
34566
34844
|
process.exit(1);
|
|
34567
34845
|
}
|
|
34568
34846
|
if (!content.trim()) {
|
|
34569
|
-
console.error(
|
|
34847
|
+
console.error(chalk3.red("Reply content cannot be empty."));
|
|
34570
34848
|
process.exit(1);
|
|
34571
34849
|
}
|
|
34572
34850
|
const space = original.space || (original.session_id?.startsWith("space:") ? original.session_id.slice(6) : undefined);
|
|
@@ -34582,7 +34860,7 @@ program2.command("reply").description("Reply to a message (uses same session)").
|
|
|
34582
34860
|
if (opts.json) {
|
|
34583
34861
|
console.log(JSON.stringify(msg, null, 2));
|
|
34584
34862
|
} else {
|
|
34585
|
-
console.log(
|
|
34863
|
+
console.log(chalk3.green(`Reply sent`) + chalk3.dim(` (id: ${msg.id}, session: ${msg.session_id})`));
|
|
34586
34864
|
}
|
|
34587
34865
|
closeDb();
|
|
34588
34866
|
});
|
|
@@ -34598,13 +34876,13 @@ program2.command("mark-read").description("Mark messages as read").argument("[id
|
|
|
34598
34876
|
} else if (ids.length > 0) {
|
|
34599
34877
|
count = markRead(ids.map(Number), agent);
|
|
34600
34878
|
} else {
|
|
34601
|
-
console.error(
|
|
34879
|
+
console.error(chalk3.red("Provide message IDs, --all, --session, or --space flag."));
|
|
34602
34880
|
process.exit(1);
|
|
34603
34881
|
}
|
|
34604
34882
|
if (opts.json) {
|
|
34605
34883
|
console.log(JSON.stringify({ marked_read: count }));
|
|
34606
34884
|
} else {
|
|
34607
|
-
console.log(
|
|
34885
|
+
console.log(chalk3.green(`Marked ${count} message(s) as read.`));
|
|
34608
34886
|
}
|
|
34609
34887
|
closeDb();
|
|
34610
34888
|
});
|
|
@@ -34640,7 +34918,7 @@ program2.command("status").description("Show database stats").option("--json", "
|
|
|
34640
34918
|
if (opts.json) {
|
|
34641
34919
|
console.log(JSON.stringify(stats, null, 2));
|
|
34642
34920
|
} else {
|
|
34643
|
-
console.log(
|
|
34921
|
+
console.log(chalk3.bold("Conversations Status"));
|
|
34644
34922
|
console.log(` DB Path: ${stats.db_path}`);
|
|
34645
34923
|
console.log(` Messages: ${stats.total_messages}`);
|
|
34646
34924
|
console.log(` Sessions: ${stats.total_sessions}`);
|
|
@@ -34662,7 +34940,7 @@ program2.command("update").description("Check for and install updates").option("
|
|
|
34662
34940
|
if (opts.json) {
|
|
34663
34941
|
console.log(JSON.stringify({ error: "Failed to check npm registry" }));
|
|
34664
34942
|
} else {
|
|
34665
|
-
console.error(
|
|
34943
|
+
console.error(chalk3.red("Failed to check npm registry for updates."));
|
|
34666
34944
|
}
|
|
34667
34945
|
process.exit(1);
|
|
34668
34946
|
}
|
|
@@ -34671,18 +34949,18 @@ program2.command("update").description("Check for and install updates").option("
|
|
|
34671
34949
|
if (opts.json) {
|
|
34672
34950
|
console.log(JSON.stringify({ current, latest, updateAvailable }));
|
|
34673
34951
|
} else if (updateAvailable) {
|
|
34674
|
-
console.log(`Current version: ${
|
|
34675
|
-
console.log(`Latest version: ${
|
|
34676
|
-
console.log(
|
|
34952
|
+
console.log(`Current version: ${chalk3.yellow(current)}`);
|
|
34953
|
+
console.log(`Latest version: ${chalk3.green(latest)}`);
|
|
34954
|
+
console.log(chalk3.cyan(`Run ${chalk3.bold("conversations update")} to install.`));
|
|
34677
34955
|
} else {
|
|
34678
|
-
console.log(
|
|
34956
|
+
console.log(chalk3.green(`Already on latest version (${current})`));
|
|
34679
34957
|
}
|
|
34680
34958
|
return;
|
|
34681
34959
|
}
|
|
34682
34960
|
if (opts.json) {
|
|
34683
34961
|
console.log(JSON.stringify({ current, latest, updateAvailable, status: "updating" }));
|
|
34684
34962
|
} else {
|
|
34685
|
-
console.log(`Updating from ${
|
|
34963
|
+
console.log(`Updating from ${chalk3.yellow(current)} to ${chalk3.green(latest)}...`);
|
|
34686
34964
|
}
|
|
34687
34965
|
const proc = Bun.spawn(["bun", "install", "-g", `@hasna/conversations@${latest}`], {
|
|
34688
34966
|
stdout: "inherit",
|
|
@@ -34691,14 +34969,14 @@ program2.command("update").description("Check for and install updates").option("
|
|
|
34691
34969
|
const exitCode = await proc.exited;
|
|
34692
34970
|
if (exitCode === 0) {
|
|
34693
34971
|
if (!opts.json) {
|
|
34694
|
-
console.log(
|
|
34972
|
+
console.log(chalk3.green(`
|
|
34695
34973
|
Successfully updated to v${latest}`));
|
|
34696
34974
|
}
|
|
34697
34975
|
} else {
|
|
34698
34976
|
if (opts.json) {
|
|
34699
34977
|
console.log(JSON.stringify({ error: "Update failed", exitCode }));
|
|
34700
34978
|
} else {
|
|
34701
|
-
console.error(
|
|
34979
|
+
console.error(chalk3.red(`
|
|
34702
34980
|
Update failed (exit code ${exitCode})`));
|
|
34703
34981
|
}
|
|
34704
34982
|
process.exit(1);
|
|
@@ -34709,11 +34987,11 @@ space.command("create").description("Create a new space").argument("<name>", "Sp
|
|
|
34709
34987
|
const agent = resolveIdentity(opts.from).trim();
|
|
34710
34988
|
const spaceName = typeof name === "string" ? name.trim() : "";
|
|
34711
34989
|
if (!agent) {
|
|
34712
|
-
console.error(
|
|
34990
|
+
console.error(chalk3.red("Creator identity is required."));
|
|
34713
34991
|
process.exit(1);
|
|
34714
34992
|
}
|
|
34715
34993
|
if (!spaceName) {
|
|
34716
|
-
console.error(
|
|
34994
|
+
console.error(chalk3.red("Space name cannot be empty."));
|
|
34717
34995
|
process.exit(1);
|
|
34718
34996
|
}
|
|
34719
34997
|
try {
|
|
@@ -34726,14 +35004,14 @@ space.command("create").description("Create a new space").argument("<name>", "Sp
|
|
|
34726
35004
|
if (opts.json) {
|
|
34727
35005
|
console.log(JSON.stringify(sp, null, 2));
|
|
34728
35006
|
} else {
|
|
34729
|
-
console.log(
|
|
35007
|
+
console.log(chalk3.green(`Space #${sp.name} created`) + (sp.description ? chalk3.dim(` \u2014 ${sp.description}`) : ""));
|
|
34730
35008
|
}
|
|
34731
35009
|
} catch (e) {
|
|
34732
35010
|
if (e.message?.includes("UNIQUE constraint")) {
|
|
34733
|
-
console.error(
|
|
35011
|
+
console.error(chalk3.red(`Space #${spaceName} already exists.`));
|
|
34734
35012
|
process.exit(1);
|
|
34735
35013
|
}
|
|
34736
|
-
console.error(
|
|
35014
|
+
console.error(chalk3.red(e.message));
|
|
34737
35015
|
process.exit(1);
|
|
34738
35016
|
}
|
|
34739
35017
|
closeDb();
|
|
@@ -34754,13 +35032,13 @@ space.command("list").description("List all spaces").option("--project <id>", "F
|
|
|
34754
35032
|
console.log(JSON.stringify(spaces, null, 2));
|
|
34755
35033
|
} else {
|
|
34756
35034
|
if (spaces.length === 0) {
|
|
34757
|
-
console.log(
|
|
35035
|
+
console.log(chalk3.dim("No spaces found."));
|
|
34758
35036
|
} else {
|
|
34759
35037
|
for (const sp of spaces) {
|
|
34760
|
-
const desc = sp.description ?
|
|
34761
|
-
const parent = sp.parent_id ?
|
|
34762
|
-
const archived = sp.archived_at ?
|
|
34763
|
-
console.log(`${
|
|
35038
|
+
const desc = sp.description ? chalk3.dim(` \u2014 ${sp.description}`) : "";
|
|
35039
|
+
const parent = sp.parent_id ? chalk3.dim(` (child of ${sp.parent_id})`) : "";
|
|
35040
|
+
const archived = sp.archived_at ? chalk3.yellow(" [archived]") : "";
|
|
35041
|
+
console.log(`${chalk3.magenta(`#${sp.name}`)}${desc}${parent}${archived} ${sp.member_count} members, ${sp.message_count} messages`);
|
|
34764
35042
|
}
|
|
34765
35043
|
}
|
|
34766
35044
|
}
|
|
@@ -34769,7 +35047,7 @@ space.command("list").description("List all spaces").option("--project <id>", "F
|
|
|
34769
35047
|
space.command("update").description("Update a space").argument("<name>", "Space name").option("--description <text>", "New description").option("--parent <name>", "New parent space name").option("--project <id>", "New project ID").option("--json", "Output as JSON").action((name, opts) => {
|
|
34770
35048
|
const spaceName = typeof name === "string" ? name.trim() : "";
|
|
34771
35049
|
if (!spaceName) {
|
|
34772
|
-
console.error(
|
|
35050
|
+
console.error(chalk3.red("Space name cannot be empty."));
|
|
34773
35051
|
process.exit(1);
|
|
34774
35052
|
}
|
|
34775
35053
|
const updates = {};
|
|
@@ -34784,10 +35062,10 @@ space.command("update").description("Update a space").argument("<name>", "Space
|
|
|
34784
35062
|
if (opts.json) {
|
|
34785
35063
|
console.log(JSON.stringify(sp, null, 2));
|
|
34786
35064
|
} else {
|
|
34787
|
-
console.log(
|
|
35065
|
+
console.log(chalk3.green(`Space #${sp.name} updated.`));
|
|
34788
35066
|
}
|
|
34789
35067
|
} catch (e) {
|
|
34790
|
-
console.error(
|
|
35068
|
+
console.error(chalk3.red(e.message));
|
|
34791
35069
|
process.exit(1);
|
|
34792
35070
|
}
|
|
34793
35071
|
closeDb();
|
|
@@ -34795,7 +35073,7 @@ space.command("update").description("Update a space").argument("<name>", "Space
|
|
|
34795
35073
|
space.command("archive").description("Archive a space").argument("<name>", "Space name").option("--json", "Output as JSON").action((name, opts) => {
|
|
34796
35074
|
const spaceName = typeof name === "string" ? name.trim() : "";
|
|
34797
35075
|
if (!spaceName) {
|
|
34798
|
-
console.error(
|
|
35076
|
+
console.error(chalk3.red("Space name cannot be empty."));
|
|
34799
35077
|
process.exit(1);
|
|
34800
35078
|
}
|
|
34801
35079
|
try {
|
|
@@ -34803,10 +35081,10 @@ space.command("archive").description("Archive a space").argument("<name>", "Spac
|
|
|
34803
35081
|
if (opts.json) {
|
|
34804
35082
|
console.log(JSON.stringify(sp, null, 2));
|
|
34805
35083
|
} else {
|
|
34806
|
-
console.log(
|
|
35084
|
+
console.log(chalk3.green(`Space #${sp.name} archived.`));
|
|
34807
35085
|
}
|
|
34808
35086
|
} catch (e) {
|
|
34809
|
-
console.error(
|
|
35087
|
+
console.error(chalk3.red(e.message));
|
|
34810
35088
|
process.exit(1);
|
|
34811
35089
|
}
|
|
34812
35090
|
closeDb();
|
|
@@ -34814,7 +35092,7 @@ space.command("archive").description("Archive a space").argument("<name>", "Spac
|
|
|
34814
35092
|
space.command("unarchive").description("Unarchive a space").argument("<name>", "Space name").option("--json", "Output as JSON").action((name, opts) => {
|
|
34815
35093
|
const spaceName = typeof name === "string" ? name.trim() : "";
|
|
34816
35094
|
if (!spaceName) {
|
|
34817
|
-
console.error(
|
|
35095
|
+
console.error(chalk3.red("Space name cannot be empty."));
|
|
34818
35096
|
process.exit(1);
|
|
34819
35097
|
}
|
|
34820
35098
|
try {
|
|
@@ -34822,10 +35100,10 @@ space.command("unarchive").description("Unarchive a space").argument("<name>", "
|
|
|
34822
35100
|
if (opts.json) {
|
|
34823
35101
|
console.log(JSON.stringify(sp, null, 2));
|
|
34824
35102
|
} else {
|
|
34825
|
-
console.log(
|
|
35103
|
+
console.log(chalk3.green(`Space #${sp.name} unarchived.`));
|
|
34826
35104
|
}
|
|
34827
35105
|
} catch (e) {
|
|
34828
|
-
console.error(
|
|
35106
|
+
console.error(chalk3.red(e.message));
|
|
34829
35107
|
process.exit(1);
|
|
34830
35108
|
}
|
|
34831
35109
|
closeDb();
|
|
@@ -34835,20 +35113,20 @@ space.command("send").description("Send a message to a space").argument("<space>
|
|
|
34835
35113
|
const spaceArg = typeof spaceName === "string" ? spaceName.trim() : "";
|
|
34836
35114
|
const content = typeof message === "string" ? message : "";
|
|
34837
35115
|
if (!from) {
|
|
34838
|
-
console.error(
|
|
35116
|
+
console.error(chalk3.red("Sender identity is required."));
|
|
34839
35117
|
process.exit(1);
|
|
34840
35118
|
}
|
|
34841
35119
|
if (!spaceArg) {
|
|
34842
|
-
console.error(
|
|
35120
|
+
console.error(chalk3.red("Space name cannot be empty."));
|
|
34843
35121
|
process.exit(1);
|
|
34844
35122
|
}
|
|
34845
35123
|
if (!content.trim()) {
|
|
34846
|
-
console.error(
|
|
35124
|
+
console.error(chalk3.red("Message content cannot be empty."));
|
|
34847
35125
|
process.exit(1);
|
|
34848
35126
|
}
|
|
34849
35127
|
const sp = getSpace(spaceArg);
|
|
34850
35128
|
if (!sp) {
|
|
34851
|
-
console.error(
|
|
35129
|
+
console.error(chalk3.red(`Space #${spaceArg} not found.`));
|
|
34852
35130
|
process.exit(1);
|
|
34853
35131
|
}
|
|
34854
35132
|
const msg = sendMessage({
|
|
@@ -34862,14 +35140,14 @@ space.command("send").description("Send a message to a space").argument("<space>
|
|
|
34862
35140
|
if (opts.json) {
|
|
34863
35141
|
console.log(JSON.stringify(msg, null, 2));
|
|
34864
35142
|
} else {
|
|
34865
|
-
console.log(
|
|
35143
|
+
console.log(chalk3.green(`Message sent to #${spaceArg}`) + chalk3.dim(` (id: ${msg.id})`));
|
|
34866
35144
|
}
|
|
34867
35145
|
closeDb();
|
|
34868
35146
|
});
|
|
34869
35147
|
space.command("read").description("Read messages from a space").argument("<space>", "Space name").option("--since <timestamp>", "Messages after this ISO timestamp").option("--limit <n>", "Max messages to return", parseInt).option("--json", "Output as JSON").action((spaceName, opts) => {
|
|
34870
35148
|
const spaceArg = typeof spaceName === "string" ? spaceName.trim() : "";
|
|
34871
35149
|
if (!spaceArg) {
|
|
34872
|
-
console.error(
|
|
35150
|
+
console.error(chalk3.red("Space name cannot be empty."));
|
|
34873
35151
|
process.exit(1);
|
|
34874
35152
|
}
|
|
34875
35153
|
const messages = readMessages({
|
|
@@ -34881,13 +35159,18 @@ space.command("read").description("Read messages from a space").argument("<space
|
|
|
34881
35159
|
console.log(JSON.stringify(messages, null, 2));
|
|
34882
35160
|
} else {
|
|
34883
35161
|
if (messages.length === 0) {
|
|
34884
|
-
console.log(
|
|
35162
|
+
console.log(chalk3.dim(`No messages in #${spaceArg}.`));
|
|
34885
35163
|
} else {
|
|
34886
35164
|
for (const msg of messages) {
|
|
34887
|
-
const time3 =
|
|
34888
|
-
const from =
|
|
34889
|
-
const priority = msg.priority !== "normal" ?
|
|
34890
|
-
console.log(`${time3} ${from} \u2192 ${
|
|
35165
|
+
const time3 = chalk3.dim(msg.created_at.slice(11, 19));
|
|
35166
|
+
const from = chalk3.cyan(msg.from_agent);
|
|
35167
|
+
const priority = msg.priority !== "normal" ? chalk3.red(` [${msg.priority}]`) : "";
|
|
35168
|
+
console.log(`${time3} ${from} \u2192 ${chalk3.magenta(`#${spaceArg}`)}${priority}`);
|
|
35169
|
+
const rendered = renderContent(msg.content);
|
|
35170
|
+
const indented = rendered.split(`
|
|
35171
|
+
`).map((l) => " " + l).join(`
|
|
35172
|
+
`);
|
|
35173
|
+
console.log(indented);
|
|
34891
35174
|
}
|
|
34892
35175
|
}
|
|
34893
35176
|
}
|
|
@@ -34897,22 +35180,22 @@ space.command("join").description("Join a space").argument("<space>", "Space nam
|
|
|
34897
35180
|
const agent = resolveIdentity(opts.from).trim();
|
|
34898
35181
|
const spaceArg = typeof spaceName === "string" ? spaceName.trim() : "";
|
|
34899
35182
|
if (!agent) {
|
|
34900
|
-
console.error(
|
|
35183
|
+
console.error(chalk3.red("Agent identity is required."));
|
|
34901
35184
|
process.exit(1);
|
|
34902
35185
|
}
|
|
34903
35186
|
if (!spaceArg) {
|
|
34904
|
-
console.error(
|
|
35187
|
+
console.error(chalk3.red("Space name cannot be empty."));
|
|
34905
35188
|
process.exit(1);
|
|
34906
35189
|
}
|
|
34907
35190
|
const ok = joinSpace(spaceArg, agent);
|
|
34908
35191
|
if (!ok) {
|
|
34909
|
-
console.error(
|
|
35192
|
+
console.error(chalk3.red(`Space #${spaceArg} not found.`));
|
|
34910
35193
|
process.exit(1);
|
|
34911
35194
|
}
|
|
34912
35195
|
if (opts.json) {
|
|
34913
35196
|
console.log(JSON.stringify({ space: spaceArg, agent, joined: true }));
|
|
34914
35197
|
} else {
|
|
34915
|
-
console.log(
|
|
35198
|
+
console.log(chalk3.green(`${agent} joined #${spaceArg}`));
|
|
34916
35199
|
}
|
|
34917
35200
|
closeDb();
|
|
34918
35201
|
});
|
|
@@ -34920,11 +35203,11 @@ space.command("leave").description("Leave a space").argument("<space>", "Space n
|
|
|
34920
35203
|
const agent = resolveIdentity(opts.from).trim();
|
|
34921
35204
|
const spaceArg = typeof spaceName === "string" ? spaceName.trim() : "";
|
|
34922
35205
|
if (!agent) {
|
|
34923
|
-
console.error(
|
|
35206
|
+
console.error(chalk3.red("Agent identity is required."));
|
|
34924
35207
|
process.exit(1);
|
|
34925
35208
|
}
|
|
34926
35209
|
if (!spaceArg) {
|
|
34927
|
-
console.error(
|
|
35210
|
+
console.error(chalk3.red("Space name cannot be empty."));
|
|
34928
35211
|
process.exit(1);
|
|
34929
35212
|
}
|
|
34930
35213
|
const ok = leaveSpace(spaceArg, agent);
|
|
@@ -34932,9 +35215,9 @@ space.command("leave").description("Leave a space").argument("<space>", "Space n
|
|
|
34932
35215
|
console.log(JSON.stringify({ space: spaceArg, agent, left: ok }));
|
|
34933
35216
|
} else {
|
|
34934
35217
|
if (ok) {
|
|
34935
|
-
console.log(
|
|
35218
|
+
console.log(chalk3.green(`${agent} left #${spaceArg}`));
|
|
34936
35219
|
} else {
|
|
34937
|
-
console.log(
|
|
35220
|
+
console.log(chalk3.dim(`${agent} was not a member of #${spaceArg}`));
|
|
34938
35221
|
}
|
|
34939
35222
|
}
|
|
34940
35223
|
closeDb();
|
|
@@ -34942,7 +35225,7 @@ space.command("leave").description("Leave a space").argument("<space>", "Space n
|
|
|
34942
35225
|
space.command("members").description("List space members").argument("<space>", "Space name").option("--json", "Output as JSON").action((spaceName, opts) => {
|
|
34943
35226
|
const spaceArg = typeof spaceName === "string" ? spaceName.trim() : "";
|
|
34944
35227
|
if (!spaceArg) {
|
|
34945
|
-
console.error(
|
|
35228
|
+
console.error(chalk3.red("Space name cannot be empty."));
|
|
34946
35229
|
process.exit(1);
|
|
34947
35230
|
}
|
|
34948
35231
|
const members = getSpaceMembers(spaceArg);
|
|
@@ -34950,11 +35233,11 @@ space.command("members").description("List space members").argument("<space>", "
|
|
|
34950
35233
|
console.log(JSON.stringify(members, null, 2));
|
|
34951
35234
|
} else {
|
|
34952
35235
|
if (members.length === 0) {
|
|
34953
|
-
console.log(
|
|
35236
|
+
console.log(chalk3.dim(`No members in #${spaceArg}.`));
|
|
34954
35237
|
} else {
|
|
34955
|
-
console.log(
|
|
35238
|
+
console.log(chalk3.magenta(`#${spaceArg}`) + chalk3.dim(` \u2014 ${members.length} member(s)`));
|
|
34956
35239
|
for (const m of members) {
|
|
34957
|
-
console.log(` ${
|
|
35240
|
+
console.log(` ${chalk3.cyan(m.agent)} ${chalk3.dim(`joined ${m.joined_at.slice(0, 10)}`)}`);
|
|
34958
35241
|
}
|
|
34959
35242
|
}
|
|
34960
35243
|
}
|
|
@@ -34965,11 +35248,11 @@ project.command("create").description("Create a new project").argument("<name>",
|
|
|
34965
35248
|
const agent = resolveIdentity(opts.from).trim();
|
|
34966
35249
|
const projectName = typeof name === "string" ? name.trim() : "";
|
|
34967
35250
|
if (!agent) {
|
|
34968
|
-
console.error(
|
|
35251
|
+
console.error(chalk3.red("Creator identity is required."));
|
|
34969
35252
|
process.exit(1);
|
|
34970
35253
|
}
|
|
34971
35254
|
if (!projectName) {
|
|
34972
|
-
console.error(
|
|
35255
|
+
console.error(chalk3.red("Project name cannot be empty."));
|
|
34973
35256
|
process.exit(1);
|
|
34974
35257
|
}
|
|
34975
35258
|
let tags;
|
|
@@ -34977,7 +35260,7 @@ project.command("create").description("Create a new project").argument("<name>",
|
|
|
34977
35260
|
try {
|
|
34978
35261
|
tags = JSON.parse(opts.tags);
|
|
34979
35262
|
} catch {
|
|
34980
|
-
console.error(
|
|
35263
|
+
console.error(chalk3.red("Invalid --tags JSON. Expected array of strings."));
|
|
34981
35264
|
process.exit(1);
|
|
34982
35265
|
}
|
|
34983
35266
|
}
|
|
@@ -34993,14 +35276,14 @@ project.command("create").description("Create a new project").argument("<name>",
|
|
|
34993
35276
|
if (opts.json) {
|
|
34994
35277
|
console.log(JSON.stringify(p, null, 2));
|
|
34995
35278
|
} else {
|
|
34996
|
-
console.log(
|
|
35279
|
+
console.log(chalk3.green(`Project "${p.name}" created`) + chalk3.dim(` (id: ${p.id})`));
|
|
34997
35280
|
}
|
|
34998
35281
|
} catch (e) {
|
|
34999
35282
|
if (e.message?.includes("UNIQUE constraint")) {
|
|
35000
|
-
console.error(
|
|
35283
|
+
console.error(chalk3.red(`Project "${projectName}" already exists.`));
|
|
35001
35284
|
process.exit(1);
|
|
35002
35285
|
}
|
|
35003
|
-
console.error(
|
|
35286
|
+
console.error(chalk3.red(e.message));
|
|
35004
35287
|
process.exit(1);
|
|
35005
35288
|
}
|
|
35006
35289
|
closeDb();
|
|
@@ -35012,12 +35295,12 @@ project.command("list").description("List all projects").option("--status <statu
|
|
|
35012
35295
|
console.log(JSON.stringify(projects, null, 2));
|
|
35013
35296
|
} else {
|
|
35014
35297
|
if (projects.length === 0) {
|
|
35015
|
-
console.log(
|
|
35298
|
+
console.log(chalk3.dim("No projects found."));
|
|
35016
35299
|
} else {
|
|
35017
35300
|
for (const p of projects) {
|
|
35018
|
-
const desc = p.description ?
|
|
35019
|
-
const statusBadge = p.status === "archived" ?
|
|
35020
|
-
console.log(`${
|
|
35301
|
+
const desc = p.description ? chalk3.dim(` \u2014 ${p.description}`) : "";
|
|
35302
|
+
const statusBadge = p.status === "archived" ? chalk3.yellow(" [archived]") : "";
|
|
35303
|
+
console.log(`${chalk3.bold(p.name)}${desc}${statusBadge} ${p.space_count} spaces`);
|
|
35021
35304
|
}
|
|
35022
35305
|
}
|
|
35023
35306
|
}
|
|
@@ -35028,13 +35311,13 @@ project.command("get").description("Get project details").argument("<id-or-name>
|
|
|
35028
35311
|
if (!p)
|
|
35029
35312
|
p = getProjectByName(idOrName);
|
|
35030
35313
|
if (!p) {
|
|
35031
|
-
console.error(
|
|
35314
|
+
console.error(chalk3.red(`Project "${idOrName}" not found.`));
|
|
35032
35315
|
process.exit(1);
|
|
35033
35316
|
}
|
|
35034
35317
|
if (opts.json) {
|
|
35035
35318
|
console.log(JSON.stringify(p, null, 2));
|
|
35036
35319
|
} else {
|
|
35037
|
-
console.log(
|
|
35320
|
+
console.log(chalk3.bold(p.name));
|
|
35038
35321
|
if (p.description)
|
|
35039
35322
|
console.log(` Description: ${p.description}`);
|
|
35040
35323
|
if (p.path)
|
|
@@ -35065,7 +35348,7 @@ project.command("update").description("Update a project").argument("<id>", "Proj
|
|
|
35065
35348
|
try {
|
|
35066
35349
|
updates.tags = JSON.parse(opts.tags);
|
|
35067
35350
|
} catch {
|
|
35068
|
-
console.error(
|
|
35351
|
+
console.error(chalk3.red("Invalid --tags JSON."));
|
|
35069
35352
|
process.exit(1);
|
|
35070
35353
|
}
|
|
35071
35354
|
}
|
|
@@ -35074,10 +35357,10 @@ project.command("update").description("Update a project").argument("<id>", "Proj
|
|
|
35074
35357
|
if (opts.json) {
|
|
35075
35358
|
console.log(JSON.stringify(p, null, 2));
|
|
35076
35359
|
} else {
|
|
35077
|
-
console.log(
|
|
35360
|
+
console.log(chalk3.green(`Project "${p.name}" updated.`));
|
|
35078
35361
|
}
|
|
35079
35362
|
} catch (e) {
|
|
35080
|
-
console.error(
|
|
35363
|
+
console.error(chalk3.red(e.message));
|
|
35081
35364
|
process.exit(1);
|
|
35082
35365
|
}
|
|
35083
35366
|
closeDb();
|
|
@@ -35086,16 +35369,16 @@ project.command("delete").description("Delete a project").argument("<id>", "Proj
|
|
|
35086
35369
|
try {
|
|
35087
35370
|
const deleted = deleteProject(id);
|
|
35088
35371
|
if (!deleted) {
|
|
35089
|
-
console.error(
|
|
35372
|
+
console.error(chalk3.red(`Project "${id}" not found.`));
|
|
35090
35373
|
process.exit(1);
|
|
35091
35374
|
}
|
|
35092
35375
|
if (opts.json) {
|
|
35093
35376
|
console.log(JSON.stringify({ id, deleted: true }));
|
|
35094
35377
|
} else {
|
|
35095
|
-
console.log(
|
|
35378
|
+
console.log(chalk3.green(`Project deleted.`));
|
|
35096
35379
|
}
|
|
35097
35380
|
} catch (e) {
|
|
35098
|
-
console.error(
|
|
35381
|
+
console.error(chalk3.red(e.message));
|
|
35099
35382
|
process.exit(1);
|
|
35100
35383
|
}
|
|
35101
35384
|
closeDb();
|
|
@@ -35103,7 +35386,7 @@ project.command("delete").description("Delete a project").argument("<id>", "Proj
|
|
|
35103
35386
|
program2.command("delete").description("Delete a message (only sender can delete)").argument("<id>", "Message ID", parseInt).option("--from <agent>", "Sender agent ID").option("--json", "Output as JSON").action((id, opts) => {
|
|
35104
35387
|
const agent = resolveIdentity(opts.from).trim();
|
|
35105
35388
|
if (!agent) {
|
|
35106
|
-
console.error(
|
|
35389
|
+
console.error(chalk3.red("Agent identity is required."));
|
|
35107
35390
|
process.exit(1);
|
|
35108
35391
|
}
|
|
35109
35392
|
const result = deleteMessage(id, agent);
|
|
@@ -35111,9 +35394,9 @@ program2.command("delete").description("Delete a message (only sender can delete
|
|
|
35111
35394
|
console.log(JSON.stringify({ id, deleted: result }));
|
|
35112
35395
|
} else {
|
|
35113
35396
|
if (result) {
|
|
35114
|
-
console.log(
|
|
35397
|
+
console.log(chalk3.green(`Message #${id} deleted.`));
|
|
35115
35398
|
} else {
|
|
35116
|
-
console.error(
|
|
35399
|
+
console.error(chalk3.red(`Message #${id} not found or not your message.`));
|
|
35117
35400
|
process.exit(1);
|
|
35118
35401
|
}
|
|
35119
35402
|
}
|
|
@@ -35123,11 +35406,11 @@ program2.command("edit").description("Edit a message (only sender can edit)").ar
|
|
|
35123
35406
|
const agent = resolveIdentity(opts.from).trim();
|
|
35124
35407
|
const content = typeof newContent === "string" ? newContent : "";
|
|
35125
35408
|
if (!agent) {
|
|
35126
|
-
console.error(
|
|
35409
|
+
console.error(chalk3.red("Agent identity is required."));
|
|
35127
35410
|
process.exit(1);
|
|
35128
35411
|
}
|
|
35129
35412
|
if (!content.trim()) {
|
|
35130
|
-
console.error(
|
|
35413
|
+
console.error(chalk3.red("New content cannot be empty."));
|
|
35131
35414
|
process.exit(1);
|
|
35132
35415
|
}
|
|
35133
35416
|
const msg = editMessage(id, agent, content);
|
|
@@ -35135,9 +35418,9 @@ program2.command("edit").description("Edit a message (only sender can edit)").ar
|
|
|
35135
35418
|
console.log(JSON.stringify(msg, null, 2));
|
|
35136
35419
|
} else {
|
|
35137
35420
|
if (msg) {
|
|
35138
|
-
console.log(
|
|
35421
|
+
console.log(chalk3.green(`Message #${id} edited.`));
|
|
35139
35422
|
} else {
|
|
35140
|
-
console.error(
|
|
35423
|
+
console.error(chalk3.red(`Message #${id} not found or not your message.`));
|
|
35141
35424
|
process.exit(1);
|
|
35142
35425
|
}
|
|
35143
35426
|
}
|
|
@@ -35149,9 +35432,9 @@ program2.command("pin").description("Pin a message").argument("<id>", "Message I
|
|
|
35149
35432
|
console.log(JSON.stringify(msg, null, 2));
|
|
35150
35433
|
} else {
|
|
35151
35434
|
if (msg) {
|
|
35152
|
-
console.log(
|
|
35435
|
+
console.log(chalk3.green(`Message #${id} pinned.`));
|
|
35153
35436
|
} else {
|
|
35154
|
-
console.error(
|
|
35437
|
+
console.error(chalk3.red(`Message #${id} not found.`));
|
|
35155
35438
|
process.exit(1);
|
|
35156
35439
|
}
|
|
35157
35440
|
}
|
|
@@ -35163,9 +35446,9 @@ program2.command("unpin").description("Unpin a message").argument("<id>", "Messa
|
|
|
35163
35446
|
console.log(JSON.stringify(msg, null, 2));
|
|
35164
35447
|
} else {
|
|
35165
35448
|
if (msg) {
|
|
35166
|
-
console.log(
|
|
35449
|
+
console.log(chalk3.green(`Message #${id} unpinned.`));
|
|
35167
35450
|
} else {
|
|
35168
|
-
console.error(
|
|
35451
|
+
console.error(chalk3.red(`Message #${id} not found.`));
|
|
35169
35452
|
process.exit(1);
|
|
35170
35453
|
}
|
|
35171
35454
|
}
|
|
@@ -35180,13 +35463,13 @@ agents.command("list").description("List all agents with their presence status")
|
|
|
35180
35463
|
console.log(JSON.stringify(agentsList, null, 2));
|
|
35181
35464
|
} else {
|
|
35182
35465
|
if (agentsList.length === 0) {
|
|
35183
|
-
console.log(
|
|
35466
|
+
console.log(chalk3.dim("No agents found."));
|
|
35184
35467
|
} else {
|
|
35185
35468
|
for (const a of agentsList) {
|
|
35186
|
-
const status = a.online ?
|
|
35187
|
-
const lastSeen =
|
|
35188
|
-
const agentName = a.agent === agent ?
|
|
35189
|
-
console.log(` ${agentName} ${status} ${
|
|
35469
|
+
const status = a.online ? chalk3.green("online") : chalk3.dim("offline");
|
|
35470
|
+
const lastSeen = chalk3.dim(a.last_seen_at.slice(0, 19));
|
|
35471
|
+
const agentName = a.agent === agent ? chalk3.cyan(`${a.agent} (you)`) : chalk3.cyan(a.agent);
|
|
35472
|
+
console.log(` ${agentName} ${status} ${chalk3.dim(a.status)} ${lastSeen}`);
|
|
35190
35473
|
}
|
|
35191
35474
|
}
|
|
35192
35475
|
}
|
|
@@ -35195,7 +35478,7 @@ agents.command("list").description("List all agents with their presence status")
|
|
|
35195
35478
|
agents.command("remove").description("Remove an agent from the presence list").argument("<name>", "Agent name to remove").option("--json", "Output as JSON").action((name, opts) => {
|
|
35196
35479
|
const agentName = typeof name === "string" ? name.trim() : "";
|
|
35197
35480
|
if (!agentName) {
|
|
35198
|
-
console.error(
|
|
35481
|
+
console.error(chalk3.red("Agent name cannot be empty."));
|
|
35199
35482
|
process.exit(1);
|
|
35200
35483
|
}
|
|
35201
35484
|
const removed = removePresence(agentName);
|
|
@@ -35203,9 +35486,9 @@ agents.command("remove").description("Remove an agent from the presence list").a
|
|
|
35203
35486
|
console.log(JSON.stringify({ agent: agentName, removed }));
|
|
35204
35487
|
} else {
|
|
35205
35488
|
if (removed) {
|
|
35206
|
-
console.log(
|
|
35489
|
+
console.log(chalk3.green(`Agent "${agentName}" removed.`));
|
|
35207
35490
|
} else {
|
|
35208
|
-
console.error(
|
|
35491
|
+
console.error(chalk3.red(`Agent "${agentName}" not found.`));
|
|
35209
35492
|
process.exit(1);
|
|
35210
35493
|
}
|
|
35211
35494
|
}
|
|
@@ -35215,26 +35498,58 @@ agents.command("rename").description("Rename an agent in the presence list").arg
|
|
|
35215
35498
|
const old = typeof oldName === "string" ? oldName.trim() : "";
|
|
35216
35499
|
const renamed = typeof newName === "string" ? newName.trim() : "";
|
|
35217
35500
|
if (!old || !renamed) {
|
|
35218
|
-
console.error(
|
|
35501
|
+
console.error(chalk3.red("Both old and new names are required."));
|
|
35219
35502
|
process.exit(1);
|
|
35220
35503
|
}
|
|
35221
35504
|
try {
|
|
35222
35505
|
const ok = renameAgent(old, renamed);
|
|
35223
35506
|
if (!ok) {
|
|
35224
|
-
console.error(
|
|
35507
|
+
console.error(chalk3.red(`Agent "${old}" not found.`));
|
|
35225
35508
|
process.exit(1);
|
|
35226
35509
|
}
|
|
35227
35510
|
if (opts.json) {
|
|
35228
35511
|
console.log(JSON.stringify({ old_name: old, new_name: renamed, renamed: true }));
|
|
35229
35512
|
} else {
|
|
35230
|
-
console.log(
|
|
35513
|
+
console.log(chalk3.green(`Agent "${old}" renamed to "${renamed}".`));
|
|
35231
35514
|
}
|
|
35232
35515
|
} catch (e) {
|
|
35233
|
-
console.error(
|
|
35516
|
+
console.error(chalk3.red(e.message));
|
|
35234
35517
|
process.exit(1);
|
|
35235
35518
|
}
|
|
35236
35519
|
closeDb();
|
|
35237
35520
|
});
|
|
35521
|
+
program2.command("whoami").description("Show current agent identity and online status").option("--from <agent>", "Explicit agent identity").action((opts) => {
|
|
35522
|
+
const envValue = process.env.CONVERSATIONS_AGENT_ID?.trim();
|
|
35523
|
+
const agent = resolveIdentity(opts.from);
|
|
35524
|
+
let source;
|
|
35525
|
+
if (opts.from) {
|
|
35526
|
+
source = "explicit (--from flag)";
|
|
35527
|
+
} else if (envValue) {
|
|
35528
|
+
source = "env var (CONVERSATIONS_AGENT_ID)";
|
|
35529
|
+
} else {
|
|
35530
|
+
const { join: join6 } = __require("path");
|
|
35531
|
+
const { homedir: homedir5 } = __require("os");
|
|
35532
|
+
const agentIdFile = join6(homedir5(), ".conversations", "agent-id");
|
|
35533
|
+
source = `auto-generated (${agentIdFile})`;
|
|
35534
|
+
}
|
|
35535
|
+
const presence = getPresence(agent);
|
|
35536
|
+
let onlineStatus;
|
|
35537
|
+
if (presence && presence.online) {
|
|
35538
|
+
const lastSeenMs = new Date(presence.last_seen_at + "Z").getTime();
|
|
35539
|
+
const agoMs = Date.now() - lastSeenMs;
|
|
35540
|
+
const agoSec = Math.floor(agoMs / 1000);
|
|
35541
|
+
const agoStr = agoSec < 60 ? `${agoSec}s ago` : `${Math.floor(agoSec / 60)}m ago`;
|
|
35542
|
+
onlineStatus = chalk3.green(`yes`) + chalk3.dim(` (last seen ${agoStr})`);
|
|
35543
|
+
} else if (presence) {
|
|
35544
|
+
onlineStatus = chalk3.red("no") + chalk3.dim(` (last seen ${presence.last_seen_at})`);
|
|
35545
|
+
} else {
|
|
35546
|
+
onlineStatus = chalk3.red("no") + chalk3.dim(" (no presence record)");
|
|
35547
|
+
}
|
|
35548
|
+
console.log(` ${chalk3.bold("Agent:")} ${chalk3.cyan(agent)}`);
|
|
35549
|
+
console.log(` ${chalk3.bold("Source:")} ${source}`);
|
|
35550
|
+
console.log(` ${chalk3.bold("Online:")} ${onlineStatus}`);
|
|
35551
|
+
closeDb();
|
|
35552
|
+
});
|
|
35238
35553
|
program2.command("blockers").description("Check for unread blocking messages").option("--from <agent>", "Agent to check blockers for").option("--json", "Output as JSON").action((opts) => {
|
|
35239
35554
|
const agent = resolveIdentity(opts.from);
|
|
35240
35555
|
const blockers = getUnreadBlockers(agent);
|
|
@@ -35242,70 +35557,40 @@ program2.command("blockers").description("Check for unread blocking messages").o
|
|
|
35242
35557
|
console.log(JSON.stringify(blockers, null, 2));
|
|
35243
35558
|
} else {
|
|
35244
35559
|
if (blockers.length === 0) {
|
|
35245
|
-
console.log(
|
|
35560
|
+
console.log(chalk3.dim("No blocking messages."));
|
|
35246
35561
|
} else {
|
|
35247
|
-
console.log(
|
|
35562
|
+
console.log(chalk3.red.bold(`${blockers.length} blocking message(s):
|
|
35248
35563
|
`));
|
|
35249
35564
|
for (const b of blockers) {
|
|
35250
|
-
const where = b.space ?
|
|
35251
|
-
const time3 =
|
|
35252
|
-
console.log(` ${
|
|
35565
|
+
const where = b.space ? chalk3.magenta(`#${b.space}`) : chalk3.yellow("DM");
|
|
35566
|
+
const time3 = chalk3.dim(b.created_at.slice(11, 19));
|
|
35567
|
+
console.log(` ${chalk3.red(`[#${b.id}]`)} ${time3} ${chalk3.cyan(b.from_agent)} ${where}: ${b.content}`);
|
|
35253
35568
|
}
|
|
35254
|
-
console.log(
|
|
35569
|
+
console.log(chalk3.dim(`
|
|
35255
35570
|
Acknowledge with: conversations mark-read ${blockers.map((b) => b.id).join(" ")}`));
|
|
35256
35571
|
}
|
|
35257
35572
|
}
|
|
35258
35573
|
closeDb();
|
|
35259
35574
|
});
|
|
35260
|
-
program2.command("watch").description("Watch for new messages with desktop notifications").option("--from <agent>", "Your agent identity").option("--space <name>", "Watch a specific space").option("--interval <ms>", "Poll interval in milliseconds", parseInt).action((opts) => {
|
|
35575
|
+
program2.command("watch").description("Watch for new messages with desktop notifications").option("--from <agent>", "Your agent identity").option("--space <name>", "Watch a specific space").option("--all", "Watch DMs and all subscribed spaces").option("--interval <ms>", "Poll interval in milliseconds", parseInt).action((opts) => {
|
|
35261
35576
|
const agent = resolveIdentity(opts.from);
|
|
35262
35577
|
heartbeat(agent);
|
|
35263
35578
|
const interval = Number.isFinite(opts.interval) && opts.interval > 0 ? opts.interval : 1000;
|
|
35264
35579
|
const cols = Math.min(process.stdout.columns || 80, 100);
|
|
35580
|
+
let agentSpaces = [];
|
|
35581
|
+
if (opts.all) {
|
|
35582
|
+
const db2 = getDb();
|
|
35583
|
+
const rows = db2.prepare("SELECT space FROM space_members WHERE agent = ?").all(agent);
|
|
35584
|
+
agentSpaces = rows.map((r) => r.space);
|
|
35585
|
+
}
|
|
35586
|
+
const modeLabel = opts.all ? `DMs + ${agentSpaces.length} space(s)` : opts.space ? `Space: #${opts.space}` : "All DMs";
|
|
35265
35587
|
console.log("");
|
|
35266
|
-
console.log(
|
|
35267
|
-
console.log(
|
|
35268
|
-
console.log(
|
|
35588
|
+
console.log(chalk3.bold(` Conversations`) + chalk3.dim(` \u2014 watching as ${chalk3.cyan(agent)}`));
|
|
35589
|
+
console.log(chalk3.dim(` ${modeLabel} \xB7 Poll: ${interval}ms \xB7 Ctrl+C to stop`));
|
|
35590
|
+
console.log(chalk3.dim(" " + "\u2500".repeat(cols - 4)));
|
|
35269
35591
|
console.log("");
|
|
35270
35592
|
const { startPolling: startPolling2 } = (init_poll(), __toCommonJS(exports_poll));
|
|
35271
|
-
const renderContent = (
|
|
35272
|
-
const lines = content.split(`
|
|
35273
|
-
`);
|
|
35274
|
-
const rendered = [];
|
|
35275
|
-
for (const line of lines) {
|
|
35276
|
-
let l = line;
|
|
35277
|
-
const h = l.match(/^(#{1,3})\s+(.+)/);
|
|
35278
|
-
if (h) {
|
|
35279
|
-
rendered.push(chalk2.bold(h[2]));
|
|
35280
|
-
continue;
|
|
35281
|
-
}
|
|
35282
|
-
if (/^\s*[-*+]\s/.test(l)) {
|
|
35283
|
-
rendered.push(" " + chalk2.dim("\u2022") + " " + renderInline(l.replace(/^\s*[-*+]\s/, "")));
|
|
35284
|
-
continue;
|
|
35285
|
-
}
|
|
35286
|
-
const ol = l.match(/^\s*(\d+)[.)]\s(.*)/);
|
|
35287
|
-
if (ol) {
|
|
35288
|
-
rendered.push(" " + chalk2.dim(ol[1] + ".") + " " + renderInline(ol[2]));
|
|
35289
|
-
continue;
|
|
35290
|
-
}
|
|
35291
|
-
if (l.startsWith(">")) {
|
|
35292
|
-
rendered.push(chalk2.dim(" \u2502 ") + chalk2.italic(renderInline(l.replace(/^>\s?/, ""))));
|
|
35293
|
-
continue;
|
|
35294
|
-
}
|
|
35295
|
-
if (l.trimStart().startsWith("```"))
|
|
35296
|
-
continue;
|
|
35297
|
-
if (l.trim() === "") {
|
|
35298
|
-
rendered.push("");
|
|
35299
|
-
continue;
|
|
35300
|
-
}
|
|
35301
|
-
rendered.push(renderInline(l));
|
|
35302
|
-
}
|
|
35303
|
-
return rendered.join(`
|
|
35304
|
-
`);
|
|
35305
|
-
};
|
|
35306
|
-
const renderInline = (text) => {
|
|
35307
|
-
return text.replace(/`([^`]+)`/g, (_, code) => chalk2.bgGray.white(` ${code} `)).replace(/\*\*\*(.+?)\*\*\*/g, (_, t) => chalk2.bold.italic(t)).replace(/\*\*(.+?)\*\*/g, (_, t) => chalk2.bold(t)).replace(/\*(.+?)\*/g, (_, t) => chalk2.italic(t)).replace(/~~(.+?)~~/g, (_, t) => chalk2.strikethrough(t));
|
|
35308
|
-
};
|
|
35593
|
+
const { renderContent: renderContent2 } = (init_terminal_markdown(), __toCommonJS(exports_terminal_markdown));
|
|
35309
35594
|
const desktopNotify = (title, body) => {
|
|
35310
35595
|
if (process.platform === "darwin") {
|
|
35311
35596
|
try {
|
|
@@ -35317,52 +35602,78 @@ program2.command("watch").description("Watch for new messages with desktop notif
|
|
|
35317
35602
|
}
|
|
35318
35603
|
};
|
|
35319
35604
|
const renderMessage = (msg) => {
|
|
35320
|
-
const time3 =
|
|
35321
|
-
const where = msg.space ?
|
|
35322
|
-
const priority = msg.priority !== "normal" ? msg.priority === "urgent" ?
|
|
35323
|
-
const blocking = msg.blocking ?
|
|
35324
|
-
const sender =
|
|
35605
|
+
const time3 = chalk3.dim(msg.created_at.slice(11, 19));
|
|
35606
|
+
const where = msg.space ? chalk3.magenta(`#${msg.space}`) : chalk3.yellow("DM");
|
|
35607
|
+
const priority = msg.priority !== "normal" ? msg.priority === "urgent" ? chalk3.red.bold(` [${msg.priority}]`) : msg.priority === "high" ? chalk3.yellow(` [${msg.priority}]`) : chalk3.dim(` [${msg.priority}]`) : "";
|
|
35608
|
+
const blocking = msg.blocking ? chalk3.red.bold(" \u26A0 BLOCKER") : "";
|
|
35609
|
+
const sender = chalk3.cyan.bold(msg.from_agent);
|
|
35325
35610
|
console.log(` ${sender} ${where} ${time3}${priority}${blocking}`);
|
|
35326
|
-
const content =
|
|
35611
|
+
const content = renderContent2(msg.content);
|
|
35327
35612
|
const indented = content.split(`
|
|
35328
35613
|
`).map((l) => " " + l).join(`
|
|
35329
35614
|
`);
|
|
35330
35615
|
console.log(indented);
|
|
35331
|
-
console.log(
|
|
35616
|
+
console.log(chalk3.dim(" " + "\xB7".repeat(Math.min(cols - 8, 60))));
|
|
35332
35617
|
console.log("");
|
|
35333
35618
|
};
|
|
35334
|
-
|
|
35335
|
-
to:
|
|
35336
|
-
|
|
35337
|
-
|
|
35338
|
-
|
|
35339
|
-
|
|
35340
|
-
|
|
35341
|
-
|
|
35619
|
+
if (opts.all) {
|
|
35620
|
+
const dmRecent = readMessages({ to: agent, limit: 20, order: "asc" });
|
|
35621
|
+
const spaceRecent = [];
|
|
35622
|
+
for (const sp of agentSpaces) {
|
|
35623
|
+
spaceRecent.push(...readMessages({ space: sp, limit: 10, order: "asc" }));
|
|
35624
|
+
}
|
|
35625
|
+
const recent = [...dmRecent, ...spaceRecent].sort((a, b) => a.created_at.localeCompare(b.created_at)).slice(-20);
|
|
35626
|
+
if (recent.length > 0) {
|
|
35627
|
+
console.log(chalk3.dim(` \u2500\u2500 Recent messages (${recent.length}) \u2500\u2500
|
|
35628
|
+
`));
|
|
35629
|
+
for (const msg of recent) {
|
|
35630
|
+
renderMessage(msg);
|
|
35631
|
+
}
|
|
35632
|
+
console.log(chalk3.dim(` \u2500\u2500 Live \u2500\u2500
|
|
35342
35633
|
`));
|
|
35343
|
-
for (const msg of recent) {
|
|
35344
|
-
renderMessage(msg);
|
|
35345
35634
|
}
|
|
35346
|
-
|
|
35635
|
+
} else {
|
|
35636
|
+
const recent = readMessages({
|
|
35637
|
+
to: opts.space ? undefined : agent,
|
|
35638
|
+
space: opts.space,
|
|
35639
|
+
limit: 20,
|
|
35640
|
+
order: "asc"
|
|
35641
|
+
});
|
|
35642
|
+
if (recent.length > 0) {
|
|
35643
|
+
console.log(chalk3.dim(` \u2500\u2500 Recent messages (${recent.length}) \u2500\u2500
|
|
35347
35644
|
`));
|
|
35348
|
-
|
|
35349
|
-
startPolling2({
|
|
35350
|
-
to_agent: opts.space ? undefined : agent,
|
|
35351
|
-
space: opts.space,
|
|
35352
|
-
interval_ms: interval,
|
|
35353
|
-
on_messages: (messages) => {
|
|
35354
|
-
for (const msg of messages) {
|
|
35355
|
-
if (msg.from_agent === agent)
|
|
35356
|
-
continue;
|
|
35645
|
+
for (const msg of recent) {
|
|
35357
35646
|
renderMessage(msg);
|
|
35358
|
-
const where = msg.space ? `#${msg.space}` : "DM";
|
|
35359
|
-
const preview = msg.content.replace(/[*#`~_>\-]/g, "").slice(0, 150);
|
|
35360
|
-
desktopNotify(`${msg.from_agent} (${where})`, preview);
|
|
35361
35647
|
}
|
|
35648
|
+
console.log(chalk3.dim(` \u2500\u2500 Live \u2500\u2500
|
|
35649
|
+
`));
|
|
35362
35650
|
}
|
|
35363
|
-
}
|
|
35651
|
+
}
|
|
35652
|
+
const onNewMessages = (messages) => {
|
|
35653
|
+
for (const msg of messages) {
|
|
35654
|
+
if (msg.from_agent === agent)
|
|
35655
|
+
continue;
|
|
35656
|
+
renderMessage(msg);
|
|
35657
|
+
const where = msg.space ? `#${msg.space}` : "DM";
|
|
35658
|
+
const preview = msg.content.replace(/[*#`~_>\-]/g, "").slice(0, 150);
|
|
35659
|
+
desktopNotify(`${msg.from_agent} (${where})`, preview);
|
|
35660
|
+
}
|
|
35661
|
+
};
|
|
35662
|
+
if (opts.all) {
|
|
35663
|
+
startPolling2({ to_agent: agent, interval_ms: interval, on_messages: onNewMessages });
|
|
35664
|
+
for (const sp of agentSpaces) {
|
|
35665
|
+
startPolling2({ space: sp, interval_ms: interval, on_messages: onNewMessages });
|
|
35666
|
+
}
|
|
35667
|
+
} else {
|
|
35668
|
+
startPolling2({
|
|
35669
|
+
to_agent: opts.space ? undefined : agent,
|
|
35670
|
+
space: opts.space,
|
|
35671
|
+
interval_ms: interval,
|
|
35672
|
+
on_messages: onNewMessages
|
|
35673
|
+
});
|
|
35674
|
+
}
|
|
35364
35675
|
process.on("SIGINT", () => {
|
|
35365
|
-
console.log(
|
|
35676
|
+
console.log(chalk3.dim(`
|
|
35366
35677
|
Stopped watching.`));
|
|
35367
35678
|
closeDb();
|
|
35368
35679
|
process.exit(0);
|
|
@@ -35372,15 +35683,19 @@ program2.command("mcp").description("Start MCP server").action(async () => {
|
|
|
35372
35683
|
const { startMcpServer: startMcpServer2 } = await Promise.resolve().then(() => (init_mcp2(), exports_mcp));
|
|
35373
35684
|
await startMcpServer2();
|
|
35374
35685
|
});
|
|
35375
|
-
program2.command("dashboard").description("Start web dashboard").option("--port <port>", "Port to listen on", parseInt).option("--host <host>", "Host to bind (default: 127.0.0.1)").action(async (opts) => {
|
|
35686
|
+
program2.command("dashboard").description("Start web dashboard").option("--port <port>", "Port to listen on", parseInt).option("--host <host>", "Host to bind (default: 127.0.0.1)").option("--open", "Auto-open dashboard in browser").action(async (opts) => {
|
|
35376
35687
|
const { startDashboardServer: startDashboardServer2 } = await Promise.resolve().then(() => (init_serve(), exports_serve));
|
|
35377
35688
|
const port = Number.isFinite(opts.port) && opts.port >= 0 && opts.port <= 65535 ? opts.port : 0;
|
|
35378
|
-
startDashboardServer2(port, opts.host);
|
|
35689
|
+
const server2 = startDashboardServer2(port, opts.host);
|
|
35690
|
+
if (opts.open) {
|
|
35691
|
+
const { exec } = __require("child_process");
|
|
35692
|
+
exec(`open http://localhost:${server2.port}`);
|
|
35693
|
+
}
|
|
35379
35694
|
});
|
|
35380
35695
|
program2.action(() => {
|
|
35381
35696
|
if (!process.stdin.isTTY) {
|
|
35382
|
-
console.error(
|
|
35383
|
-
console.error(
|
|
35697
|
+
console.error(chalk3.red("Interactive mode requires a TTY terminal."));
|
|
35698
|
+
console.error(chalk3.dim("Use subcommands (send, read, sessions, etc.) for non-interactive use."));
|
|
35384
35699
|
process.exit(1);
|
|
35385
35700
|
}
|
|
35386
35701
|
const agent = resolveIdentity();
|