@hasna/conversations 0.2.45 → 0.2.47
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 +35 -0
- package/bin/index.js +635 -84
- package/bin/mcp.js +393 -63
- package/dist/index.d.ts +1 -0
- package/dist/index.js +159 -0
- package/dist/lib/space-notifications.d.ts +19 -0
- package/dist/lib/space-notifications.test.d.ts +1 -0
- package/dist/mcp/channel.d.ts +4 -1
- package/dist/mcp/channel.test.d.ts +1 -0
- package/dist/mcp/tools/messaging.d.ts +1 -1
- package/dist/mcp/tools/spaces.d.ts +2 -0
- package/dist/types.d.ts +17 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9680,6 +9680,18 @@ function getDb() {
|
|
|
9680
9680
|
PRIMARY KEY (space, agent)
|
|
9681
9681
|
)
|
|
9682
9682
|
`);
|
|
9683
|
+
db.exec(`
|
|
9684
|
+
CREATE TABLE IF NOT EXISTS space_subscriptions (
|
|
9685
|
+
space TEXT NOT NULL REFERENCES spaces(name),
|
|
9686
|
+
agent TEXT NOT NULL,
|
|
9687
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
|
|
9688
|
+
preview_chars INTEGER NOT NULL DEFAULT 140,
|
|
9689
|
+
since_message_id INTEGER NOT NULL DEFAULT 0,
|
|
9690
|
+
PRIMARY KEY (space, agent)
|
|
9691
|
+
)
|
|
9692
|
+
`);
|
|
9693
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_space_subscriptions_agent ON space_subscriptions(agent)");
|
|
9694
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_space_subscriptions_space ON space_subscriptions(space)");
|
|
9683
9695
|
db.exec(`
|
|
9684
9696
|
CREATE TABLE IF NOT EXISTS agent_presence (
|
|
9685
9697
|
id TEXT NOT NULL,
|
|
@@ -9720,6 +9732,16 @@ function getDb() {
|
|
|
9720
9732
|
)
|
|
9721
9733
|
`);
|
|
9722
9734
|
db.exec("CREATE INDEX IF NOT EXISTS idx_reactions_message ON reactions(message_id)");
|
|
9735
|
+
db.exec(`
|
|
9736
|
+
CREATE TABLE IF NOT EXISTS space_notification_reads (
|
|
9737
|
+
agent TEXT NOT NULL,
|
|
9738
|
+
message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE,
|
|
9739
|
+
read_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
|
|
9740
|
+
PRIMARY KEY (agent, message_id)
|
|
9741
|
+
)
|
|
9742
|
+
`);
|
|
9743
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_space_notification_reads_agent ON space_notification_reads(agent)");
|
|
9744
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_space_notification_reads_message ON space_notification_reads(message_id)");
|
|
9723
9745
|
const existingTables = db.prepare("SELECT name FROM sqlite_master WHERE type='table'").all();
|
|
9724
9746
|
const tableNames = existingTables.map((t) => t.name);
|
|
9725
9747
|
if (tableNames.includes("channels") && tableNames.includes("spaces")) {
|
|
@@ -9767,6 +9789,19 @@ function getDb() {
|
|
|
9767
9789
|
if (!spaceColNames.includes("topic")) {
|
|
9768
9790
|
db.exec("ALTER TABLE spaces ADD COLUMN topic TEXT");
|
|
9769
9791
|
}
|
|
9792
|
+
const spaceSubscriptionCols = db.prepare("PRAGMA table_info(space_subscriptions)").all();
|
|
9793
|
+
const spaceSubscriptionColNames = spaceSubscriptionCols.map((c) => c.name);
|
|
9794
|
+
if (!spaceSubscriptionColNames.includes("since_message_id")) {
|
|
9795
|
+
db.exec("ALTER TABLE space_subscriptions ADD COLUMN since_message_id INTEGER NOT NULL DEFAULT 0");
|
|
9796
|
+
db.exec(`
|
|
9797
|
+
UPDATE space_subscriptions
|
|
9798
|
+
SET since_message_id = COALESCE(
|
|
9799
|
+
(SELECT MAX(m.id) FROM messages m WHERE m.space = space_subscriptions.space),
|
|
9800
|
+
0
|
|
9801
|
+
)
|
|
9802
|
+
WHERE since_message_id = 0
|
|
9803
|
+
`);
|
|
9804
|
+
}
|
|
9770
9805
|
const msgCols2 = db.prepare("PRAGMA table_info(messages)").all();
|
|
9771
9806
|
const colNames2 = msgCols2.map((c) => c.name);
|
|
9772
9807
|
if (!colNames2.includes("edited_at")) {
|
|
@@ -12568,6 +12603,122 @@ function isSpaceMember(spaceName, agent) {
|
|
|
12568
12603
|
const row = db2.prepare("SELECT 1 FROM space_members WHERE space = ? AND agent = ?").get(spaceName, agent);
|
|
12569
12604
|
return !!row;
|
|
12570
12605
|
}
|
|
12606
|
+
// src/lib/space-notifications.ts
|
|
12607
|
+
init_db();
|
|
12608
|
+
var DEFAULT_PREVIEW_CHARS = 140;
|
|
12609
|
+
function buildMessagePreview(content, maxChars = DEFAULT_PREVIEW_CHARS) {
|
|
12610
|
+
const normalized = content.replace(/[*#`~_>\-]/g, " ").replace(/\s+/g, " ").trim();
|
|
12611
|
+
if (normalized.length <= maxChars)
|
|
12612
|
+
return normalized;
|
|
12613
|
+
return normalized.slice(0, Math.max(1, maxChars)).trimEnd() + "\u2026";
|
|
12614
|
+
}
|
|
12615
|
+
function subscribeToSpaceNotifications(space, agent, opts) {
|
|
12616
|
+
const db2 = getDb();
|
|
12617
|
+
const existingSpace = db2.prepare("SELECT name FROM spaces WHERE name = ?").get(space);
|
|
12618
|
+
if (!existingSpace) {
|
|
12619
|
+
throw new Error(`Space not found: ${space}`);
|
|
12620
|
+
}
|
|
12621
|
+
const previewChars = Number.isFinite(opts?.preview_chars) && opts?.preview_chars > 0 ? Math.floor(opts.preview_chars) : DEFAULT_PREVIEW_CHARS;
|
|
12622
|
+
const currentMaxMessageId = db2.prepare("SELECT COALESCE(MAX(id), 0) AS max_id FROM messages WHERE space = ?").get(space).max_id;
|
|
12623
|
+
db2.prepare(`
|
|
12624
|
+
INSERT INTO space_subscriptions (space, agent, preview_chars, since_message_id)
|
|
12625
|
+
VALUES (?, ?, ?, ?)
|
|
12626
|
+
ON CONFLICT(space, agent) DO UPDATE SET preview_chars = excluded.preview_chars
|
|
12627
|
+
`).run(space, agent, previewChars, currentMaxMessageId);
|
|
12628
|
+
return db2.prepare("SELECT space, agent, created_at, preview_chars, since_message_id FROM space_subscriptions WHERE space = ? AND agent = ?").get(space, agent);
|
|
12629
|
+
}
|
|
12630
|
+
function unsubscribeFromSpaceNotifications(space, agent) {
|
|
12631
|
+
const db2 = getDb();
|
|
12632
|
+
const result = db2.prepare("DELETE FROM space_subscriptions WHERE space = ? AND agent = ?").run(space, agent);
|
|
12633
|
+
return result.changes > 0;
|
|
12634
|
+
}
|
|
12635
|
+
function listSpaceNotificationSubscriptions(agent) {
|
|
12636
|
+
const db2 = getDb();
|
|
12637
|
+
if (agent) {
|
|
12638
|
+
return db2.prepare("SELECT space, agent, created_at, preview_chars, since_message_id FROM space_subscriptions WHERE agent = ? ORDER BY created_at ASC, space ASC").all(agent);
|
|
12639
|
+
}
|
|
12640
|
+
return db2.prepare("SELECT space, agent, created_at, preview_chars, since_message_id FROM space_subscriptions ORDER BY agent ASC, space ASC").all();
|
|
12641
|
+
}
|
|
12642
|
+
function getSubscribedSpaces(agent) {
|
|
12643
|
+
return listSpaceNotificationSubscriptions(agent).map((row) => row.space);
|
|
12644
|
+
}
|
|
12645
|
+
function readSpaceNotifications(opts) {
|
|
12646
|
+
const db2 = getDb();
|
|
12647
|
+
const conditions = [
|
|
12648
|
+
"s.agent = ?",
|
|
12649
|
+
"m.space IS NOT NULL",
|
|
12650
|
+
"m.from_agent != ?",
|
|
12651
|
+
"m.id > s.since_message_id"
|
|
12652
|
+
];
|
|
12653
|
+
const params = [opts.agent, opts.agent];
|
|
12654
|
+
if (opts.space) {
|
|
12655
|
+
conditions.push("m.space = ?");
|
|
12656
|
+
params.push(opts.space);
|
|
12657
|
+
}
|
|
12658
|
+
if (opts.since) {
|
|
12659
|
+
conditions.push("m.created_at > ?");
|
|
12660
|
+
params.push(opts.since);
|
|
12661
|
+
}
|
|
12662
|
+
if (opts.unread_only !== false) {
|
|
12663
|
+
conditions.push("snr.message_id IS NULL");
|
|
12664
|
+
}
|
|
12665
|
+
const limit = Number.isFinite(opts.limit) && opts.limit > 0 ? Math.floor(opts.limit) : 20;
|
|
12666
|
+
const rows = db2.prepare(`
|
|
12667
|
+
SELECT
|
|
12668
|
+
m.id AS message_id,
|
|
12669
|
+
m.space,
|
|
12670
|
+
m.from_agent,
|
|
12671
|
+
m.created_at,
|
|
12672
|
+
m.priority,
|
|
12673
|
+
m.content,
|
|
12674
|
+
m.attachments,
|
|
12675
|
+
s.preview_chars,
|
|
12676
|
+
snr.message_id AS read_message_id
|
|
12677
|
+
FROM messages m
|
|
12678
|
+
INNER JOIN space_subscriptions s
|
|
12679
|
+
ON s.space = m.space
|
|
12680
|
+
LEFT JOIN space_notification_reads snr
|
|
12681
|
+
ON snr.message_id = m.id AND snr.agent = s.agent
|
|
12682
|
+
WHERE ${conditions.join(" AND ")}
|
|
12683
|
+
ORDER BY m.created_at DESC, m.id DESC
|
|
12684
|
+
LIMIT ${Math.max(1, Math.min(limit, 500))}
|
|
12685
|
+
`).all(...params);
|
|
12686
|
+
const notifications = rows.map((row) => ({
|
|
12687
|
+
message_id: row.message_id,
|
|
12688
|
+
space: row.space,
|
|
12689
|
+
from_agent: row.from_agent,
|
|
12690
|
+
created_at: row.created_at,
|
|
12691
|
+
priority: row.priority,
|
|
12692
|
+
preview: buildMessagePreview(row.content, row.preview_chars),
|
|
12693
|
+
unread: row.read_message_id == null,
|
|
12694
|
+
has_attachments: !!row.attachments && row.attachments !== "[]"
|
|
12695
|
+
}));
|
|
12696
|
+
if (opts.mark_read && notifications.length > 0) {
|
|
12697
|
+
markSpaceNotificationsRead(opts.agent, notifications.map((row) => row.message_id));
|
|
12698
|
+
for (const row of notifications)
|
|
12699
|
+
row.unread = false;
|
|
12700
|
+
}
|
|
12701
|
+
return notifications;
|
|
12702
|
+
}
|
|
12703
|
+
function markSpaceNotificationsRead(agent, messageIds) {
|
|
12704
|
+
if (messageIds.length === 0)
|
|
12705
|
+
return 0;
|
|
12706
|
+
const db2 = getDb();
|
|
12707
|
+
const insert = db2.prepare(`
|
|
12708
|
+
INSERT OR IGNORE INTO space_notification_reads (agent, message_id)
|
|
12709
|
+
VALUES (?, ?)
|
|
12710
|
+
`);
|
|
12711
|
+
let count = 0;
|
|
12712
|
+
for (const id of messageIds) {
|
|
12713
|
+
const result = insert.run(agent, id);
|
|
12714
|
+
count += result.changes;
|
|
12715
|
+
}
|
|
12716
|
+
return count;
|
|
12717
|
+
}
|
|
12718
|
+
function markAllSpaceNotificationsRead(agent, space) {
|
|
12719
|
+
const unread = readSpaceNotifications({ agent, space, unread_only: true, limit: 1e4 });
|
|
12720
|
+
return markSpaceNotificationsRead(agent, unread.map((row) => row.message_id));
|
|
12721
|
+
}
|
|
12571
12722
|
// src/lib/projects.ts
|
|
12572
12723
|
init_db();
|
|
12573
12724
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
@@ -14221,9 +14372,11 @@ export {
|
|
|
14221
14372
|
useMessages,
|
|
14222
14373
|
updateSpace,
|
|
14223
14374
|
updateProject,
|
|
14375
|
+
unsubscribeFromSpaceNotifications,
|
|
14224
14376
|
unpinMessage,
|
|
14225
14377
|
unarchiveSpace,
|
|
14226
14378
|
tryBulkAcquireLock,
|
|
14379
|
+
subscribeToSpaceNotifications,
|
|
14227
14380
|
startPolling,
|
|
14228
14381
|
setActiveModel,
|
|
14229
14382
|
sendMessage,
|
|
@@ -14236,13 +14389,17 @@ export {
|
|
|
14236
14389
|
releaseStaleAgentLocks,
|
|
14237
14390
|
releaseLock,
|
|
14238
14391
|
registerAgent,
|
|
14392
|
+
readSpaceNotifications,
|
|
14239
14393
|
readMessages,
|
|
14240
14394
|
pinMessage,
|
|
14241
14395
|
markSpaceRead,
|
|
14396
|
+
markSpaceNotificationsRead,
|
|
14242
14397
|
markSessionRead,
|
|
14243
14398
|
markRead,
|
|
14399
|
+
markAllSpaceNotificationsRead,
|
|
14244
14400
|
markAllRead,
|
|
14245
14401
|
listSpaces,
|
|
14402
|
+
listSpaceNotificationSubscriptions,
|
|
14246
14403
|
listSessions,
|
|
14247
14404
|
listProjects,
|
|
14248
14405
|
listLocksEnriched,
|
|
@@ -14257,6 +14414,7 @@ export {
|
|
|
14257
14414
|
getUnreadBlockers,
|
|
14258
14415
|
getTrendingTopics,
|
|
14259
14416
|
getThreadReplies,
|
|
14417
|
+
getSubscribedSpaces,
|
|
14260
14418
|
getSpaceTopics,
|
|
14261
14419
|
getSpaceMembers,
|
|
14262
14420
|
getSpaceDepth,
|
|
@@ -14292,6 +14450,7 @@ export {
|
|
|
14292
14450
|
clearActiveModel,
|
|
14293
14451
|
cleanExpiredLocks,
|
|
14294
14452
|
checkLock,
|
|
14453
|
+
buildMessagePreview,
|
|
14295
14454
|
buildGraph,
|
|
14296
14455
|
archiveSpace,
|
|
14297
14456
|
addReaction,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { SpaceNotification, SpaceNotificationSubscription } from "../types.js";
|
|
2
|
+
export declare function buildMessagePreview(content: string, maxChars?: number): string;
|
|
3
|
+
export declare function subscribeToSpaceNotifications(space: string, agent: string, opts?: {
|
|
4
|
+
preview_chars?: number;
|
|
5
|
+
}): SpaceNotificationSubscription;
|
|
6
|
+
export declare function unsubscribeFromSpaceNotifications(space: string, agent: string): boolean;
|
|
7
|
+
export declare function listSpaceNotificationSubscriptions(agent?: string): SpaceNotificationSubscription[];
|
|
8
|
+
export declare function getSubscribedSpaces(agent: string): string[];
|
|
9
|
+
export interface ReadSpaceNotificationsOptions {
|
|
10
|
+
agent: string;
|
|
11
|
+
space?: string;
|
|
12
|
+
unread_only?: boolean;
|
|
13
|
+
limit?: number;
|
|
14
|
+
since?: string;
|
|
15
|
+
mark_read?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export declare function readSpaceNotifications(opts: ReadSpaceNotificationsOptions): SpaceNotification[];
|
|
18
|
+
export declare function markSpaceNotificationsRead(agent: string, messageIds: number[]): number;
|
|
19
|
+
export declare function markAllSpaceNotificationsRead(agent: string, space?: string): number;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/mcp/channel.d.ts
CHANGED
|
@@ -21,4 +21,7 @@ export declare function setSessionAgent(agentId: string, claudeSessionId?: strin
|
|
|
21
21
|
export declare function setClaudeSessionId(id: string): void;
|
|
22
22
|
export declare function getSessionAgent(): string | null;
|
|
23
23
|
export declare function getClaudeSessionId(): string | null;
|
|
24
|
-
export declare function registerChannelBridge(server: McpServer
|
|
24
|
+
export declare function registerChannelBridge(server: McpServer, opts?: {
|
|
25
|
+
pollIntervalMs?: number;
|
|
26
|
+
startDelayMs?: number;
|
|
27
|
+
}): () => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Messaging tools: send_message, read_messages, read_digest, list_sessions, reply,
|
|
2
|
+
* Messaging tools: send_message, read_messages, get_message, read_digest, list_sessions, reply,
|
|
3
3
|
* mark_read, mark_unread, mark_space_read, search_messages, export_messages,
|
|
4
4
|
* delete_message, edit_message, pin_message, unpin_message, get_pinned_messages,
|
|
5
5
|
* mark_all_read, broadcast
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Space tools: create_space, list_spaces, send_to_space, read_space,
|
|
3
3
|
* join_space, leave_space, update_space, archive_space, unarchive_space,
|
|
4
|
+
* subscribe_space_notifications, unsubscribe_space_notifications,
|
|
5
|
+
* list_space_subscriptions, read_space_notifications, mark_space_notifications_read,
|
|
4
6
|
* set_space_topic, get_space_topic, summarize_space
|
|
5
7
|
*/
|
|
6
8
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
package/dist/types.d.ts
CHANGED
|
@@ -56,6 +56,23 @@ export interface SpaceMember {
|
|
|
56
56
|
agent: string;
|
|
57
57
|
joined_at: string;
|
|
58
58
|
}
|
|
59
|
+
export interface SpaceNotificationSubscription {
|
|
60
|
+
space: string;
|
|
61
|
+
agent: string;
|
|
62
|
+
created_at: string;
|
|
63
|
+
preview_chars: number;
|
|
64
|
+
since_message_id: number;
|
|
65
|
+
}
|
|
66
|
+
export interface SpaceNotification {
|
|
67
|
+
message_id: number;
|
|
68
|
+
space: string;
|
|
69
|
+
from_agent: string;
|
|
70
|
+
created_at: string;
|
|
71
|
+
priority: Priority;
|
|
72
|
+
preview: string;
|
|
73
|
+
unread: boolean;
|
|
74
|
+
has_attachments: boolean;
|
|
75
|
+
}
|
|
59
76
|
export interface SpaceInfo extends Space {
|
|
60
77
|
member_count: number;
|
|
61
78
|
message_count: number;
|