@hasna/conversations 0.1.29 → 0.1.31
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 +19 -0
- package/bin/index.js +33 -7
- package/bin/mcp.js +33 -7
- package/dist/index.d.ts +2 -0
- package/dist/index.js +106 -4
- package/dist/lib/locks.d.ts +20 -0
- package/dist/lib/locks.test.d.ts +1 -0
- package/dist/types.d.ts +3 -0
- package/package.json +1 -1
package/bin/hook.js
CHANGED
|
@@ -60,6 +60,7 @@ function getDb() {
|
|
|
60
60
|
from_agent TEXT NOT NULL,
|
|
61
61
|
to_agent TEXT NOT NULL,
|
|
62
62
|
space TEXT,
|
|
63
|
+
project_id TEXT,
|
|
63
64
|
content TEXT NOT NULL,
|
|
64
65
|
priority TEXT NOT NULL DEFAULT 'normal',
|
|
65
66
|
working_dir TEXT,
|
|
@@ -125,6 +126,20 @@ function getDb() {
|
|
|
125
126
|
metadata TEXT
|
|
126
127
|
)
|
|
127
128
|
`);
|
|
129
|
+
db.exec(`
|
|
130
|
+
CREATE TABLE IF NOT EXISTS resource_locks (
|
|
131
|
+
resource_type TEXT NOT NULL,
|
|
132
|
+
resource_id TEXT NOT NULL,
|
|
133
|
+
agent_id TEXT NOT NULL,
|
|
134
|
+
lock_type TEXT NOT NULL DEFAULT 'advisory',
|
|
135
|
+
locked_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
|
|
136
|
+
expires_at TEXT NOT NULL,
|
|
137
|
+
UNIQUE(resource_type, resource_id, lock_type)
|
|
138
|
+
)
|
|
139
|
+
`);
|
|
140
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_locks_resource ON resource_locks(resource_type, resource_id)");
|
|
141
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_locks_agent ON resource_locks(agent_id)");
|
|
142
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_locks_expires ON resource_locks(expires_at)");
|
|
128
143
|
db.exec(`
|
|
129
144
|
CREATE TABLE IF NOT EXISTS reactions (
|
|
130
145
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -200,6 +215,10 @@ function getDb() {
|
|
|
200
215
|
db.exec("ALTER TABLE messages ADD COLUMN reply_to INTEGER REFERENCES messages(id)");
|
|
201
216
|
db.exec("CREATE INDEX IF NOT EXISTS idx_messages_reply_to ON messages(reply_to)");
|
|
202
217
|
}
|
|
218
|
+
if (!colNames2.includes("project_id")) {
|
|
219
|
+
db.exec("ALTER TABLE messages ADD COLUMN project_id TEXT");
|
|
220
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_messages_project ON messages(project_id)");
|
|
221
|
+
}
|
|
203
222
|
const presenceCols = db.prepare("PRAGMA table_info(agent_presence)").all();
|
|
204
223
|
const presenceColNames = presenceCols.map((c) => c.name);
|
|
205
224
|
if (!presenceColNames.includes("id")) {
|
package/bin/index.js
CHANGED
|
@@ -1914,6 +1914,7 @@ function getDb() {
|
|
|
1914
1914
|
from_agent TEXT NOT NULL,
|
|
1915
1915
|
to_agent TEXT NOT NULL,
|
|
1916
1916
|
space TEXT,
|
|
1917
|
+
project_id TEXT,
|
|
1917
1918
|
content TEXT NOT NULL,
|
|
1918
1919
|
priority TEXT NOT NULL DEFAULT 'normal',
|
|
1919
1920
|
working_dir TEXT,
|
|
@@ -1979,6 +1980,20 @@ function getDb() {
|
|
|
1979
1980
|
metadata TEXT
|
|
1980
1981
|
)
|
|
1981
1982
|
`);
|
|
1983
|
+
db.exec(`
|
|
1984
|
+
CREATE TABLE IF NOT EXISTS resource_locks (
|
|
1985
|
+
resource_type TEXT NOT NULL,
|
|
1986
|
+
resource_id TEXT NOT NULL,
|
|
1987
|
+
agent_id TEXT NOT NULL,
|
|
1988
|
+
lock_type TEXT NOT NULL DEFAULT 'advisory',
|
|
1989
|
+
locked_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
|
|
1990
|
+
expires_at TEXT NOT NULL,
|
|
1991
|
+
UNIQUE(resource_type, resource_id, lock_type)
|
|
1992
|
+
)
|
|
1993
|
+
`);
|
|
1994
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_locks_resource ON resource_locks(resource_type, resource_id)");
|
|
1995
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_locks_agent ON resource_locks(agent_id)");
|
|
1996
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_locks_expires ON resource_locks(expires_at)");
|
|
1982
1997
|
db.exec(`
|
|
1983
1998
|
CREATE TABLE IF NOT EXISTS reactions (
|
|
1984
1999
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -2054,6 +2069,10 @@ function getDb() {
|
|
|
2054
2069
|
db.exec("ALTER TABLE messages ADD COLUMN reply_to INTEGER REFERENCES messages(id)");
|
|
2055
2070
|
db.exec("CREATE INDEX IF NOT EXISTS idx_messages_reply_to ON messages(reply_to)");
|
|
2056
2071
|
}
|
|
2072
|
+
if (!colNames2.includes("project_id")) {
|
|
2073
|
+
db.exec("ALTER TABLE messages ADD COLUMN project_id TEXT");
|
|
2074
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_messages_project ON messages(project_id)");
|
|
2075
|
+
}
|
|
2057
2076
|
const presenceCols = db.prepare("PRAGMA table_info(agent_presence)").all();
|
|
2058
2077
|
const presenceColNames = presenceCols.map((c) => c.name);
|
|
2059
2078
|
if (!presenceColNames.includes("id")) {
|
|
@@ -2265,11 +2284,11 @@ function sendMessage(opts) {
|
|
|
2265
2284
|
const blocking = opts.blocking ? 1 : 0;
|
|
2266
2285
|
const replyTo = opts.reply_to || null;
|
|
2267
2286
|
const stmt = db2.prepare(`
|
|
2268
|
-
INSERT INTO messages (session_id, from_agent, to_agent, space, content, priority, working_dir, repository, branch, metadata, blocking, reply_to)
|
|
2269
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
2287
|
+
INSERT INTO messages (session_id, from_agent, to_agent, space, project_id, content, priority, working_dir, repository, branch, metadata, blocking, reply_to)
|
|
2288
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
2270
2289
|
RETURNING *
|
|
2271
2290
|
`);
|
|
2272
|
-
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, replyTo);
|
|
2291
|
+
const row = stmt.get(sessionId, opts.from, opts.to, opts.space || null, opts.project_id || null, opts.content, normalizedPriority, opts.working_dir || null, opts.repository || null, opts.branch || null, metadata, blocking, replyTo);
|
|
2273
2292
|
const message = parseMessage(row);
|
|
2274
2293
|
if (opts.attachments && opts.attachments.length > 0) {
|
|
2275
2294
|
const attachmentsDir = join3(getAttachmentsDir(), String(message.id));
|
|
@@ -2313,6 +2332,10 @@ function readMessages(opts = {}) {
|
|
|
2313
2332
|
conditions.push("space = ?");
|
|
2314
2333
|
params.push(opts.space);
|
|
2315
2334
|
}
|
|
2335
|
+
if (opts.project_id) {
|
|
2336
|
+
conditions.push("project_id = ?");
|
|
2337
|
+
params.push(opts.project_id);
|
|
2338
|
+
}
|
|
2316
2339
|
if (opts.since) {
|
|
2317
2340
|
conditions.push("created_at > ?");
|
|
2318
2341
|
params.push(opts.since);
|
|
@@ -3599,7 +3622,7 @@ var init_poll = __esm(() => {
|
|
|
3599
3622
|
var require_package = __commonJS((exports, module) => {
|
|
3600
3623
|
module.exports = {
|
|
3601
3624
|
name: "@hasna/conversations",
|
|
3602
|
-
version: "0.1.
|
|
3625
|
+
version: "0.1.31",
|
|
3603
3626
|
description: "Real-time CLI messaging for AI agents",
|
|
3604
3627
|
type: "module",
|
|
3605
3628
|
bin: {
|
|
@@ -32576,17 +32599,19 @@ var init_mcp2 = __esm(() => {
|
|
|
32576
32599
|
content: exports_external.string(),
|
|
32577
32600
|
from: exports_external.string().optional(),
|
|
32578
32601
|
priority: exports_external.string().optional(),
|
|
32579
|
-
blocking: exports_external.coerce.boolean().optional()
|
|
32602
|
+
blocking: exports_external.coerce.boolean().optional(),
|
|
32603
|
+
project_id: exports_external.string().optional()
|
|
32580
32604
|
}
|
|
32581
32605
|
}, async (args) => {
|
|
32582
|
-
const { from: fromParam, to, content, priority, blocking } = args;
|
|
32606
|
+
const { from: fromParam, to, content, priority, blocking, project_id } = args;
|
|
32583
32607
|
const from = resolveIdentity(fromParam);
|
|
32584
32608
|
const msg = sendMessage({
|
|
32585
32609
|
from,
|
|
32586
32610
|
to,
|
|
32587
32611
|
content,
|
|
32588
32612
|
priority,
|
|
32589
|
-
blocking
|
|
32613
|
+
blocking,
|
|
32614
|
+
project_id
|
|
32590
32615
|
});
|
|
32591
32616
|
return {
|
|
32592
32617
|
content: [{ type: "text", text: JSON.stringify(msg) }]
|
|
@@ -32599,6 +32624,7 @@ var init_mcp2 = __esm(() => {
|
|
|
32599
32624
|
from: exports_external.string().optional(),
|
|
32600
32625
|
to: exports_external.string().optional(),
|
|
32601
32626
|
space: exports_external.string().optional(),
|
|
32627
|
+
project_id: exports_external.string().optional(),
|
|
32602
32628
|
since: exports_external.string().optional(),
|
|
32603
32629
|
limit: exports_external.coerce.number().optional(),
|
|
32604
32630
|
unread_only: exports_external.coerce.boolean().optional()
|
package/bin/mcp.js
CHANGED
|
@@ -6546,6 +6546,7 @@ function getDb() {
|
|
|
6546
6546
|
from_agent TEXT NOT NULL,
|
|
6547
6547
|
to_agent TEXT NOT NULL,
|
|
6548
6548
|
space TEXT,
|
|
6549
|
+
project_id TEXT,
|
|
6549
6550
|
content TEXT NOT NULL,
|
|
6550
6551
|
priority TEXT NOT NULL DEFAULT 'normal',
|
|
6551
6552
|
working_dir TEXT,
|
|
@@ -6611,6 +6612,20 @@ function getDb() {
|
|
|
6611
6612
|
metadata TEXT
|
|
6612
6613
|
)
|
|
6613
6614
|
`);
|
|
6615
|
+
db.exec(`
|
|
6616
|
+
CREATE TABLE IF NOT EXISTS resource_locks (
|
|
6617
|
+
resource_type TEXT NOT NULL,
|
|
6618
|
+
resource_id TEXT NOT NULL,
|
|
6619
|
+
agent_id TEXT NOT NULL,
|
|
6620
|
+
lock_type TEXT NOT NULL DEFAULT 'advisory',
|
|
6621
|
+
locked_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
|
|
6622
|
+
expires_at TEXT NOT NULL,
|
|
6623
|
+
UNIQUE(resource_type, resource_id, lock_type)
|
|
6624
|
+
)
|
|
6625
|
+
`);
|
|
6626
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_locks_resource ON resource_locks(resource_type, resource_id)");
|
|
6627
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_locks_agent ON resource_locks(agent_id)");
|
|
6628
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_locks_expires ON resource_locks(expires_at)");
|
|
6614
6629
|
db.exec(`
|
|
6615
6630
|
CREATE TABLE IF NOT EXISTS reactions (
|
|
6616
6631
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -6686,6 +6701,10 @@ function getDb() {
|
|
|
6686
6701
|
db.exec("ALTER TABLE messages ADD COLUMN reply_to INTEGER REFERENCES messages(id)");
|
|
6687
6702
|
db.exec("CREATE INDEX IF NOT EXISTS idx_messages_reply_to ON messages(reply_to)");
|
|
6688
6703
|
}
|
|
6704
|
+
if (!colNames2.includes("project_id")) {
|
|
6705
|
+
db.exec("ALTER TABLE messages ADD COLUMN project_id TEXT");
|
|
6706
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_messages_project ON messages(project_id)");
|
|
6707
|
+
}
|
|
6689
6708
|
const presenceCols = db.prepare("PRAGMA table_info(agent_presence)").all();
|
|
6690
6709
|
const presenceColNames = presenceCols.map((c) => c.name);
|
|
6691
6710
|
if (!presenceColNames.includes("id")) {
|
|
@@ -28718,11 +28737,11 @@ function sendMessage(opts) {
|
|
|
28718
28737
|
const blocking = opts.blocking ? 1 : 0;
|
|
28719
28738
|
const replyTo = opts.reply_to || null;
|
|
28720
28739
|
const stmt = db2.prepare(`
|
|
28721
|
-
INSERT INTO messages (session_id, from_agent, to_agent, space, content, priority, working_dir, repository, branch, metadata, blocking, reply_to)
|
|
28722
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
28740
|
+
INSERT INTO messages (session_id, from_agent, to_agent, space, project_id, content, priority, working_dir, repository, branch, metadata, blocking, reply_to)
|
|
28741
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
28723
28742
|
RETURNING *
|
|
28724
28743
|
`);
|
|
28725
|
-
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, replyTo);
|
|
28744
|
+
const row = stmt.get(sessionId, opts.from, opts.to, opts.space || null, opts.project_id || null, opts.content, normalizedPriority, opts.working_dir || null, opts.repository || null, opts.branch || null, metadata, blocking, replyTo);
|
|
28726
28745
|
const message = parseMessage(row);
|
|
28727
28746
|
if (opts.attachments && opts.attachments.length > 0) {
|
|
28728
28747
|
const attachmentsDir = join3(getAttachmentsDir(), String(message.id));
|
|
@@ -28766,6 +28785,10 @@ function readMessages(opts = {}) {
|
|
|
28766
28785
|
conditions.push("space = ?");
|
|
28767
28786
|
params.push(opts.space);
|
|
28768
28787
|
}
|
|
28788
|
+
if (opts.project_id) {
|
|
28789
|
+
conditions.push("project_id = ?");
|
|
28790
|
+
params.push(opts.project_id);
|
|
28791
|
+
}
|
|
28769
28792
|
if (opts.since) {
|
|
28770
28793
|
conditions.push("created_at > ?");
|
|
28771
28794
|
params.push(opts.since);
|
|
@@ -29872,7 +29895,7 @@ function renameAgent(oldName, newName) {
|
|
|
29872
29895
|
// package.json
|
|
29873
29896
|
var package_default = {
|
|
29874
29897
|
name: "@hasna/conversations",
|
|
29875
|
-
version: "0.1.
|
|
29898
|
+
version: "0.1.31",
|
|
29876
29899
|
description: "Real-time CLI messaging for AI agents",
|
|
29877
29900
|
type: "module",
|
|
29878
29901
|
bin: {
|
|
@@ -29961,17 +29984,19 @@ server.registerTool("send_message", {
|
|
|
29961
29984
|
content: exports_external.string(),
|
|
29962
29985
|
from: exports_external.string().optional(),
|
|
29963
29986
|
priority: exports_external.string().optional(),
|
|
29964
|
-
blocking: exports_external.coerce.boolean().optional()
|
|
29987
|
+
blocking: exports_external.coerce.boolean().optional(),
|
|
29988
|
+
project_id: exports_external.string().optional()
|
|
29965
29989
|
}
|
|
29966
29990
|
}, async (args) => {
|
|
29967
|
-
const { from: fromParam, to, content, priority, blocking } = args;
|
|
29991
|
+
const { from: fromParam, to, content, priority, blocking, project_id } = args;
|
|
29968
29992
|
const from = resolveIdentity(fromParam);
|
|
29969
29993
|
const msg = sendMessage({
|
|
29970
29994
|
from,
|
|
29971
29995
|
to,
|
|
29972
29996
|
content,
|
|
29973
29997
|
priority,
|
|
29974
|
-
blocking
|
|
29998
|
+
blocking,
|
|
29999
|
+
project_id
|
|
29975
30000
|
});
|
|
29976
30001
|
return {
|
|
29977
30002
|
content: [{ type: "text", text: JSON.stringify(msg) }]
|
|
@@ -29984,6 +30009,7 @@ server.registerTool("read_messages", {
|
|
|
29984
30009
|
from: exports_external.string().optional(),
|
|
29985
30010
|
to: exports_external.string().optional(),
|
|
29986
30011
|
space: exports_external.string().optional(),
|
|
30012
|
+
project_id: exports_external.string().optional(),
|
|
29987
30013
|
since: exports_external.string().optional(),
|
|
29988
30014
|
limit: exports_external.coerce.number().optional(),
|
|
29989
30015
|
unread_only: exports_external.coerce.boolean().optional()
|
package/dist/index.d.ts
CHANGED
|
@@ -19,4 +19,6 @@ export { resolveIdentity, requireIdentity, } from "./lib/identity.js";
|
|
|
19
19
|
export { addReaction, removeReaction, getReactions, getReactionSummary, } from "./lib/reactions.js";
|
|
20
20
|
export { fireWebhooks, } from "./lib/webhooks.js";
|
|
21
21
|
export { heartbeat, registerAgent, isAgentConflict, getPresence, listAgents, removePresence, renameAgent, } from "./lib/presence.js";
|
|
22
|
+
export { acquireLock, releaseLock, checkLock, cleanExpiredLocks, listLocks, } from "./lib/locks.js";
|
|
23
|
+
export type { ResourceLock } from "./lib/locks.js";
|
|
22
24
|
export type { Message, Session, Space, SpaceInfo, SpaceMember, Project, ProjectInfo, Priority, SendMessageOptions, ReadMessagesOptions, SearchMessagesOptions, AgentPresence, AgentConflictError, RegisterAgentResult, Reaction, Attachment, } from "./types.js";
|
package/dist/index.js
CHANGED
|
@@ -73,6 +73,7 @@ function getDb() {
|
|
|
73
73
|
from_agent TEXT NOT NULL,
|
|
74
74
|
to_agent TEXT NOT NULL,
|
|
75
75
|
space TEXT,
|
|
76
|
+
project_id TEXT,
|
|
76
77
|
content TEXT NOT NULL,
|
|
77
78
|
priority TEXT NOT NULL DEFAULT 'normal',
|
|
78
79
|
working_dir TEXT,
|
|
@@ -138,6 +139,20 @@ function getDb() {
|
|
|
138
139
|
metadata TEXT
|
|
139
140
|
)
|
|
140
141
|
`);
|
|
142
|
+
db.exec(`
|
|
143
|
+
CREATE TABLE IF NOT EXISTS resource_locks (
|
|
144
|
+
resource_type TEXT NOT NULL,
|
|
145
|
+
resource_id TEXT NOT NULL,
|
|
146
|
+
agent_id TEXT NOT NULL,
|
|
147
|
+
lock_type TEXT NOT NULL DEFAULT 'advisory',
|
|
148
|
+
locked_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
|
|
149
|
+
expires_at TEXT NOT NULL,
|
|
150
|
+
UNIQUE(resource_type, resource_id, lock_type)
|
|
151
|
+
)
|
|
152
|
+
`);
|
|
153
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_locks_resource ON resource_locks(resource_type, resource_id)");
|
|
154
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_locks_agent ON resource_locks(agent_id)");
|
|
155
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_locks_expires ON resource_locks(expires_at)");
|
|
141
156
|
db.exec(`
|
|
142
157
|
CREATE TABLE IF NOT EXISTS reactions (
|
|
143
158
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -213,6 +228,10 @@ function getDb() {
|
|
|
213
228
|
db.exec("ALTER TABLE messages ADD COLUMN reply_to INTEGER REFERENCES messages(id)");
|
|
214
229
|
db.exec("CREATE INDEX IF NOT EXISTS idx_messages_reply_to ON messages(reply_to)");
|
|
215
230
|
}
|
|
231
|
+
if (!colNames2.includes("project_id")) {
|
|
232
|
+
db.exec("ALTER TABLE messages ADD COLUMN project_id TEXT");
|
|
233
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_messages_project ON messages(project_id)");
|
|
234
|
+
}
|
|
216
235
|
const presenceCols = db.prepare("PRAGMA table_info(agent_presence)").all();
|
|
217
236
|
const presenceColNames = presenceCols.map((c) => c.name);
|
|
218
237
|
if (!presenceColNames.includes("id")) {
|
|
@@ -2239,11 +2258,11 @@ function sendMessage(opts) {
|
|
|
2239
2258
|
const blocking = opts.blocking ? 1 : 0;
|
|
2240
2259
|
const replyTo = opts.reply_to || null;
|
|
2241
2260
|
const stmt = db2.prepare(`
|
|
2242
|
-
INSERT INTO messages (session_id, from_agent, to_agent, space, content, priority, working_dir, repository, branch, metadata, blocking, reply_to)
|
|
2243
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
2261
|
+
INSERT INTO messages (session_id, from_agent, to_agent, space, project_id, content, priority, working_dir, repository, branch, metadata, blocking, reply_to)
|
|
2262
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
2244
2263
|
RETURNING *
|
|
2245
2264
|
`);
|
|
2246
|
-
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, replyTo);
|
|
2265
|
+
const row = stmt.get(sessionId, opts.from, opts.to, opts.space || null, opts.project_id || null, opts.content, normalizedPriority, opts.working_dir || null, opts.repository || null, opts.branch || null, metadata, blocking, replyTo);
|
|
2247
2266
|
const message = parseMessage(row);
|
|
2248
2267
|
if (opts.attachments && opts.attachments.length > 0) {
|
|
2249
2268
|
const attachmentsDir = join3(getAttachmentsDir(), String(message.id));
|
|
@@ -2287,6 +2306,10 @@ function readMessages(opts = {}) {
|
|
|
2287
2306
|
conditions.push("space = ?");
|
|
2288
2307
|
params.push(opts.space);
|
|
2289
2308
|
}
|
|
2309
|
+
if (opts.project_id) {
|
|
2310
|
+
conditions.push("project_id = ?");
|
|
2311
|
+
params.push(opts.project_id);
|
|
2312
|
+
}
|
|
2290
2313
|
if (opts.since) {
|
|
2291
2314
|
conditions.push("created_at > ?");
|
|
2292
2315
|
params.push(opts.since);
|
|
@@ -3557,6 +3580,80 @@ function renameAgent(oldName, newName) {
|
|
|
3557
3580
|
db2.prepare("UPDATE agent_presence SET agent = ? WHERE LOWER(agent) = ?").run(normalizedNew, normalizedOld);
|
|
3558
3581
|
return true;
|
|
3559
3582
|
}
|
|
3583
|
+
// src/lib/locks.ts
|
|
3584
|
+
init_db();
|
|
3585
|
+
var DEFAULT_LOCK_EXPIRY_MS = 5 * 60 * 1000;
|
|
3586
|
+
function acquireLock(resourceType, resourceId, agentId, lockType = "advisory", expiryMs = DEFAULT_LOCK_EXPIRY_MS) {
|
|
3587
|
+
const db2 = getDb();
|
|
3588
|
+
return db2.transaction(() => {
|
|
3589
|
+
cleanExpiredLocks();
|
|
3590
|
+
const existing = db2.prepare(`
|
|
3591
|
+
SELECT * FROM resource_locks
|
|
3592
|
+
WHERE resource_type = ? AND resource_id = ? AND lock_type = ?
|
|
3593
|
+
`).get(resourceType, resourceId, lockType);
|
|
3594
|
+
if (existing) {
|
|
3595
|
+
if (existing.agent_id !== agentId) {
|
|
3596
|
+
return { acquired: false, lock: null, held_by: existing.agent_id };
|
|
3597
|
+
}
|
|
3598
|
+
const expiresAt = new Date(Date.now() + expiryMs).toISOString().replace("T", "T").replace("Z", "");
|
|
3599
|
+
db2.prepare(`
|
|
3600
|
+
UPDATE resource_locks SET expires_at = ?, locked_at = strftime('%Y-%m-%dT%H:%M:%f', 'now')
|
|
3601
|
+
WHERE resource_type = ? AND resource_id = ? AND lock_type = ?
|
|
3602
|
+
`).run(expiresAt, resourceType, resourceId, lockType);
|
|
3603
|
+
} else {
|
|
3604
|
+
const expiresAt = new Date(Date.now() + expiryMs).toISOString().slice(0, -1);
|
|
3605
|
+
db2.prepare(`
|
|
3606
|
+
INSERT INTO resource_locks (resource_type, resource_id, agent_id, lock_type, locked_at, expires_at)
|
|
3607
|
+
VALUES (?, ?, ?, ?, strftime('%Y-%m-%dT%H:%M:%f', 'now'), ?)
|
|
3608
|
+
`).run(resourceType, resourceId, agentId, lockType, expiresAt);
|
|
3609
|
+
}
|
|
3610
|
+
const lock = db2.prepare(`
|
|
3611
|
+
SELECT * FROM resource_locks WHERE resource_type = ? AND resource_id = ? AND lock_type = ?
|
|
3612
|
+
`).get(resourceType, resourceId, lockType);
|
|
3613
|
+
return { acquired: true, lock };
|
|
3614
|
+
}).immediate();
|
|
3615
|
+
}
|
|
3616
|
+
function releaseLock(resourceType, resourceId, agentId) {
|
|
3617
|
+
const db2 = getDb();
|
|
3618
|
+
const result = db2.prepare(`
|
|
3619
|
+
DELETE FROM resource_locks
|
|
3620
|
+
WHERE resource_type = ? AND resource_id = ? AND agent_id = ?
|
|
3621
|
+
`).run(resourceType, resourceId, agentId);
|
|
3622
|
+
return result.changes > 0;
|
|
3623
|
+
}
|
|
3624
|
+
function checkLock(resourceType, resourceId) {
|
|
3625
|
+
const db2 = getDb();
|
|
3626
|
+
cleanExpiredLocks();
|
|
3627
|
+
return db2.prepare(`
|
|
3628
|
+
SELECT * FROM resource_locks
|
|
3629
|
+
WHERE resource_type = ? AND resource_id = ?
|
|
3630
|
+
ORDER BY locked_at ASC
|
|
3631
|
+
LIMIT 1
|
|
3632
|
+
`).get(resourceType, resourceId);
|
|
3633
|
+
}
|
|
3634
|
+
function cleanExpiredLocks() {
|
|
3635
|
+
const db2 = getDb();
|
|
3636
|
+
const result = db2.prepare(`
|
|
3637
|
+
DELETE FROM resource_locks WHERE expires_at < strftime('%Y-%m-%dT%H:%M:%f', 'now')
|
|
3638
|
+
`).run();
|
|
3639
|
+
return result.changes;
|
|
3640
|
+
}
|
|
3641
|
+
function listLocks(opts) {
|
|
3642
|
+
const db2 = getDb();
|
|
3643
|
+
cleanExpiredLocks();
|
|
3644
|
+
let query = "SELECT * FROM resource_locks WHERE 1=1";
|
|
3645
|
+
const params = [];
|
|
3646
|
+
if (opts?.resource_type) {
|
|
3647
|
+
query += " AND resource_type = ?";
|
|
3648
|
+
params.push(opts.resource_type);
|
|
3649
|
+
}
|
|
3650
|
+
if (opts?.agent_id) {
|
|
3651
|
+
query += " AND agent_id = ?";
|
|
3652
|
+
params.push(opts.agent_id);
|
|
3653
|
+
}
|
|
3654
|
+
query += " ORDER BY locked_at ASC";
|
|
3655
|
+
return db2.prepare(query).all(...params);
|
|
3656
|
+
}
|
|
3560
3657
|
export {
|
|
3561
3658
|
useSpaceMessages,
|
|
3562
3659
|
updateSpace,
|
|
@@ -3571,6 +3668,7 @@ export {
|
|
|
3571
3668
|
renameAgent,
|
|
3572
3669
|
removeReaction,
|
|
3573
3670
|
removePresence,
|
|
3671
|
+
releaseLock,
|
|
3574
3672
|
registerAgent,
|
|
3575
3673
|
readMessages,
|
|
3576
3674
|
pinMessage,
|
|
@@ -3581,6 +3679,7 @@ export {
|
|
|
3581
3679
|
listSpaces,
|
|
3582
3680
|
listSessions,
|
|
3583
3681
|
listProjects,
|
|
3682
|
+
listLocks,
|
|
3584
3683
|
listAgents,
|
|
3585
3684
|
leaveSpace,
|
|
3586
3685
|
joinSpace,
|
|
@@ -3610,6 +3709,9 @@ export {
|
|
|
3610
3709
|
createSpace,
|
|
3611
3710
|
createProject,
|
|
3612
3711
|
closeDb,
|
|
3712
|
+
cleanExpiredLocks,
|
|
3713
|
+
checkLock,
|
|
3613
3714
|
archiveSpace,
|
|
3614
|
-
addReaction
|
|
3715
|
+
addReaction,
|
|
3716
|
+
acquireLock
|
|
3615
3717
|
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface ResourceLock {
|
|
2
|
+
resource_type: string;
|
|
3
|
+
resource_id: string;
|
|
4
|
+
agent_id: string;
|
|
5
|
+
lock_type: "advisory" | "exclusive";
|
|
6
|
+
locked_at: string;
|
|
7
|
+
expires_at: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function acquireLock(resourceType: string, resourceId: string, agentId: string, lockType?: "advisory" | "exclusive", expiryMs?: number): {
|
|
10
|
+
acquired: boolean;
|
|
11
|
+
lock: ResourceLock | null;
|
|
12
|
+
held_by?: string;
|
|
13
|
+
};
|
|
14
|
+
export declare function releaseLock(resourceType: string, resourceId: string, agentId: string): boolean;
|
|
15
|
+
export declare function checkLock(resourceType: string, resourceId: string): ResourceLock | null;
|
|
16
|
+
export declare function cleanExpiredLocks(): number;
|
|
17
|
+
export declare function listLocks(opts?: {
|
|
18
|
+
resource_type?: string;
|
|
19
|
+
agent_id?: string;
|
|
20
|
+
}): ResourceLock[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/types.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export interface Message {
|
|
|
5
5
|
from_agent: string;
|
|
6
6
|
to_agent: string;
|
|
7
7
|
space: string | null;
|
|
8
|
+
project_id: string | null;
|
|
8
9
|
content: string;
|
|
9
10
|
priority: Priority;
|
|
10
11
|
working_dir: string | null;
|
|
@@ -80,6 +81,7 @@ export interface SendMessageOptions {
|
|
|
80
81
|
content: string;
|
|
81
82
|
session_id?: string;
|
|
82
83
|
space?: string;
|
|
84
|
+
project_id?: string;
|
|
83
85
|
priority?: Priority;
|
|
84
86
|
working_dir?: string;
|
|
85
87
|
repository?: string;
|
|
@@ -97,6 +99,7 @@ export interface ReadMessagesOptions {
|
|
|
97
99
|
from?: string;
|
|
98
100
|
to?: string;
|
|
99
101
|
space?: string;
|
|
102
|
+
project_id?: string;
|
|
100
103
|
since?: string;
|
|
101
104
|
since_id?: number;
|
|
102
105
|
limit?: number;
|