@hasna/conversations 0.1.5 → 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 +114 -16
- package/bin/mcp.js +244 -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/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 });
|
|
@@ -3080,12 +3137,13 @@ var init_presence = __esm(() => {
|
|
|
3080
3137
|
var require_package = __commonJS((exports, module) => {
|
|
3081
3138
|
module.exports = {
|
|
3082
3139
|
name: "@hasna/conversations",
|
|
3083
|
-
version: "0.1.
|
|
3140
|
+
version: "0.1.6",
|
|
3084
3141
|
description: "Real-time CLI messaging for AI agents",
|
|
3085
3142
|
type: "module",
|
|
3086
3143
|
bin: {
|
|
3087
3144
|
conversations: "bin/index.js",
|
|
3088
|
-
"conversations-mcp": "bin/mcp.js"
|
|
3145
|
+
"conversations-mcp": "bin/mcp.js",
|
|
3146
|
+
"conversations-hook": "bin/hook.js"
|
|
3089
3147
|
},
|
|
3090
3148
|
exports: {
|
|
3091
3149
|
".": {
|
|
@@ -3103,7 +3161,7 @@ var require_package = __commonJS((exports, module) => {
|
|
|
3103
3161
|
main: "./dist/index.js",
|
|
3104
3162
|
types: "./dist/index.d.ts",
|
|
3105
3163
|
scripts: {
|
|
3106
|
-
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",
|
|
3107
3165
|
"build:dashboard": "cd dashboard && bun install && bun run build",
|
|
3108
3166
|
test: "bun test",
|
|
3109
3167
|
dev: "bun run ./src/cli/index.tsx",
|
|
@@ -32057,9 +32115,10 @@ var init_mcp2 = __esm(() => {
|
|
|
32057
32115
|
working_dir: exports_external.string().optional().describe("Working directory context"),
|
|
32058
32116
|
repository: exports_external.string().optional().describe("Repository context"),
|
|
32059
32117
|
branch: exports_external.string().optional().describe("Branch context"),
|
|
32060
|
-
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.")
|
|
32061
32120
|
}
|
|
32062
|
-
}, 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 }) => {
|
|
32063
32122
|
const from = resolveIdentity(fromParam);
|
|
32064
32123
|
let parsedMetadata;
|
|
32065
32124
|
if (metadata) {
|
|
@@ -32081,7 +32140,8 @@ var init_mcp2 = __esm(() => {
|
|
|
32081
32140
|
working_dir,
|
|
32082
32141
|
repository,
|
|
32083
32142
|
branch,
|
|
32084
|
-
metadata: parsedMetadata
|
|
32143
|
+
metadata: parsedMetadata,
|
|
32144
|
+
blocking
|
|
32085
32145
|
});
|
|
32086
32146
|
return {
|
|
32087
32147
|
content: [{ type: "text", text: JSON.stringify(msg, null, 2) }]
|
|
@@ -32268,9 +32328,10 @@ var init_mcp2 = __esm(() => {
|
|
|
32268
32328
|
from: exports_external.string().optional().describe("Your agent ID. Falls back to CONVERSATIONS_AGENT_ID env var."),
|
|
32269
32329
|
space: exports_external.string().describe("Space name"),
|
|
32270
32330
|
content: exports_external.string().describe("Message content"),
|
|
32271
|
-
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.")
|
|
32272
32333
|
}
|
|
32273
|
-
}, async ({ from: fromParam, space, content, priority }) => {
|
|
32334
|
+
}, async ({ from: fromParam, space, content, priority, blocking }) => {
|
|
32274
32335
|
const from = resolveIdentity(fromParam);
|
|
32275
32336
|
const sp = getSpace(space);
|
|
32276
32337
|
if (!sp) {
|
|
@@ -32285,7 +32346,8 @@ var init_mcp2 = __esm(() => {
|
|
|
32285
32346
|
content,
|
|
32286
32347
|
space,
|
|
32287
32348
|
session_id: `space:${space}`,
|
|
32288
|
-
priority
|
|
32349
|
+
priority,
|
|
32350
|
+
blocking
|
|
32289
32351
|
});
|
|
32290
32352
|
return {
|
|
32291
32353
|
content: [{ type: "text", text: JSON.stringify(msg, null, 2) }]
|
|
@@ -32724,6 +32786,19 @@ var init_mcp2 = __esm(() => {
|
|
|
32724
32786
|
content: [{ type: "text", text: JSON.stringify(agents, null, 2) }]
|
|
32725
32787
|
};
|
|
32726
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
|
+
});
|
|
32727
32802
|
server.registerTool("remove_agent", {
|
|
32728
32803
|
title: "Remove Agent",
|
|
32729
32804
|
description: "Remove an agent from the presence list. Only the agent itself should remove its own presence.",
|
|
@@ -34298,7 +34373,7 @@ function App({ agent }) {
|
|
|
34298
34373
|
var import__package2 = __toESM(require_package(), 1);
|
|
34299
34374
|
var program2 = new Command;
|
|
34300
34375
|
program2.name("conversations").description("Real-time CLI messaging for AI agents").version(import__package2.default.version);
|
|
34301
|
-
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) => {
|
|
34302
34377
|
const from = resolveIdentity(opts.from).trim();
|
|
34303
34378
|
const to = typeof opts.to === "string" ? opts.to.trim() : "";
|
|
34304
34379
|
const content = typeof message === "string" ? message : "";
|
|
@@ -34333,7 +34408,8 @@ program2.command("send").description("Send a message to an agent").argument("<me
|
|
|
34333
34408
|
working_dir: opts.workingDir,
|
|
34334
34409
|
repository: opts.repository,
|
|
34335
34410
|
branch: opts.branch,
|
|
34336
|
-
metadata
|
|
34411
|
+
metadata,
|
|
34412
|
+
blocking: opts.blocking
|
|
34337
34413
|
});
|
|
34338
34414
|
if (opts.json) {
|
|
34339
34415
|
console.log(JSON.stringify(msg, null, 2));
|
|
@@ -35114,6 +35190,28 @@ agents.command("rename").description("Rename an agent in the presence list").arg
|
|
|
35114
35190
|
}
|
|
35115
35191
|
closeDb();
|
|
35116
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
|
+
});
|
|
35117
35215
|
program2.command("mcp").description("Start MCP server").action(async () => {
|
|
35118
35216
|
const { startMcpServer: startMcpServer2 } = await Promise.resolve().then(() => (init_mcp2(), exports_mcp));
|
|
35119
35217
|
await startMcpServer2();
|