@hasna/conversations 0.1.4 → 0.1.6
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 +626 -0
- package/bin/index.js +234 -21
- package/bin/mcp.js +315 -156
- package/dist/hooks/blocker-hook.d.ts +2 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +243 -153
- package/dist/lib/identity.d.ts +1 -1
- package/dist/lib/messages.d.ts +1 -0
- package/dist/lib/presence.d.ts +1 -0
- package/dist/types.d.ts +2 -0
- package/package.json +4 -3
package/bin/index.js
CHANGED
|
@@ -4,6 +4,7 @@ var __create = Object.create;
|
|
|
4
4
|
var __getProtoOf = Object.getPrototypeOf;
|
|
5
5
|
var __defProp = Object.defineProperty;
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
9
|
var __toESM = (mod, isNodeMode, target) => {
|
|
9
10
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
@@ -16,6 +17,20 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
16
17
|
});
|
|
17
18
|
return to;
|
|
18
19
|
};
|
|
20
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
21
|
+
var __toCommonJS = (from) => {
|
|
22
|
+
var entry = __moduleCache.get(from), desc;
|
|
23
|
+
if (entry)
|
|
24
|
+
return entry;
|
|
25
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
26
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
27
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
28
|
+
get: () => from[key],
|
|
29
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
30
|
+
}));
|
|
31
|
+
__moduleCache.set(from, entry);
|
|
32
|
+
return entry;
|
|
33
|
+
};
|
|
19
34
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
20
35
|
var __export = (target, all) => {
|
|
21
36
|
for (var name in all)
|
|
@@ -1869,6 +1884,12 @@ var require_commander = __commonJS((exports) => {
|
|
|
1869
1884
|
});
|
|
1870
1885
|
|
|
1871
1886
|
// src/lib/db.ts
|
|
1887
|
+
var exports_db = {};
|
|
1888
|
+
__export(exports_db, {
|
|
1889
|
+
getDbPath: () => getDbPath,
|
|
1890
|
+
getDb: () => getDb,
|
|
1891
|
+
closeDb: () => closeDb
|
|
1892
|
+
});
|
|
1872
1893
|
import { Database } from "bun:sqlite";
|
|
1873
1894
|
import { mkdirSync } from "fs";
|
|
1874
1895
|
import { join, dirname } from "path";
|
|
@@ -2006,6 +2027,10 @@ function getDb() {
|
|
|
2006
2027
|
db.exec("ALTER TABLE messages ADD COLUMN pinned_at TEXT");
|
|
2007
2028
|
db.exec("CREATE INDEX IF NOT EXISTS idx_messages_pinned ON messages(pinned_at)");
|
|
2008
2029
|
}
|
|
2030
|
+
if (!colNames2.includes("blocking")) {
|
|
2031
|
+
db.exec("ALTER TABLE messages ADD COLUMN blocking INTEGER NOT NULL DEFAULT 0");
|
|
2032
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_messages_blocking ON messages(blocking)");
|
|
2033
|
+
}
|
|
2009
2034
|
return db;
|
|
2010
2035
|
}
|
|
2011
2036
|
function closeDb() {
|
|
@@ -2030,7 +2055,8 @@ function parseMessage(row) {
|
|
|
2030
2055
|
}
|
|
2031
2056
|
return {
|
|
2032
2057
|
...row,
|
|
2033
|
-
metadata
|
|
2058
|
+
metadata,
|
|
2059
|
+
blocking: !!row.blocking
|
|
2034
2060
|
};
|
|
2035
2061
|
}
|
|
2036
2062
|
function sendMessage(opts) {
|
|
@@ -2039,12 +2065,13 @@ function sendMessage(opts) {
|
|
|
2039
2065
|
const sessionId = explicitSession ?? (opts.space ? `space:${opts.space}` : `${[opts.from, opts.to].sort().join("-")}-${randomUUID().slice(0, 8)}`);
|
|
2040
2066
|
const metadata = opts.metadata ? JSON.stringify(opts.metadata) : null;
|
|
2041
2067
|
const normalizedPriority = opts.priority === "low" || opts.priority === "normal" || opts.priority === "high" || opts.priority === "urgent" ? opts.priority : "normal";
|
|
2068
|
+
const blocking = opts.blocking ? 1 : 0;
|
|
2042
2069
|
const stmt = db2.prepare(`
|
|
2043
|
-
INSERT INTO messages (session_id, from_agent, to_agent, space, content, priority, working_dir, repository, branch, metadata)
|
|
2044
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
2070
|
+
INSERT INTO messages (session_id, from_agent, to_agent, space, content, priority, working_dir, repository, branch, metadata, blocking)
|
|
2071
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
2045
2072
|
RETURNING *
|
|
2046
2073
|
`);
|
|
2047
|
-
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);
|
|
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);
|
|
2048
2075
|
return parseMessage(row);
|
|
2049
2076
|
}
|
|
2050
2077
|
function readMessages(opts = {}) {
|
|
@@ -2213,6 +2240,19 @@ function getPinnedMessages(opts) {
|
|
|
2213
2240
|
const rows = db2.prepare(`SELECT * FROM messages ${where} ORDER BY pinned_at DESC, id DESC ${limit}`).all(...params);
|
|
2214
2241
|
return rows.map(parseMessage);
|
|
2215
2242
|
}
|
|
2243
|
+
function getUnreadBlockers(agent) {
|
|
2244
|
+
const db2 = getDb();
|
|
2245
|
+
const rows = db2.prepare(`
|
|
2246
|
+
SELECT * FROM messages
|
|
2247
|
+
WHERE blocking = 1 AND read_at IS NULL
|
|
2248
|
+
AND (
|
|
2249
|
+
to_agent = ?
|
|
2250
|
+
OR space IN (SELECT space FROM space_members WHERE agent = ?)
|
|
2251
|
+
)
|
|
2252
|
+
ORDER BY created_at ASC, id ASC
|
|
2253
|
+
`).all(agent, agent);
|
|
2254
|
+
return rows.map(parseMessage);
|
|
2255
|
+
}
|
|
2216
2256
|
function searchMessages(opts) {
|
|
2217
2257
|
const db2 = getDb();
|
|
2218
2258
|
const conditions = ["content LIKE ?"];
|
|
@@ -2975,6 +3015,16 @@ var init_names = __esm(() => {
|
|
|
2975
3015
|
import { readFileSync, writeFileSync, mkdirSync as mkdirSync2 } from "fs";
|
|
2976
3016
|
import { join as join2, dirname as dirname2 } from "path";
|
|
2977
3017
|
import { homedir as homedir2 } from "os";
|
|
3018
|
+
function isNameTaken(name) {
|
|
3019
|
+
try {
|
|
3020
|
+
const { getDb: getDb2 } = (init_db(), __toCommonJS(exports_db));
|
|
3021
|
+
const db2 = getDb2();
|
|
3022
|
+
const row = db2.prepare("SELECT agent FROM agent_presence WHERE agent = ?").get(name);
|
|
3023
|
+
return !!row;
|
|
3024
|
+
} catch {
|
|
3025
|
+
return false;
|
|
3026
|
+
}
|
|
3027
|
+
}
|
|
2978
3028
|
function getAutoName() {
|
|
2979
3029
|
if (cachedAutoName)
|
|
2980
3030
|
return cachedAutoName;
|
|
@@ -2985,7 +3035,14 @@ function getAutoName() {
|
|
|
2985
3035
|
return name2;
|
|
2986
3036
|
}
|
|
2987
3037
|
} catch {}
|
|
2988
|
-
const
|
|
3038
|
+
const shuffled = [...AGENT_NAMES].sort(() => Math.random() - 0.5);
|
|
3039
|
+
let name = shuffled[0];
|
|
3040
|
+
for (const candidate of shuffled) {
|
|
3041
|
+
if (!isNameTaken(candidate)) {
|
|
3042
|
+
name = candidate;
|
|
3043
|
+
break;
|
|
3044
|
+
}
|
|
3045
|
+
}
|
|
2989
3046
|
cachedAutoName = name;
|
|
2990
3047
|
try {
|
|
2991
3048
|
mkdirSync2(dirname2(AGENT_ID_FILE), { recursive: true });
|
|
@@ -3055,6 +3112,22 @@ function listAgents(opts) {
|
|
|
3055
3112
|
const rows = db2.prepare(query).all(...params);
|
|
3056
3113
|
return rows.map(parsePresence);
|
|
3057
3114
|
}
|
|
3115
|
+
function removePresence(agent) {
|
|
3116
|
+
const db2 = getDb();
|
|
3117
|
+
const result = db2.prepare("DELETE FROM agent_presence WHERE agent = ?").run(agent);
|
|
3118
|
+
return result.changes > 0;
|
|
3119
|
+
}
|
|
3120
|
+
function renameAgent(oldName, newName) {
|
|
3121
|
+
const db2 = getDb();
|
|
3122
|
+
const existing = db2.prepare("SELECT agent FROM agent_presence WHERE agent = ?").get(oldName);
|
|
3123
|
+
if (!existing)
|
|
3124
|
+
return false;
|
|
3125
|
+
const conflict = db2.prepare("SELECT agent FROM agent_presence WHERE agent = ?").get(newName);
|
|
3126
|
+
if (conflict)
|
|
3127
|
+
throw new Error(`Agent "${newName}" already exists`);
|
|
3128
|
+
db2.prepare("UPDATE agent_presence SET agent = ? WHERE agent = ?").run(newName, oldName);
|
|
3129
|
+
return true;
|
|
3130
|
+
}
|
|
3058
3131
|
var ONLINE_THRESHOLD_SECONDS = 60;
|
|
3059
3132
|
var init_presence = __esm(() => {
|
|
3060
3133
|
init_db();
|
|
@@ -3064,12 +3137,13 @@ var init_presence = __esm(() => {
|
|
|
3064
3137
|
var require_package = __commonJS((exports, module) => {
|
|
3065
3138
|
module.exports = {
|
|
3066
3139
|
name: "@hasna/conversations",
|
|
3067
|
-
version: "0.1.
|
|
3140
|
+
version: "0.1.6",
|
|
3068
3141
|
description: "Real-time CLI messaging for AI agents",
|
|
3069
3142
|
type: "module",
|
|
3070
3143
|
bin: {
|
|
3071
3144
|
conversations: "bin/index.js",
|
|
3072
|
-
"conversations-mcp": "bin/mcp.js"
|
|
3145
|
+
"conversations-mcp": "bin/mcp.js",
|
|
3146
|
+
"conversations-hook": "bin/hook.js"
|
|
3073
3147
|
},
|
|
3074
3148
|
exports: {
|
|
3075
3149
|
".": {
|
|
@@ -3087,7 +3161,7 @@ var require_package = __commonJS((exports, module) => {
|
|
|
3087
3161
|
main: "./dist/index.js",
|
|
3088
3162
|
types: "./dist/index.d.ts",
|
|
3089
3163
|
scripts: {
|
|
3090
|
-
build: "bun build ./src/cli/index.tsx --outdir ./bin --target bun --external ink --external react --external chalk && bun build ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun build ./src/index.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
3164
|
+
build: "bun build ./src/cli/index.tsx --outdir ./bin --target bun --external ink --external react --external chalk && bun build ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun build ./src/hooks/blocker-hook.ts --outfile ./bin/hook.js --target bun && bun build ./src/index.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
3091
3165
|
"build:dashboard": "cd dashboard && bun install && bun run build",
|
|
3092
3166
|
test: "bun test",
|
|
3093
3167
|
dev: "bun run ./src/cli/index.tsx",
|
|
@@ -32041,9 +32115,10 @@ var init_mcp2 = __esm(() => {
|
|
|
32041
32115
|
working_dir: exports_external.string().optional().describe("Working directory context"),
|
|
32042
32116
|
repository: exports_external.string().optional().describe("Repository context"),
|
|
32043
32117
|
branch: exports_external.string().optional().describe("Branch context"),
|
|
32044
|
-
metadata: exports_external.string().optional().describe("JSON metadata string")
|
|
32118
|
+
metadata: exports_external.string().optional().describe("JSON metadata string"),
|
|
32119
|
+
blocking: exports_external.boolean().optional().describe("Send as a blocking message. Recipients must acknowledge before continuing.")
|
|
32045
32120
|
}
|
|
32046
|
-
}, async ({ from: fromParam, to, content, session_id, priority, working_dir, repository, branch, metadata }) => {
|
|
32121
|
+
}, async ({ from: fromParam, to, content, session_id, priority, working_dir, repository, branch, metadata, blocking }) => {
|
|
32047
32122
|
const from = resolveIdentity(fromParam);
|
|
32048
32123
|
let parsedMetadata;
|
|
32049
32124
|
if (metadata) {
|
|
@@ -32065,7 +32140,8 @@ var init_mcp2 = __esm(() => {
|
|
|
32065
32140
|
working_dir,
|
|
32066
32141
|
repository,
|
|
32067
32142
|
branch,
|
|
32068
|
-
metadata: parsedMetadata
|
|
32143
|
+
metadata: parsedMetadata,
|
|
32144
|
+
blocking
|
|
32069
32145
|
});
|
|
32070
32146
|
return {
|
|
32071
32147
|
content: [{ type: "text", text: JSON.stringify(msg, null, 2) }]
|
|
@@ -32252,9 +32328,10 @@ var init_mcp2 = __esm(() => {
|
|
|
32252
32328
|
from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
|
|
32253
32329
|
space: exports_external.string().describe("Space name"),
|
|
32254
32330
|
content: exports_external.string().describe("Message content"),
|
|
32255
|
-
priority: exports_external.enum(["low", "normal", "high", "urgent"]).optional().describe("Message priority")
|
|
32331
|
+
priority: exports_external.enum(["low", "normal", "high", "urgent"]).optional().describe("Message priority"),
|
|
32332
|
+
blocking: exports_external.boolean().optional().describe("Send as a blocking message. All space members must acknowledge.")
|
|
32256
32333
|
}
|
|
32257
|
-
}, async ({ from: fromParam, space, content, priority }) => {
|
|
32334
|
+
}, async ({ from: fromParam, space, content, priority, blocking }) => {
|
|
32258
32335
|
const from = resolveIdentity(fromParam);
|
|
32259
32336
|
const sp = getSpace(space);
|
|
32260
32337
|
if (!sp) {
|
|
@@ -32269,7 +32346,8 @@ var init_mcp2 = __esm(() => {
|
|
|
32269
32346
|
content,
|
|
32270
32347
|
space,
|
|
32271
32348
|
session_id: `space:${space}`,
|
|
32272
|
-
priority
|
|
32349
|
+
priority,
|
|
32350
|
+
blocking
|
|
32273
32351
|
});
|
|
32274
32352
|
return {
|
|
32275
32353
|
content: [{ type: "text", text: JSON.stringify(msg, null, 2) }]
|
|
@@ -32708,6 +32786,74 @@ var init_mcp2 = __esm(() => {
|
|
|
32708
32786
|
content: [{ type: "text", text: JSON.stringify(agents, null, 2) }]
|
|
32709
32787
|
};
|
|
32710
32788
|
});
|
|
32789
|
+
server.registerTool("get_blockers", {
|
|
32790
|
+
title: "Get Blockers",
|
|
32791
|
+
description: "Check for unread blocking messages targeting you. Returns messages that must be acknowledged before continuing.",
|
|
32792
|
+
inputSchema: {
|
|
32793
|
+
from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var.")
|
|
32794
|
+
}
|
|
32795
|
+
}, async ({ from: fromParam }) => {
|
|
32796
|
+
const agent = resolveIdentity(fromParam);
|
|
32797
|
+
const blockers = getUnreadBlockers(agent);
|
|
32798
|
+
return {
|
|
32799
|
+
content: [{ type: "text", text: JSON.stringify(blockers, null, 2) }]
|
|
32800
|
+
};
|
|
32801
|
+
});
|
|
32802
|
+
server.registerTool("remove_agent", {
|
|
32803
|
+
title: "Remove Agent",
|
|
32804
|
+
description: "Remove an agent from the presence list. Only the agent itself should remove its own presence.",
|
|
32805
|
+
inputSchema: {
|
|
32806
|
+
from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
|
|
32807
|
+
agent: exports_external.string().optional().describe("Agent to remove (defaults to yourself)")
|
|
32808
|
+
}
|
|
32809
|
+
}, async ({ from: fromParam, agent: targetAgent }) => {
|
|
32810
|
+
const self = resolveIdentity(fromParam);
|
|
32811
|
+
const agent = targetAgent?.trim() || self;
|
|
32812
|
+
const removed = removePresence(agent);
|
|
32813
|
+
if (!removed) {
|
|
32814
|
+
return {
|
|
32815
|
+
content: [{ type: "text", text: `Agent "${agent}" not found` }],
|
|
32816
|
+
isError: true
|
|
32817
|
+
};
|
|
32818
|
+
}
|
|
32819
|
+
return {
|
|
32820
|
+
content: [{ type: "text", text: JSON.stringify({ agent, removed: true }, null, 2) }]
|
|
32821
|
+
};
|
|
32822
|
+
});
|
|
32823
|
+
server.registerTool("rename_agent", {
|
|
32824
|
+
title: "Rename Agent",
|
|
32825
|
+
description: "Rename an agent in the presence list. By default renames yourself.",
|
|
32826
|
+
inputSchema: {
|
|
32827
|
+
from: exports_external.string().optional().describe("Your current agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
|
|
32828
|
+
new_name: exports_external.string().describe("The new name for the agent")
|
|
32829
|
+
}
|
|
32830
|
+
}, async ({ from: fromParam, new_name }) => {
|
|
32831
|
+
const oldName = resolveIdentity(fromParam);
|
|
32832
|
+
const newName = new_name.trim();
|
|
32833
|
+
if (!newName) {
|
|
32834
|
+
return {
|
|
32835
|
+
content: [{ type: "text", text: "New name cannot be empty" }],
|
|
32836
|
+
isError: true
|
|
32837
|
+
};
|
|
32838
|
+
}
|
|
32839
|
+
try {
|
|
32840
|
+
const renamed = renameAgent(oldName, newName);
|
|
32841
|
+
if (!renamed) {
|
|
32842
|
+
return {
|
|
32843
|
+
content: [{ type: "text", text: `Agent "${oldName}" not found in presence list` }],
|
|
32844
|
+
isError: true
|
|
32845
|
+
};
|
|
32846
|
+
}
|
|
32847
|
+
return {
|
|
32848
|
+
content: [{ type: "text", text: JSON.stringify({ old_name: oldName, new_name: newName, renamed: true }, null, 2) }]
|
|
32849
|
+
};
|
|
32850
|
+
} catch (e) {
|
|
32851
|
+
return {
|
|
32852
|
+
content: [{ type: "text", text: e.message }],
|
|
32853
|
+
isError: true
|
|
32854
|
+
};
|
|
32855
|
+
}
|
|
32856
|
+
});
|
|
32711
32857
|
isDirectRun = import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith("mcp.js") || process.argv[1]?.endsWith("mcp.ts");
|
|
32712
32858
|
if (isDirectRun) {
|
|
32713
32859
|
startMcpServer().catch((error48) => {
|
|
@@ -34227,7 +34373,7 @@ function App({ agent }) {
|
|
|
34227
34373
|
var import__package2 = __toESM(require_package(), 1);
|
|
34228
34374
|
var program2 = new Command;
|
|
34229
34375
|
program2.name("conversations").description("Real-time CLI messaging for AI agents").version(import__package2.default.version);
|
|
34230
|
-
program2.command("send").description("Send a message to an agent").argument("<message>", "Message content").requiredOption("--to <agent>", "Recipient agent ID").option("--from <agent>", "Sender agent ID").option("--session <id>", "Session ID (auto-generated if omitted)").option("--priority <level>", "Priority: low, normal, high, urgent", "normal").option("--working-dir <path>", "Working directory context").option("--repository <repo>", "Repository context").option("--branch <branch>", "Branch context").option("--metadata <json>", "JSON metadata string").option("--json", "Output as JSON").action((message, opts) => {
|
|
34376
|
+
program2.command("send").description("Send a message to an agent").argument("<message>", "Message content").requiredOption("--to <agent>", "Recipient agent ID").option("--from <agent>", "Sender agent ID").option("--session <id>", "Session ID (auto-generated if omitted)").option("--priority <level>", "Priority: low, normal, high, urgent", "normal").option("--working-dir <path>", "Working directory context").option("--repository <repo>", "Repository context").option("--branch <branch>", "Branch context").option("--metadata <json>", "JSON metadata string").option("--blocking", "Send as a blocking message (recipient must acknowledge)").option("--json", "Output as JSON").action((message, opts) => {
|
|
34231
34377
|
const from = resolveIdentity(opts.from).trim();
|
|
34232
34378
|
const to = typeof opts.to === "string" ? opts.to.trim() : "";
|
|
34233
34379
|
const content = typeof message === "string" ? message : "";
|
|
@@ -34262,7 +34408,8 @@ program2.command("send").description("Send a message to an agent").argument("<me
|
|
|
34262
34408
|
working_dir: opts.workingDir,
|
|
34263
34409
|
repository: opts.repository,
|
|
34264
34410
|
branch: opts.branch,
|
|
34265
|
-
metadata
|
|
34411
|
+
metadata,
|
|
34412
|
+
blocking: opts.blocking
|
|
34266
34413
|
});
|
|
34267
34414
|
if (opts.json) {
|
|
34268
34415
|
console.log(JSON.stringify(msg, null, 2));
|
|
@@ -34979,17 +35126,18 @@ program2.command("unpin").description("Unpin a message").argument("<id>", "Messa
|
|
|
34979
35126
|
}
|
|
34980
35127
|
closeDb();
|
|
34981
35128
|
});
|
|
34982
|
-
program2.command("agents").description("
|
|
35129
|
+
var agents = program2.command("agents").description("Manage agents");
|
|
35130
|
+
agents.command("list").description("List all agents with their presence status").option("--online", "Only show online agents").option("--json", "Output as JSON").action((opts) => {
|
|
34983
35131
|
const agent = resolveIdentity();
|
|
34984
35132
|
heartbeat(agent);
|
|
34985
|
-
const
|
|
35133
|
+
const agentsList = listAgents({ online_only: opts.online });
|
|
34986
35134
|
if (opts.json) {
|
|
34987
|
-
console.log(JSON.stringify(
|
|
35135
|
+
console.log(JSON.stringify(agentsList, null, 2));
|
|
34988
35136
|
} else {
|
|
34989
|
-
if (
|
|
35137
|
+
if (agentsList.length === 0) {
|
|
34990
35138
|
console.log(chalk2.dim("No agents found."));
|
|
34991
35139
|
} else {
|
|
34992
|
-
for (const a of
|
|
35140
|
+
for (const a of agentsList) {
|
|
34993
35141
|
const status = a.online ? chalk2.green("online") : chalk2.dim("offline");
|
|
34994
35142
|
const lastSeen = chalk2.dim(a.last_seen_at.slice(0, 19));
|
|
34995
35143
|
const agentName = a.agent === agent ? chalk2.cyan(`${a.agent} (you)`) : chalk2.cyan(a.agent);
|
|
@@ -34999,6 +35147,71 @@ program2.command("agents").description("List all agents with their presence stat
|
|
|
34999
35147
|
}
|
|
35000
35148
|
closeDb();
|
|
35001
35149
|
});
|
|
35150
|
+
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) => {
|
|
35151
|
+
const agentName = typeof name === "string" ? name.trim() : "";
|
|
35152
|
+
if (!agentName) {
|
|
35153
|
+
console.error(chalk2.red("Agent name cannot be empty."));
|
|
35154
|
+
process.exit(1);
|
|
35155
|
+
}
|
|
35156
|
+
const removed = removePresence(agentName);
|
|
35157
|
+
if (opts.json) {
|
|
35158
|
+
console.log(JSON.stringify({ agent: agentName, removed }));
|
|
35159
|
+
} else {
|
|
35160
|
+
if (removed) {
|
|
35161
|
+
console.log(chalk2.green(`Agent "${agentName}" removed.`));
|
|
35162
|
+
} else {
|
|
35163
|
+
console.error(chalk2.red(`Agent "${agentName}" not found.`));
|
|
35164
|
+
process.exit(1);
|
|
35165
|
+
}
|
|
35166
|
+
}
|
|
35167
|
+
closeDb();
|
|
35168
|
+
});
|
|
35169
|
+
agents.command("rename").description("Rename an agent in the presence list").argument("<old-name>", "Current agent name").argument("<new-name>", "New agent name").option("--json", "Output as JSON").action((oldName, newName, opts) => {
|
|
35170
|
+
const old = typeof oldName === "string" ? oldName.trim() : "";
|
|
35171
|
+
const renamed = typeof newName === "string" ? newName.trim() : "";
|
|
35172
|
+
if (!old || !renamed) {
|
|
35173
|
+
console.error(chalk2.red("Both old and new names are required."));
|
|
35174
|
+
process.exit(1);
|
|
35175
|
+
}
|
|
35176
|
+
try {
|
|
35177
|
+
const ok = renameAgent(old, renamed);
|
|
35178
|
+
if (!ok) {
|
|
35179
|
+
console.error(chalk2.red(`Agent "${old}" not found.`));
|
|
35180
|
+
process.exit(1);
|
|
35181
|
+
}
|
|
35182
|
+
if (opts.json) {
|
|
35183
|
+
console.log(JSON.stringify({ old_name: old, new_name: renamed, renamed: true }));
|
|
35184
|
+
} else {
|
|
35185
|
+
console.log(chalk2.green(`Agent "${old}" renamed to "${renamed}".`));
|
|
35186
|
+
}
|
|
35187
|
+
} catch (e) {
|
|
35188
|
+
console.error(chalk2.red(e.message));
|
|
35189
|
+
process.exit(1);
|
|
35190
|
+
}
|
|
35191
|
+
closeDb();
|
|
35192
|
+
});
|
|
35193
|
+
program2.command("blockers").description("Check for unread blocking messages").option("--from <agent>", "Agent to check blockers for").option("--json", "Output as JSON").action((opts) => {
|
|
35194
|
+
const agent = resolveIdentity(opts.from);
|
|
35195
|
+
const blockers = getUnreadBlockers(agent);
|
|
35196
|
+
if (opts.json) {
|
|
35197
|
+
console.log(JSON.stringify(blockers, null, 2));
|
|
35198
|
+
} else {
|
|
35199
|
+
if (blockers.length === 0) {
|
|
35200
|
+
console.log(chalk2.dim("No blocking messages."));
|
|
35201
|
+
} else {
|
|
35202
|
+
console.log(chalk2.red.bold(`${blockers.length} blocking message(s):
|
|
35203
|
+
`));
|
|
35204
|
+
for (const b of blockers) {
|
|
35205
|
+
const where = b.space ? chalk2.magenta(`#${b.space}`) : chalk2.yellow("DM");
|
|
35206
|
+
const time3 = chalk2.dim(b.created_at.slice(11, 19));
|
|
35207
|
+
console.log(` ${chalk2.red(`[#${b.id}]`)} ${time3} ${chalk2.cyan(b.from_agent)} ${where}: ${b.content}`);
|
|
35208
|
+
}
|
|
35209
|
+
console.log(chalk2.dim(`
|
|
35210
|
+
Acknowledge with: conversations mark-read ${blockers.map((b) => b.id).join(" ")}`));
|
|
35211
|
+
}
|
|
35212
|
+
}
|
|
35213
|
+
closeDb();
|
|
35214
|
+
});
|
|
35002
35215
|
program2.command("mcp").description("Start MCP server").action(async () => {
|
|
35003
35216
|
const { startMcpServer: startMcpServer2 } = await Promise.resolve().then(() => (init_mcp2(), exports_mcp));
|
|
35004
35217
|
await startMcpServer2();
|