@hasna/conversations 0.2.6 → 0.2.8
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/index.js +42 -16
- package/bin/mcp.js +42 -16
- package/dist/index.js +19 -2
- package/dist/types.d.ts +4 -0
- package/package.json +1 -1
package/bin/index.js
CHANGED
|
@@ -2395,9 +2395,10 @@ function readMessages(opts = {}) {
|
|
|
2395
2395
|
conditions.push(`id IN (SELECT message_id FROM message_mentions WHERE mentioned_agent = ?)`);
|
|
2396
2396
|
params.push(opts.mentions_only.toLowerCase());
|
|
2397
2397
|
}
|
|
2398
|
+
const isLatest = opts.latest && opts.latest > 0;
|
|
2398
2399
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2399
|
-
const resolvedLimit = Number.isFinite(opts.limit) && opts.limit > 0 ? Math.floor(opts.limit) : 20;
|
|
2400
|
-
const order = opts.order?.toLowerCase() === "desc" ? "DESC" : "ASC";
|
|
2400
|
+
const resolvedLimit = isLatest ? Math.floor(opts.latest) : Number.isFinite(opts.limit) && opts.limit > 0 ? Math.floor(opts.limit) : 20;
|
|
2401
|
+
const order = isLatest ? "DESC" : opts.order?.toLowerCase() === "desc" ? "DESC" : "ASC";
|
|
2401
2402
|
const rows = db2.prepare(`SELECT * FROM messages ${where} ORDER BY created_at ${order}, id ${order} LIMIT ${resolvedLimit}`).all(...params);
|
|
2402
2403
|
let messages = rows.map(parseMessage);
|
|
2403
2404
|
if (opts.include_reply_counts && messages.length > 0) {
|
|
@@ -2646,6 +2647,14 @@ function searchMessages(opts) {
|
|
|
2646
2647
|
extraWhere += " AND m.to_agent = ?";
|
|
2647
2648
|
ftsParams.push(opts.to);
|
|
2648
2649
|
}
|
|
2650
|
+
if (opts.since) {
|
|
2651
|
+
extraWhere += " AND m.created_at >= ?";
|
|
2652
|
+
ftsParams.push(opts.since);
|
|
2653
|
+
}
|
|
2654
|
+
if (opts.until) {
|
|
2655
|
+
extraWhere += " AND m.created_at <= ?";
|
|
2656
|
+
ftsParams.push(opts.until);
|
|
2657
|
+
}
|
|
2649
2658
|
const orderClause = sortByRelevance ? "ORDER BY rank" : "ORDER BY m.created_at DESC, m.id DESC";
|
|
2650
2659
|
const rows2 = db2.prepare(`SELECT m.*, rank,
|
|
2651
2660
|
snippet(messages_fts, 0, '**', '**', '...', 20) as snippet
|
|
@@ -2678,6 +2687,14 @@ function searchMessages(opts) {
|
|
|
2678
2687
|
conditions.push("to_agent = ?");
|
|
2679
2688
|
params.push(opts.to);
|
|
2680
2689
|
}
|
|
2690
|
+
if (opts.since) {
|
|
2691
|
+
conditions.push("created_at >= ?");
|
|
2692
|
+
params.push(opts.since);
|
|
2693
|
+
}
|
|
2694
|
+
if (opts.until) {
|
|
2695
|
+
conditions.push("created_at <= ?");
|
|
2696
|
+
params.push(opts.until);
|
|
2697
|
+
}
|
|
2681
2698
|
const where = `WHERE ${conditions.join(" AND ")}`;
|
|
2682
2699
|
const rows = db2.prepare(`SELECT * FROM messages ${where} ORDER BY created_at DESC, id DESC LIMIT ${limit}`).all(...params);
|
|
2683
2700
|
return rows.map((row) => {
|
|
@@ -4424,7 +4441,7 @@ var init_poll = __esm(() => {
|
|
|
4424
4441
|
var require_package = __commonJS((exports, module) => {
|
|
4425
4442
|
module.exports = {
|
|
4426
4443
|
name: "@hasna/conversations",
|
|
4427
|
-
version: "0.2.
|
|
4444
|
+
version: "0.2.8",
|
|
4428
4445
|
description: "Real-time CLI messaging for AI agents",
|
|
4429
4446
|
type: "module",
|
|
4430
4447
|
bin: {
|
|
@@ -33680,7 +33697,8 @@ var init_mcp2 = __esm(() => {
|
|
|
33680
33697
|
max_content_length: exports_external.coerce.number().optional().describe("Truncate each message content to N chars (adds truncated:true flag)"),
|
|
33681
33698
|
threads_only: exports_external.coerce.boolean().optional().describe("Only return root messages (reply_to IS NULL) \u2014 hides thread replies"),
|
|
33682
33699
|
include_reply_counts: exports_external.coerce.boolean().optional().describe("Include reply_count on each message (adds one extra query)"),
|
|
33683
|
-
mentions_only: exports_external.string().optional().describe("Only return messages that @mention this agent")
|
|
33700
|
+
mentions_only: exports_external.string().optional().describe("Only return messages that @mention this agent"),
|
|
33701
|
+
latest: exports_external.coerce.number().optional().describe("Return the N most recent unread messages, newest first. Shorthand for order:desc + limit:N.")
|
|
33684
33702
|
}
|
|
33685
33703
|
}, async (args) => {
|
|
33686
33704
|
const agent = resolveIdentity(args.from);
|
|
@@ -33763,19 +33781,26 @@ var init_mcp2 = __esm(() => {
|
|
|
33763
33781
|
};
|
|
33764
33782
|
});
|
|
33765
33783
|
server.registerTool("search_messages", {
|
|
33766
|
-
description: "Full-text search across messages.",
|
|
33784
|
+
description: "Full-text search across messages. Uses FTS5 with BM25 ranking if available, falls back to LIKE. Returns messages with snippet and relevance_score.",
|
|
33767
33785
|
inputSchema: {
|
|
33768
|
-
query: exports_external.string(),
|
|
33769
|
-
space: exports_external.string().optional(),
|
|
33770
|
-
from: exports_external.string().optional(),
|
|
33771
|
-
to: exports_external.string().optional(),
|
|
33772
|
-
|
|
33786
|
+
query: exports_external.string().describe(`Search query. Wrap in quotes for exact phrase: '"BUG-005"'`),
|
|
33787
|
+
space: exports_external.string().optional().describe("Limit to a specific space"),
|
|
33788
|
+
from: exports_external.string().optional().describe("Filter by sender"),
|
|
33789
|
+
to: exports_external.string().optional().describe("Filter by recipient"),
|
|
33790
|
+
since: exports_external.string().optional().describe("ISO 8601 date \u2014 only messages after this"),
|
|
33791
|
+
until: exports_external.string().optional().describe("ISO 8601 date \u2014 only messages before this"),
|
|
33792
|
+
sort: exports_external.enum(["relevance", "recent"]).optional().describe("Sort order (default: relevance)"),
|
|
33793
|
+
limit: exports_external.coerce.number().optional().describe("Max results (default: 20)")
|
|
33773
33794
|
}
|
|
33774
33795
|
}, async (args) => {
|
|
33775
|
-
const { query, space, from, to, limit } = args;
|
|
33776
|
-
const
|
|
33796
|
+
const { query, space, from, to, since, until, sort, limit } = args;
|
|
33797
|
+
const results = searchMessages({ query, space, from, to, since, until, sort, limit });
|
|
33777
33798
|
return {
|
|
33778
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
33799
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
33800
|
+
results,
|
|
33801
|
+
count: results.length,
|
|
33802
|
+
query
|
|
33803
|
+
}) }]
|
|
33779
33804
|
};
|
|
33780
33805
|
});
|
|
33781
33806
|
server.registerTool("export_messages", {
|
|
@@ -33930,11 +33955,12 @@ var init_mcp2 = __esm(() => {
|
|
|
33930
33955
|
mark_read: exports_external.coerce.boolean().optional(),
|
|
33931
33956
|
max_content_length: exports_external.coerce.number().optional().describe("Truncate each message content to N chars (adds truncated:true flag)"),
|
|
33932
33957
|
threads_only: exports_external.coerce.boolean().optional().describe("Only return root messages (hides thread replies)"),
|
|
33933
|
-
include_reply_counts: exports_external.coerce.boolean().optional().describe("Include reply_count on each message")
|
|
33958
|
+
include_reply_counts: exports_external.coerce.boolean().optional().describe("Include reply_count on each message"),
|
|
33959
|
+
latest: exports_external.coerce.number().optional().describe("Return the N most recent messages, newest first")
|
|
33934
33960
|
}
|
|
33935
33961
|
}, async (args) => {
|
|
33936
|
-
const { space, since, limit, mark_read, max_content_length, threads_only, include_reply_counts } = args;
|
|
33937
|
-
const messages = readMessages({ space, since, limit, max_content_length, threads_only, include_reply_counts });
|
|
33962
|
+
const { space, since, limit, mark_read, max_content_length, threads_only, include_reply_counts, latest } = args;
|
|
33963
|
+
const messages = readMessages({ space, since, limit, max_content_length, threads_only, include_reply_counts, latest });
|
|
33938
33964
|
if (mark_read !== false && messages.length > 0) {
|
|
33939
33965
|
markReadByIds(messages.map((m) => m.id));
|
|
33940
33966
|
}
|
package/bin/mcp.js
CHANGED
|
@@ -28904,9 +28904,10 @@ function readMessages(opts = {}) {
|
|
|
28904
28904
|
conditions.push(`id IN (SELECT message_id FROM message_mentions WHERE mentioned_agent = ?)`);
|
|
28905
28905
|
params.push(opts.mentions_only.toLowerCase());
|
|
28906
28906
|
}
|
|
28907
|
+
const isLatest = opts.latest && opts.latest > 0;
|
|
28907
28908
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
28908
|
-
const resolvedLimit = Number.isFinite(opts.limit) && opts.limit > 0 ? Math.floor(opts.limit) : 20;
|
|
28909
|
-
const order = opts.order?.toLowerCase() === "desc" ? "DESC" : "ASC";
|
|
28909
|
+
const resolvedLimit = isLatest ? Math.floor(opts.latest) : Number.isFinite(opts.limit) && opts.limit > 0 ? Math.floor(opts.limit) : 20;
|
|
28910
|
+
const order = isLatest ? "DESC" : opts.order?.toLowerCase() === "desc" ? "DESC" : "ASC";
|
|
28910
28911
|
const rows = db2.prepare(`SELECT * FROM messages ${where} ORDER BY created_at ${order}, id ${order} LIMIT ${resolvedLimit}`).all(...params);
|
|
28911
28912
|
let messages = rows.map(parseMessage);
|
|
28912
28913
|
if (opts.include_reply_counts && messages.length > 0) {
|
|
@@ -29143,6 +29144,14 @@ function searchMessages(opts) {
|
|
|
29143
29144
|
extraWhere += " AND m.to_agent = ?";
|
|
29144
29145
|
ftsParams.push(opts.to);
|
|
29145
29146
|
}
|
|
29147
|
+
if (opts.since) {
|
|
29148
|
+
extraWhere += " AND m.created_at >= ?";
|
|
29149
|
+
ftsParams.push(opts.since);
|
|
29150
|
+
}
|
|
29151
|
+
if (opts.until) {
|
|
29152
|
+
extraWhere += " AND m.created_at <= ?";
|
|
29153
|
+
ftsParams.push(opts.until);
|
|
29154
|
+
}
|
|
29146
29155
|
const orderClause = sortByRelevance ? "ORDER BY rank" : "ORDER BY m.created_at DESC, m.id DESC";
|
|
29147
29156
|
const rows2 = db2.prepare(`SELECT m.*, rank,
|
|
29148
29157
|
snippet(messages_fts, 0, '**', '**', '...', 20) as snippet
|
|
@@ -29175,6 +29184,14 @@ function searchMessages(opts) {
|
|
|
29175
29184
|
conditions.push("to_agent = ?");
|
|
29176
29185
|
params.push(opts.to);
|
|
29177
29186
|
}
|
|
29187
|
+
if (opts.since) {
|
|
29188
|
+
conditions.push("created_at >= ?");
|
|
29189
|
+
params.push(opts.since);
|
|
29190
|
+
}
|
|
29191
|
+
if (opts.until) {
|
|
29192
|
+
conditions.push("created_at <= ?");
|
|
29193
|
+
params.push(opts.until);
|
|
29194
|
+
}
|
|
29178
29195
|
const where = `WHERE ${conditions.join(" AND ")}`;
|
|
29179
29196
|
const rows = db2.prepare(`SELECT * FROM messages ${where} ORDER BY created_at DESC, id DESC LIMIT ${limit}`).all(...params);
|
|
29180
29197
|
return rows.map((row) => {
|
|
@@ -30908,7 +30925,7 @@ function getGraphStats() {
|
|
|
30908
30925
|
// package.json
|
|
30909
30926
|
var package_default = {
|
|
30910
30927
|
name: "@hasna/conversations",
|
|
30911
|
-
version: "0.2.
|
|
30928
|
+
version: "0.2.8",
|
|
30912
30929
|
description: "Real-time CLI messaging for AI agents",
|
|
30913
30930
|
type: "module",
|
|
30914
30931
|
bin: {
|
|
@@ -31043,7 +31060,8 @@ server.registerTool("read_messages", {
|
|
|
31043
31060
|
max_content_length: exports_external.coerce.number().optional().describe("Truncate each message content to N chars (adds truncated:true flag)"),
|
|
31044
31061
|
threads_only: exports_external.coerce.boolean().optional().describe("Only return root messages (reply_to IS NULL) \u2014 hides thread replies"),
|
|
31045
31062
|
include_reply_counts: exports_external.coerce.boolean().optional().describe("Include reply_count on each message (adds one extra query)"),
|
|
31046
|
-
mentions_only: exports_external.string().optional().describe("Only return messages that @mention this agent")
|
|
31063
|
+
mentions_only: exports_external.string().optional().describe("Only return messages that @mention this agent"),
|
|
31064
|
+
latest: exports_external.coerce.number().optional().describe("Return the N most recent unread messages, newest first. Shorthand for order:desc + limit:N.")
|
|
31047
31065
|
}
|
|
31048
31066
|
}, async (args) => {
|
|
31049
31067
|
const agent = resolveIdentity(args.from);
|
|
@@ -31126,19 +31144,26 @@ server.registerTool("mark_read", {
|
|
|
31126
31144
|
};
|
|
31127
31145
|
});
|
|
31128
31146
|
server.registerTool("search_messages", {
|
|
31129
|
-
description: "Full-text search across messages.",
|
|
31147
|
+
description: "Full-text search across messages. Uses FTS5 with BM25 ranking if available, falls back to LIKE. Returns messages with snippet and relevance_score.",
|
|
31130
31148
|
inputSchema: {
|
|
31131
|
-
query: exports_external.string(),
|
|
31132
|
-
space: exports_external.string().optional(),
|
|
31133
|
-
from: exports_external.string().optional(),
|
|
31134
|
-
to: exports_external.string().optional(),
|
|
31135
|
-
|
|
31149
|
+
query: exports_external.string().describe(`Search query. Wrap in quotes for exact phrase: '"BUG-005"'`),
|
|
31150
|
+
space: exports_external.string().optional().describe("Limit to a specific space"),
|
|
31151
|
+
from: exports_external.string().optional().describe("Filter by sender"),
|
|
31152
|
+
to: exports_external.string().optional().describe("Filter by recipient"),
|
|
31153
|
+
since: exports_external.string().optional().describe("ISO 8601 date \u2014 only messages after this"),
|
|
31154
|
+
until: exports_external.string().optional().describe("ISO 8601 date \u2014 only messages before this"),
|
|
31155
|
+
sort: exports_external.enum(["relevance", "recent"]).optional().describe("Sort order (default: relevance)"),
|
|
31156
|
+
limit: exports_external.coerce.number().optional().describe("Max results (default: 20)")
|
|
31136
31157
|
}
|
|
31137
31158
|
}, async (args) => {
|
|
31138
|
-
const { query, space, from, to, limit } = args;
|
|
31139
|
-
const
|
|
31159
|
+
const { query, space, from, to, since, until, sort, limit } = args;
|
|
31160
|
+
const results = searchMessages({ query, space, from, to, since, until, sort, limit });
|
|
31140
31161
|
return {
|
|
31141
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
31162
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
31163
|
+
results,
|
|
31164
|
+
count: results.length,
|
|
31165
|
+
query
|
|
31166
|
+
}) }]
|
|
31142
31167
|
};
|
|
31143
31168
|
});
|
|
31144
31169
|
server.registerTool("export_messages", {
|
|
@@ -31293,11 +31318,12 @@ server.registerTool("read_space", {
|
|
|
31293
31318
|
mark_read: exports_external.coerce.boolean().optional(),
|
|
31294
31319
|
max_content_length: exports_external.coerce.number().optional().describe("Truncate each message content to N chars (adds truncated:true flag)"),
|
|
31295
31320
|
threads_only: exports_external.coerce.boolean().optional().describe("Only return root messages (hides thread replies)"),
|
|
31296
|
-
include_reply_counts: exports_external.coerce.boolean().optional().describe("Include reply_count on each message")
|
|
31321
|
+
include_reply_counts: exports_external.coerce.boolean().optional().describe("Include reply_count on each message"),
|
|
31322
|
+
latest: exports_external.coerce.number().optional().describe("Return the N most recent messages, newest first")
|
|
31297
31323
|
}
|
|
31298
31324
|
}, async (args) => {
|
|
31299
|
-
const { space, since, limit, mark_read, max_content_length, threads_only, include_reply_counts } = args;
|
|
31300
|
-
const messages = readMessages({ space, since, limit, max_content_length, threads_only, include_reply_counts });
|
|
31325
|
+
const { space, since, limit, mark_read, max_content_length, threads_only, include_reply_counts, latest } = args;
|
|
31326
|
+
const messages = readMessages({ space, since, limit, max_content_length, threads_only, include_reply_counts, latest });
|
|
31301
31327
|
if (mark_read !== false && messages.length > 0) {
|
|
31302
31328
|
markReadByIds(messages.map((m) => m.id));
|
|
31303
31329
|
}
|
package/dist/index.js
CHANGED
|
@@ -2369,9 +2369,10 @@ function readMessages(opts = {}) {
|
|
|
2369
2369
|
conditions.push(`id IN (SELECT message_id FROM message_mentions WHERE mentioned_agent = ?)`);
|
|
2370
2370
|
params.push(opts.mentions_only.toLowerCase());
|
|
2371
2371
|
}
|
|
2372
|
+
const isLatest = opts.latest && opts.latest > 0;
|
|
2372
2373
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2373
|
-
const resolvedLimit = Number.isFinite(opts.limit) && opts.limit > 0 ? Math.floor(opts.limit) : 20;
|
|
2374
|
-
const order = opts.order?.toLowerCase() === "desc" ? "DESC" : "ASC";
|
|
2374
|
+
const resolvedLimit = isLatest ? Math.floor(opts.latest) : Number.isFinite(opts.limit) && opts.limit > 0 ? Math.floor(opts.limit) : 20;
|
|
2375
|
+
const order = isLatest ? "DESC" : opts.order?.toLowerCase() === "desc" ? "DESC" : "ASC";
|
|
2375
2376
|
const rows = db2.prepare(`SELECT * FROM messages ${where} ORDER BY created_at ${order}, id ${order} LIMIT ${resolvedLimit}`).all(...params);
|
|
2376
2377
|
let messages = rows.map(parseMessage);
|
|
2377
2378
|
if (opts.include_reply_counts && messages.length > 0) {
|
|
@@ -2568,6 +2569,14 @@ function searchMessages(opts) {
|
|
|
2568
2569
|
extraWhere += " AND m.to_agent = ?";
|
|
2569
2570
|
ftsParams.push(opts.to);
|
|
2570
2571
|
}
|
|
2572
|
+
if (opts.since) {
|
|
2573
|
+
extraWhere += " AND m.created_at >= ?";
|
|
2574
|
+
ftsParams.push(opts.since);
|
|
2575
|
+
}
|
|
2576
|
+
if (opts.until) {
|
|
2577
|
+
extraWhere += " AND m.created_at <= ?";
|
|
2578
|
+
ftsParams.push(opts.until);
|
|
2579
|
+
}
|
|
2571
2580
|
const orderClause = sortByRelevance ? "ORDER BY rank" : "ORDER BY m.created_at DESC, m.id DESC";
|
|
2572
2581
|
const rows2 = db2.prepare(`SELECT m.*, rank,
|
|
2573
2582
|
snippet(messages_fts, 0, '**', '**', '...', 20) as snippet
|
|
@@ -2600,6 +2609,14 @@ function searchMessages(opts) {
|
|
|
2600
2609
|
conditions.push("to_agent = ?");
|
|
2601
2610
|
params.push(opts.to);
|
|
2602
2611
|
}
|
|
2612
|
+
if (opts.since) {
|
|
2613
|
+
conditions.push("created_at >= ?");
|
|
2614
|
+
params.push(opts.since);
|
|
2615
|
+
}
|
|
2616
|
+
if (opts.until) {
|
|
2617
|
+
conditions.push("created_at <= ?");
|
|
2618
|
+
params.push(opts.until);
|
|
2619
|
+
}
|
|
2603
2620
|
const where = `WHERE ${conditions.join(" AND ")}`;
|
|
2604
2621
|
const rows = db2.prepare(`SELECT * FROM messages ${where} ORDER BY created_at DESC, id DESC LIMIT ${limit}`).all(...params);
|
|
2605
2622
|
return rows.map((row) => {
|
package/dist/types.d.ts
CHANGED
|
@@ -112,14 +112,18 @@ export interface ReadMessagesOptions {
|
|
|
112
112
|
threads_only?: boolean;
|
|
113
113
|
include_reply_counts?: boolean;
|
|
114
114
|
mentions_only?: string;
|
|
115
|
+
latest?: number;
|
|
115
116
|
}
|
|
116
117
|
export interface SearchMessagesOptions {
|
|
117
118
|
query: string;
|
|
118
119
|
space?: string;
|
|
119
120
|
from?: string;
|
|
120
121
|
to?: string;
|
|
122
|
+
since?: string;
|
|
123
|
+
until?: string;
|
|
121
124
|
limit?: number;
|
|
122
125
|
sort?: "relevance" | "recent";
|
|
126
|
+
snippet_length?: number;
|
|
123
127
|
}
|
|
124
128
|
export interface SearchResult extends Message {
|
|
125
129
|
snippet: string | null;
|