@hasna/conversations 0.2.12 → 0.2.14
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 +3 -0
- package/bin/index.js +53 -1
- package/bin/mcp.js +53 -1
- package/dist/index.js +3 -0
- package/dist/lib/messages.d.ts +4 -0
- package/package.json +1 -1
package/bin/hook.js
CHANGED
|
@@ -205,6 +205,9 @@ function getDb() {
|
|
|
205
205
|
if (!spaceColNames.includes("archived_at")) {
|
|
206
206
|
db.exec("ALTER TABLE spaces ADD COLUMN archived_at TEXT");
|
|
207
207
|
}
|
|
208
|
+
if (!spaceColNames.includes("topic")) {
|
|
209
|
+
db.exec("ALTER TABLE spaces ADD COLUMN topic TEXT");
|
|
210
|
+
}
|
|
208
211
|
const msgCols2 = db.prepare("PRAGMA table_info(messages)").all();
|
|
209
212
|
const colNames2 = msgCols2.map((c) => c.name);
|
|
210
213
|
if (!colNames2.includes("edited_at")) {
|
package/bin/index.js
CHANGED
|
@@ -2070,6 +2070,9 @@ function getDb() {
|
|
|
2070
2070
|
if (!spaceColNames.includes("archived_at")) {
|
|
2071
2071
|
db.exec("ALTER TABLE spaces ADD COLUMN archived_at TEXT");
|
|
2072
2072
|
}
|
|
2073
|
+
if (!spaceColNames.includes("topic")) {
|
|
2074
|
+
db.exec("ALTER TABLE spaces ADD COLUMN topic TEXT");
|
|
2075
|
+
}
|
|
2073
2076
|
const msgCols2 = db.prepare("PRAGMA table_info(messages)").all();
|
|
2074
2077
|
const colNames2 = msgCols2.map((c) => c.name);
|
|
2075
2078
|
if (!colNames2.includes("edited_at")) {
|
|
@@ -2803,6 +2806,14 @@ function markMentionsRead(agent, space) {
|
|
|
2803
2806
|
const result = db2.prepare("UPDATE message_mentions SET notified_at = strftime('%Y-%m-%dT%H:%M:%f', 'now') WHERE mentioned_agent = ? AND notified_at IS NULL").run(agent);
|
|
2804
2807
|
return result.changes;
|
|
2805
2808
|
}
|
|
2809
|
+
function markUnreadByIds(ids) {
|
|
2810
|
+
if (ids.length === 0)
|
|
2811
|
+
return 0;
|
|
2812
|
+
const db2 = getDb();
|
|
2813
|
+
const placeholders = ids.map(() => "?").join(",");
|
|
2814
|
+
const result = db2.prepare(`UPDATE messages SET read_at = NULL WHERE id IN (${placeholders})`).run(...ids);
|
|
2815
|
+
return result.changes;
|
|
2816
|
+
}
|
|
2806
2817
|
var init_messages = __esm(() => {
|
|
2807
2818
|
init_db();
|
|
2808
2819
|
init_webhooks();
|
|
@@ -4442,7 +4453,7 @@ var init_poll = __esm(() => {
|
|
|
4442
4453
|
var require_package = __commonJS((exports, module) => {
|
|
4443
4454
|
module.exports = {
|
|
4444
4455
|
name: "@hasna/conversations",
|
|
4445
|
-
version: "0.2.
|
|
4456
|
+
version: "0.2.14",
|
|
4446
4457
|
description: "Real-time CLI messaging for AI agents",
|
|
4447
4458
|
type: "module",
|
|
4448
4459
|
bin: {
|
|
@@ -33782,6 +33793,20 @@ var init_mcp2 = __esm(() => {
|
|
|
33782
33793
|
content: [{ type: "text", text: JSON.stringify({ marked_read: count }) }]
|
|
33783
33794
|
};
|
|
33784
33795
|
});
|
|
33796
|
+
server.registerTool("mark_unread", {
|
|
33797
|
+
description: "Re-flag a message (or messages) as unread so it re-appears in read_messages(unread_only:true). Useful for bookmarking messages to action later.",
|
|
33798
|
+
inputSchema: {
|
|
33799
|
+
message_id: exports_external.coerce.number().optional().describe("Single message ID"),
|
|
33800
|
+
ids: exports_external.array(exports_external.coerce.number()).optional().describe("Multiple message IDs")
|
|
33801
|
+
}
|
|
33802
|
+
}, async (args) => {
|
|
33803
|
+
if (!args.message_id && (!args.ids || args.ids.length === 0)) {
|
|
33804
|
+
return { content: [{ type: "text", text: "Provide message_id or ids" }], isError: true };
|
|
33805
|
+
}
|
|
33806
|
+
const ids = args.ids ?? (args.message_id ? [args.message_id] : []);
|
|
33807
|
+
const count = markUnreadByIds(ids);
|
|
33808
|
+
return { content: [{ type: "text", text: JSON.stringify({ marked_unread: count }) }] };
|
|
33809
|
+
});
|
|
33785
33810
|
server.registerTool("mark_space_read", {
|
|
33786
33811
|
description: "Mark ALL messages in a space as read without fetching them. Use this on busy spaces (200+ messages) where read_messages would overflow tokens.",
|
|
33787
33812
|
inputSchema: {
|
|
@@ -34458,6 +34483,31 @@ var init_mcp2 = __esm(() => {
|
|
|
34458
34483
|
const topics = getTrendingTopics({ hours: args.hours, project_id: args.project_id, top_n: args.top_n });
|
|
34459
34484
|
return { content: [{ type: "text", text: JSON.stringify(topics) }] };
|
|
34460
34485
|
});
|
|
34486
|
+
server.registerTool("set_space_topic", {
|
|
34487
|
+
description: "Set the current topic/status of a space. Separate from the static description \u2014 use this for live status like '\uD83D\uDD34 blocked on auth' or '\u2705 shipping v2'.",
|
|
34488
|
+
inputSchema: {
|
|
34489
|
+
space: exports_external.string().describe("Space name"),
|
|
34490
|
+
topic: exports_external.string().nullable().describe("New topic/status. Pass null to clear.")
|
|
34491
|
+
}
|
|
34492
|
+
}, async (args) => {
|
|
34493
|
+
const db2 = (await Promise.resolve().then(() => (init_db(), exports_db))).getDb();
|
|
34494
|
+
const existing = db2.prepare("SELECT name FROM spaces WHERE name = ?").get(args.space);
|
|
34495
|
+
if (!existing) {
|
|
34496
|
+
return { content: [{ type: "text", text: `Space not found: ${args.space}` }], isError: true };
|
|
34497
|
+
}
|
|
34498
|
+
db2.prepare("UPDATE spaces SET topic = ? WHERE name = ?").run(args.topic ?? null, args.space);
|
|
34499
|
+
return { content: [{ type: "text", text: args.topic ? `Topic set: ${args.topic}` : "Topic cleared" }] };
|
|
34500
|
+
});
|
|
34501
|
+
server.registerTool("get_space_topic", {
|
|
34502
|
+
description: "Get the current topic/status of a space.",
|
|
34503
|
+
inputSchema: { space: exports_external.string() }
|
|
34504
|
+
}, async (args) => {
|
|
34505
|
+
const db2 = (await Promise.resolve().then(() => (init_db(), exports_db))).getDb();
|
|
34506
|
+
const row = db2.prepare("SELECT topic FROM spaces WHERE name = ?").get(args.space);
|
|
34507
|
+
if (!row)
|
|
34508
|
+
return { content: [{ type: "text", text: `Space not found: ${args.space}` }], isError: true };
|
|
34509
|
+
return { content: [{ type: "text", text: JSON.stringify({ space: args.space, topic: row.topic }) }] };
|
|
34510
|
+
});
|
|
34461
34511
|
server.registerTool("get_session_activity", {
|
|
34462
34512
|
description: "Get activity metrics for a session: message velocity, unique agents, reply ratio, reaction count, trending status.",
|
|
34463
34513
|
inputSchema: {
|
|
@@ -34991,6 +35041,8 @@ Last message: ${rows[0]?.created_at?.slice(0, 16) ?? "?"}`);
|
|
|
34991
35041
|
get_summary: "Structured conversation summary: participants, topics, key messages, blockers. Required: session_id? or space?. Optional: limit?",
|
|
34992
35042
|
get_topics: "Extract topics from space or session. Optional: space?, session_id?, limit?",
|
|
34993
35043
|
trending_topics: "Trending topics across all messages. Optional: hours?, project_id?, top_n?",
|
|
35044
|
+
set_space_topic: "Set current topic/status of a space. Required: space, topic (pass null to clear).",
|
|
35045
|
+
get_space_topic: "Get current topic/status of a space. Required: space.",
|
|
34994
35046
|
get_session_activity: "Get activity metrics for a session: velocity, agents, reply ratio, reactions, trending. Required: session_id",
|
|
34995
35047
|
hot_sessions: "List conversations by hotness score (velocity, reactions, replies, priority, blockers). Optional: limit?, min_score?, space?, project_id?",
|
|
34996
35048
|
add_reaction: "Add emoji reaction to a message. Required: message_id, emoji. Optional: from?",
|
package/bin/mcp.js
CHANGED
|
@@ -6702,6 +6702,9 @@ function getDb() {
|
|
|
6702
6702
|
if (!spaceColNames.includes("archived_at")) {
|
|
6703
6703
|
db.exec("ALTER TABLE spaces ADD COLUMN archived_at TEXT");
|
|
6704
6704
|
}
|
|
6705
|
+
if (!spaceColNames.includes("topic")) {
|
|
6706
|
+
db.exec("ALTER TABLE spaces ADD COLUMN topic TEXT");
|
|
6707
|
+
}
|
|
6705
6708
|
const msgCols2 = db.prepare("PRAGMA table_info(messages)").all();
|
|
6706
6709
|
const colNames2 = msgCols2.map((c) => c.name);
|
|
6707
6710
|
if (!colNames2.includes("edited_at")) {
|
|
@@ -29306,6 +29309,14 @@ function markMentionsRead(agent, space) {
|
|
|
29306
29309
|
const result = db2.prepare("UPDATE message_mentions SET notified_at = strftime('%Y-%m-%dT%H:%M:%f', 'now') WHERE mentioned_agent = ? AND notified_at IS NULL").run(agent);
|
|
29307
29310
|
return result.changes;
|
|
29308
29311
|
}
|
|
29312
|
+
function markUnreadByIds(ids) {
|
|
29313
|
+
if (ids.length === 0)
|
|
29314
|
+
return 0;
|
|
29315
|
+
const db2 = getDb();
|
|
29316
|
+
const placeholders = ids.map(() => "?").join(",");
|
|
29317
|
+
const result = db2.prepare(`UPDATE messages SET read_at = NULL WHERE id IN (${placeholders})`).run(...ids);
|
|
29318
|
+
return result.changes;
|
|
29319
|
+
}
|
|
29309
29320
|
|
|
29310
29321
|
// src/lib/sessions.ts
|
|
29311
29322
|
init_db();
|
|
@@ -30932,7 +30943,7 @@ function getGraphStats() {
|
|
|
30932
30943
|
// package.json
|
|
30933
30944
|
var package_default = {
|
|
30934
30945
|
name: "@hasna/conversations",
|
|
30935
|
-
version: "0.2.
|
|
30946
|
+
version: "0.2.14",
|
|
30936
30947
|
description: "Real-time CLI messaging for AI agents",
|
|
30937
30948
|
type: "module",
|
|
30938
30949
|
bin: {
|
|
@@ -31151,6 +31162,20 @@ server.registerTool("mark_read", {
|
|
|
31151
31162
|
content: [{ type: "text", text: JSON.stringify({ marked_read: count }) }]
|
|
31152
31163
|
};
|
|
31153
31164
|
});
|
|
31165
|
+
server.registerTool("mark_unread", {
|
|
31166
|
+
description: "Re-flag a message (or messages) as unread so it re-appears in read_messages(unread_only:true). Useful for bookmarking messages to action later.",
|
|
31167
|
+
inputSchema: {
|
|
31168
|
+
message_id: exports_external.coerce.number().optional().describe("Single message ID"),
|
|
31169
|
+
ids: exports_external.array(exports_external.coerce.number()).optional().describe("Multiple message IDs")
|
|
31170
|
+
}
|
|
31171
|
+
}, async (args) => {
|
|
31172
|
+
if (!args.message_id && (!args.ids || args.ids.length === 0)) {
|
|
31173
|
+
return { content: [{ type: "text", text: "Provide message_id or ids" }], isError: true };
|
|
31174
|
+
}
|
|
31175
|
+
const ids = args.ids ?? (args.message_id ? [args.message_id] : []);
|
|
31176
|
+
const count = markUnreadByIds(ids);
|
|
31177
|
+
return { content: [{ type: "text", text: JSON.stringify({ marked_unread: count }) }] };
|
|
31178
|
+
});
|
|
31154
31179
|
server.registerTool("mark_space_read", {
|
|
31155
31180
|
description: "Mark ALL messages in a space as read without fetching them. Use this on busy spaces (200+ messages) where read_messages would overflow tokens.",
|
|
31156
31181
|
inputSchema: {
|
|
@@ -31827,6 +31852,31 @@ server.registerTool("trending_topics", {
|
|
|
31827
31852
|
const topics = getTrendingTopics({ hours: args.hours, project_id: args.project_id, top_n: args.top_n });
|
|
31828
31853
|
return { content: [{ type: "text", text: JSON.stringify(topics) }] };
|
|
31829
31854
|
});
|
|
31855
|
+
server.registerTool("set_space_topic", {
|
|
31856
|
+
description: "Set the current topic/status of a space. Separate from the static description \u2014 use this for live status like '\uD83D\uDD34 blocked on auth' or '\u2705 shipping v2'.",
|
|
31857
|
+
inputSchema: {
|
|
31858
|
+
space: exports_external.string().describe("Space name"),
|
|
31859
|
+
topic: exports_external.string().nullable().describe("New topic/status. Pass null to clear.")
|
|
31860
|
+
}
|
|
31861
|
+
}, async (args) => {
|
|
31862
|
+
const db2 = (await Promise.resolve().then(() => (init_db(), exports_db))).getDb();
|
|
31863
|
+
const existing = db2.prepare("SELECT name FROM spaces WHERE name = ?").get(args.space);
|
|
31864
|
+
if (!existing) {
|
|
31865
|
+
return { content: [{ type: "text", text: `Space not found: ${args.space}` }], isError: true };
|
|
31866
|
+
}
|
|
31867
|
+
db2.prepare("UPDATE spaces SET topic = ? WHERE name = ?").run(args.topic ?? null, args.space);
|
|
31868
|
+
return { content: [{ type: "text", text: args.topic ? `Topic set: ${args.topic}` : "Topic cleared" }] };
|
|
31869
|
+
});
|
|
31870
|
+
server.registerTool("get_space_topic", {
|
|
31871
|
+
description: "Get the current topic/status of a space.",
|
|
31872
|
+
inputSchema: { space: exports_external.string() }
|
|
31873
|
+
}, async (args) => {
|
|
31874
|
+
const db2 = (await Promise.resolve().then(() => (init_db(), exports_db))).getDb();
|
|
31875
|
+
const row = db2.prepare("SELECT topic FROM spaces WHERE name = ?").get(args.space);
|
|
31876
|
+
if (!row)
|
|
31877
|
+
return { content: [{ type: "text", text: `Space not found: ${args.space}` }], isError: true };
|
|
31878
|
+
return { content: [{ type: "text", text: JSON.stringify({ space: args.space, topic: row.topic }) }] };
|
|
31879
|
+
});
|
|
31830
31880
|
server.registerTool("get_session_activity", {
|
|
31831
31881
|
description: "Get activity metrics for a session: message velocity, unique agents, reply ratio, reaction count, trending status.",
|
|
31832
31882
|
inputSchema: {
|
|
@@ -32360,6 +32410,8 @@ server.registerTool("describe_tools", {
|
|
|
32360
32410
|
get_summary: "Structured conversation summary: participants, topics, key messages, blockers. Required: session_id? or space?. Optional: limit?",
|
|
32361
32411
|
get_topics: "Extract topics from space or session. Optional: space?, session_id?, limit?",
|
|
32362
32412
|
trending_topics: "Trending topics across all messages. Optional: hours?, project_id?, top_n?",
|
|
32413
|
+
set_space_topic: "Set current topic/status of a space. Required: space, topic (pass null to clear).",
|
|
32414
|
+
get_space_topic: "Get current topic/status of a space. Required: space.",
|
|
32363
32415
|
get_session_activity: "Get activity metrics for a session: velocity, agents, reply ratio, reactions, trending. Required: session_id",
|
|
32364
32416
|
hot_sessions: "List conversations by hotness score (velocity, reactions, replies, priority, blockers). Optional: limit?, min_score?, space?, project_id?",
|
|
32365
32417
|
add_reaction: "Add emoji reaction to a message. Required: message_id, emoji. Optional: from?",
|
package/dist/index.js
CHANGED
|
@@ -229,6 +229,9 @@ function getDb() {
|
|
|
229
229
|
if (!spaceColNames.includes("archived_at")) {
|
|
230
230
|
db.exec("ALTER TABLE spaces ADD COLUMN archived_at TEXT");
|
|
231
231
|
}
|
|
232
|
+
if (!spaceColNames.includes("topic")) {
|
|
233
|
+
db.exec("ALTER TABLE spaces ADD COLUMN topic TEXT");
|
|
234
|
+
}
|
|
232
235
|
const msgCols2 = db.prepare("PRAGMA table_info(messages)").all();
|
|
233
236
|
const colNames2 = msgCols2.map((c) => c.name);
|
|
234
237
|
if (!colNames2.includes("edited_at")) {
|
package/dist/lib/messages.d.ts
CHANGED
|
@@ -88,3 +88,7 @@ export declare function getMessagesForAgent(agent: string, opts?: {
|
|
|
88
88
|
}>;
|
|
89
89
|
/** Mark mentions as notified (agent has seen them). */
|
|
90
90
|
export declare function markMentionsRead(agent: string, space?: string): number;
|
|
91
|
+
/** Mark a specific message as unread (resets read_at to null). */
|
|
92
|
+
export declare function markUnread(messageId: number): number;
|
|
93
|
+
/** Mark multiple messages as unread. */
|
|
94
|
+
export declare function markUnreadByIds(ids: number[]): number;
|