@hasna/conversations 0.1.28 → 0.1.29

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 CHANGED
@@ -118,6 +118,7 @@ function getDb() {
118
118
  agent TEXT PRIMARY KEY,
119
119
  session_id TEXT,
120
120
  role TEXT NOT NULL DEFAULT 'agent',
121
+ project_id TEXT,
121
122
  status TEXT NOT NULL DEFAULT 'online',
122
123
  last_seen_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
123
124
  created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
@@ -219,6 +220,9 @@ function getDb() {
219
220
  db.exec("ALTER TABLE agent_presence ADD COLUMN created_at TEXT NOT NULL DEFAULT ''");
220
221
  db.exec("UPDATE agent_presence SET created_at = last_seen_at WHERE created_at = ''");
221
222
  }
223
+ if (!presenceColNames.includes("project_id")) {
224
+ db.exec("ALTER TABLE agent_presence ADD COLUMN project_id TEXT");
225
+ }
222
226
  const ftsExists = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='messages_fts'").get();
223
227
  if (!ftsExists) {
224
228
  db.exec(`
package/bin/index.js CHANGED
@@ -1972,6 +1972,7 @@ function getDb() {
1972
1972
  agent TEXT PRIMARY KEY,
1973
1973
  session_id TEXT,
1974
1974
  role TEXT NOT NULL DEFAULT 'agent',
1975
+ project_id TEXT,
1975
1976
  status TEXT NOT NULL DEFAULT 'online',
1976
1977
  last_seen_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
1977
1978
  created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
@@ -2073,6 +2074,9 @@ function getDb() {
2073
2074
  db.exec("ALTER TABLE agent_presence ADD COLUMN created_at TEXT NOT NULL DEFAULT ''");
2074
2075
  db.exec("UPDATE agent_presence SET created_at = last_seen_at WHERE created_at = ''");
2075
2076
  }
2077
+ if (!presenceColNames.includes("project_id")) {
2078
+ db.exec("ALTER TABLE agent_presence ADD COLUMN project_id TEXT");
2079
+ }
2076
2080
  const ftsExists = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='messages_fts'").get();
2077
2081
  if (!ftsExists) {
2078
2082
  db.exec(`
@@ -3339,6 +3343,7 @@ function parsePresence(row) {
3339
3343
  agent: row.agent,
3340
3344
  session_id: row.session_id ?? null,
3341
3345
  role: row.role || "agent",
3346
+ project_id: row.project_id ?? null,
3342
3347
  status: row.status,
3343
3348
  last_seen_at: lastSeenAt,
3344
3349
  created_at: row.created_at || lastSeenAt,
@@ -3351,43 +3356,46 @@ function isActiveSession(lastSeenAt) {
3351
3356
  const nowMs = Date.now();
3352
3357
  return nowMs - lastSeenMs < CONFLICT_THRESHOLD_SECONDS * 1000;
3353
3358
  }
3354
- function registerAgent(name, sessionId, role) {
3359
+ function registerAgent(name, sessionId, role, projectId) {
3355
3360
  const db2 = getDb();
3356
3361
  const normalizedName = name.trim().toLowerCase();
3357
- const existing = db2.prepare("SELECT * FROM agent_presence WHERE agent = ?").get(normalizedName);
3358
- if (existing) {
3359
- const lastSeenAt = existing.last_seen_at;
3360
- const existingSessionId = existing.session_id;
3361
- if (isActiveSession(lastSeenAt) && existingSessionId && existingSessionId !== sessionId) {
3362
- return {
3363
- conflict: true,
3364
- error: "agent_conflict",
3365
- message: `Agent "${normalizedName}" is already active (last seen: ${lastSeenAt}). Wait 30 minutes or use force takeover.`,
3366
- existing_id: existing.id,
3367
- existing_name: normalizedName,
3368
- existing_session_id: existingSessionId,
3369
- last_seen_at: lastSeenAt,
3370
- session_hint: existingSessionId ? existingSessionId.slice(0, 8) : null,
3371
- working_dir: null
3372
- };
3373
- }
3374
- const tookOver = existingSessionId !== sessionId;
3362
+ const result = db2.transaction(() => {
3363
+ const existing = db2.prepare("SELECT * FROM agent_presence WHERE agent = ?").get(normalizedName);
3364
+ if (existing) {
3365
+ const lastSeenAt = existing.last_seen_at;
3366
+ const existingSessionId = existing.session_id;
3367
+ if (isActiveSession(lastSeenAt) && existingSessionId && existingSessionId !== sessionId) {
3368
+ return {
3369
+ conflict: true,
3370
+ error: "agent_conflict",
3371
+ message: `Agent "${normalizedName}" is already active (last seen: ${lastSeenAt}). Wait 30 minutes or use force takeover.`,
3372
+ existing_id: existing.id,
3373
+ existing_name: normalizedName,
3374
+ existing_session_id: existingSessionId,
3375
+ last_seen_at: lastSeenAt,
3376
+ session_hint: existingSessionId ? existingSessionId.slice(0, 8) : null,
3377
+ working_dir: null
3378
+ };
3379
+ }
3380
+ const tookOver = existingSessionId !== sessionId;
3381
+ db2.prepare(`
3382
+ UPDATE agent_presence
3383
+ SET session_id = ?, role = ?, project_id = ?, last_seen_at = strftime('%Y-%m-%dT%H:%M:%f', 'now')
3384
+ WHERE agent = ?
3385
+ `).run(sessionId, role || existing.role || "agent", projectId ?? existing.project_id ?? null, normalizedName);
3386
+ const updated = db2.prepare("SELECT * FROM agent_presence WHERE agent = ?").get(normalizedName);
3387
+ return { agent: parsePresence(updated), created: false, took_over: tookOver };
3388
+ }
3389
+ const id = crypto.randomUUID().slice(0, 8);
3390
+ const resolvedRole = role || "agent";
3375
3391
  db2.prepare(`
3376
- UPDATE agent_presence
3377
- SET session_id = ?, role = ?, last_seen_at = strftime('%Y-%m-%dT%H:%M:%f', 'now')
3378
- WHERE agent = ?
3379
- `).run(sessionId, role || existing.role || "agent", normalizedName);
3380
- const updated = db2.prepare("SELECT * FROM agent_presence WHERE agent = ?").get(normalizedName);
3381
- return { agent: parsePresence(updated), created: false, took_over: tookOver };
3382
- }
3383
- const id = crypto.randomUUID().slice(0, 8);
3384
- const resolvedRole = role || "agent";
3385
- db2.prepare(`
3386
- INSERT INTO agent_presence (id, agent, session_id, role, status, last_seen_at, created_at)
3387
- VALUES (?, ?, ?, ?, 'online', strftime('%Y-%m-%dT%H:%M:%f', 'now'), strftime('%Y-%m-%dT%H:%M:%f', 'now'))
3388
- `).run(id, normalizedName, sessionId, resolvedRole);
3389
- const created = db2.prepare("SELECT * FROM agent_presence WHERE agent = ?").get(normalizedName);
3390
- return { agent: parsePresence(created), created: true, took_over: false };
3392
+ INSERT INTO agent_presence (id, agent, session_id, role, project_id, status, last_seen_at, created_at)
3393
+ VALUES (?, ?, ?, ?, ?, 'online', strftime('%Y-%m-%dT%H:%M:%f', 'now'), strftime('%Y-%m-%dT%H:%M:%f', 'now'))
3394
+ `).run(id, normalizedName, sessionId, resolvedRole, projectId ?? null);
3395
+ const created = db2.prepare("SELECT * FROM agent_presence WHERE agent = ?").get(normalizedName);
3396
+ return { agent: parsePresence(created), created: true, took_over: false };
3397
+ }).immediate();
3398
+ return result;
3391
3399
  }
3392
3400
  function heartbeat(agent, status, metadata, sessionId) {
3393
3401
  const db2 = getDb();
@@ -3591,7 +3599,7 @@ var init_poll = __esm(() => {
3591
3599
  var require_package = __commonJS((exports, module) => {
3592
3600
  module.exports = {
3593
3601
  name: "@hasna/conversations",
3594
- version: "0.1.28",
3602
+ version: "0.1.29",
3595
3603
  description: "Real-time CLI messaging for AI agents",
3596
3604
  type: "module",
3597
3605
  bin: {
@@ -33189,15 +33197,16 @@ var init_mcp2 = __esm(() => {
33189
33197
  };
33190
33198
  });
33191
33199
  server.registerTool("register_agent", {
33192
- description: "Register an agent with conflict detection. Returns AgentConflictError if another active session exists (active = heartbeat within last 30 min).",
33200
+ description: "Register an agent with conflict detection. Returns AgentConflictError if another active session exists (active = heartbeat within last 30 min). Optional project_id locks agent to a project for the session.",
33193
33201
  inputSchema: {
33194
33202
  name: exports_external.string(),
33195
33203
  session_id: exports_external.string(),
33196
- role: exports_external.string().optional()
33204
+ role: exports_external.string().optional(),
33205
+ project_id: exports_external.string().optional()
33197
33206
  }
33198
33207
  }, async (args) => {
33199
- const { name, session_id, role } = args;
33200
- const result = registerAgent(name, session_id, role);
33208
+ const { name, session_id, role, project_id } = args;
33209
+ const result = registerAgent(name, session_id, role, project_id);
33201
33210
  return {
33202
33211
  content: [{ type: "text", text: JSON.stringify(result) }]
33203
33212
  };
package/bin/mcp.js CHANGED
@@ -6604,6 +6604,7 @@ function getDb() {
6604
6604
  agent TEXT PRIMARY KEY,
6605
6605
  session_id TEXT,
6606
6606
  role TEXT NOT NULL DEFAULT 'agent',
6607
+ project_id TEXT,
6607
6608
  status TEXT NOT NULL DEFAULT 'online',
6608
6609
  last_seen_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
6609
6610
  created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
@@ -6705,6 +6706,9 @@ function getDb() {
6705
6706
  db.exec("ALTER TABLE agent_presence ADD COLUMN created_at TEXT NOT NULL DEFAULT ''");
6706
6707
  db.exec("UPDATE agent_presence SET created_at = last_seen_at WHERE created_at = ''");
6707
6708
  }
6709
+ if (!presenceColNames.includes("project_id")) {
6710
+ db.exec("ALTER TABLE agent_presence ADD COLUMN project_id TEXT");
6711
+ }
6708
6712
  const ftsExists = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='messages_fts'").get();
6709
6713
  if (!ftsExists) {
6710
6714
  db.exec(`
@@ -29765,6 +29769,7 @@ function parsePresence(row) {
29765
29769
  agent: row.agent,
29766
29770
  session_id: row.session_id ?? null,
29767
29771
  role: row.role || "agent",
29772
+ project_id: row.project_id ?? null,
29768
29773
  status: row.status,
29769
29774
  last_seen_at: lastSeenAt,
29770
29775
  created_at: row.created_at || lastSeenAt,
@@ -29777,43 +29782,46 @@ function isActiveSession(lastSeenAt) {
29777
29782
  const nowMs = Date.now();
29778
29783
  return nowMs - lastSeenMs < CONFLICT_THRESHOLD_SECONDS * 1000;
29779
29784
  }
29780
- function registerAgent(name, sessionId, role) {
29785
+ function registerAgent(name, sessionId, role, projectId) {
29781
29786
  const db2 = getDb();
29782
29787
  const normalizedName = name.trim().toLowerCase();
29783
- const existing = db2.prepare("SELECT * FROM agent_presence WHERE agent = ?").get(normalizedName);
29784
- if (existing) {
29785
- const lastSeenAt = existing.last_seen_at;
29786
- const existingSessionId = existing.session_id;
29787
- if (isActiveSession(lastSeenAt) && existingSessionId && existingSessionId !== sessionId) {
29788
- return {
29789
- conflict: true,
29790
- error: "agent_conflict",
29791
- message: `Agent "${normalizedName}" is already active (last seen: ${lastSeenAt}). Wait 30 minutes or use force takeover.`,
29792
- existing_id: existing.id,
29793
- existing_name: normalizedName,
29794
- existing_session_id: existingSessionId,
29795
- last_seen_at: lastSeenAt,
29796
- session_hint: existingSessionId ? existingSessionId.slice(0, 8) : null,
29797
- working_dir: null
29798
- };
29799
- }
29800
- const tookOver = existingSessionId !== sessionId;
29788
+ const result = db2.transaction(() => {
29789
+ const existing = db2.prepare("SELECT * FROM agent_presence WHERE agent = ?").get(normalizedName);
29790
+ if (existing) {
29791
+ const lastSeenAt = existing.last_seen_at;
29792
+ const existingSessionId = existing.session_id;
29793
+ if (isActiveSession(lastSeenAt) && existingSessionId && existingSessionId !== sessionId) {
29794
+ return {
29795
+ conflict: true,
29796
+ error: "agent_conflict",
29797
+ message: `Agent "${normalizedName}" is already active (last seen: ${lastSeenAt}). Wait 30 minutes or use force takeover.`,
29798
+ existing_id: existing.id,
29799
+ existing_name: normalizedName,
29800
+ existing_session_id: existingSessionId,
29801
+ last_seen_at: lastSeenAt,
29802
+ session_hint: existingSessionId ? existingSessionId.slice(0, 8) : null,
29803
+ working_dir: null
29804
+ };
29805
+ }
29806
+ const tookOver = existingSessionId !== sessionId;
29807
+ db2.prepare(`
29808
+ UPDATE agent_presence
29809
+ SET session_id = ?, role = ?, project_id = ?, last_seen_at = strftime('%Y-%m-%dT%H:%M:%f', 'now')
29810
+ WHERE agent = ?
29811
+ `).run(sessionId, role || existing.role || "agent", projectId ?? existing.project_id ?? null, normalizedName);
29812
+ const updated = db2.prepare("SELECT * FROM agent_presence WHERE agent = ?").get(normalizedName);
29813
+ return { agent: parsePresence(updated), created: false, took_over: tookOver };
29814
+ }
29815
+ const id = crypto.randomUUID().slice(0, 8);
29816
+ const resolvedRole = role || "agent";
29801
29817
  db2.prepare(`
29802
- UPDATE agent_presence
29803
- SET session_id = ?, role = ?, last_seen_at = strftime('%Y-%m-%dT%H:%M:%f', 'now')
29804
- WHERE agent = ?
29805
- `).run(sessionId, role || existing.role || "agent", normalizedName);
29806
- const updated = db2.prepare("SELECT * FROM agent_presence WHERE agent = ?").get(normalizedName);
29807
- return { agent: parsePresence(updated), created: false, took_over: tookOver };
29808
- }
29809
- const id = crypto.randomUUID().slice(0, 8);
29810
- const resolvedRole = role || "agent";
29811
- db2.prepare(`
29812
- INSERT INTO agent_presence (id, agent, session_id, role, status, last_seen_at, created_at)
29813
- VALUES (?, ?, ?, ?, 'online', strftime('%Y-%m-%dT%H:%M:%f', 'now'), strftime('%Y-%m-%dT%H:%M:%f', 'now'))
29814
- `).run(id, normalizedName, sessionId, resolvedRole);
29815
- const created = db2.prepare("SELECT * FROM agent_presence WHERE agent = ?").get(normalizedName);
29816
- return { agent: parsePresence(created), created: true, took_over: false };
29818
+ INSERT INTO agent_presence (id, agent, session_id, role, project_id, status, last_seen_at, created_at)
29819
+ VALUES (?, ?, ?, ?, ?, 'online', strftime('%Y-%m-%dT%H:%M:%f', 'now'), strftime('%Y-%m-%dT%H:%M:%f', 'now'))
29820
+ `).run(id, normalizedName, sessionId, resolvedRole, projectId ?? null);
29821
+ const created = db2.prepare("SELECT * FROM agent_presence WHERE agent = ?").get(normalizedName);
29822
+ return { agent: parsePresence(created), created: true, took_over: false };
29823
+ }).immediate();
29824
+ return result;
29817
29825
  }
29818
29826
  function heartbeat(agent, status, metadata, sessionId) {
29819
29827
  const db2 = getDb();
@@ -29864,7 +29872,7 @@ function renameAgent(oldName, newName) {
29864
29872
  // package.json
29865
29873
  var package_default = {
29866
29874
  name: "@hasna/conversations",
29867
- version: "0.1.28",
29875
+ version: "0.1.29",
29868
29876
  description: "Real-time CLI messaging for AI agents",
29869
29877
  type: "module",
29870
29878
  bin: {
@@ -30574,15 +30582,16 @@ server.registerTool("get_pinned_messages", {
30574
30582
  };
30575
30583
  });
30576
30584
  server.registerTool("register_agent", {
30577
- description: "Register an agent with conflict detection. Returns AgentConflictError if another active session exists (active = heartbeat within last 30 min).",
30585
+ description: "Register an agent with conflict detection. Returns AgentConflictError if another active session exists (active = heartbeat within last 30 min). Optional project_id locks agent to a project for the session.",
30578
30586
  inputSchema: {
30579
30587
  name: exports_external.string(),
30580
30588
  session_id: exports_external.string(),
30581
- role: exports_external.string().optional()
30589
+ role: exports_external.string().optional(),
30590
+ project_id: exports_external.string().optional()
30582
30591
  }
30583
30592
  }, async (args) => {
30584
- const { name, session_id, role } = args;
30585
- const result = registerAgent(name, session_id, role);
30593
+ const { name, session_id, role, project_id } = args;
30594
+ const result = registerAgent(name, session_id, role, project_id);
30586
30595
  return {
30587
30596
  content: [{ type: "text", text: JSON.stringify(result) }]
30588
30597
  };
package/dist/index.js CHANGED
@@ -131,6 +131,7 @@ function getDb() {
131
131
  agent TEXT PRIMARY KEY,
132
132
  session_id TEXT,
133
133
  role TEXT NOT NULL DEFAULT 'agent',
134
+ project_id TEXT,
134
135
  status TEXT NOT NULL DEFAULT 'online',
135
136
  last_seen_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
136
137
  created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
@@ -232,6 +233,9 @@ function getDb() {
232
233
  db.exec("ALTER TABLE agent_presence ADD COLUMN created_at TEXT NOT NULL DEFAULT ''");
233
234
  db.exec("UPDATE agent_presence SET created_at = last_seen_at WHERE created_at = ''");
234
235
  }
236
+ if (!presenceColNames.includes("project_id")) {
237
+ db.exec("ALTER TABLE agent_presence ADD COLUMN project_id TEXT");
238
+ }
235
239
  const ftsExists = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='messages_fts'").get();
236
240
  if (!ftsExists) {
237
241
  db.exec(`
@@ -3444,6 +3448,7 @@ function parsePresence(row) {
3444
3448
  agent: row.agent,
3445
3449
  session_id: row.session_id ?? null,
3446
3450
  role: row.role || "agent",
3451
+ project_id: row.project_id ?? null,
3447
3452
  status: row.status,
3448
3453
  last_seen_at: lastSeenAt,
3449
3454
  created_at: row.created_at || lastSeenAt,
@@ -3459,43 +3464,46 @@ function isActiveSession(lastSeenAt) {
3459
3464
  function isAgentConflict(result) {
3460
3465
  return result.conflict === true;
3461
3466
  }
3462
- function registerAgent(name, sessionId, role) {
3467
+ function registerAgent(name, sessionId, role, projectId) {
3463
3468
  const db2 = getDb();
3464
3469
  const normalizedName = name.trim().toLowerCase();
3465
- const existing = db2.prepare("SELECT * FROM agent_presence WHERE agent = ?").get(normalizedName);
3466
- if (existing) {
3467
- const lastSeenAt = existing.last_seen_at;
3468
- const existingSessionId = existing.session_id;
3469
- if (isActiveSession(lastSeenAt) && existingSessionId && existingSessionId !== sessionId) {
3470
- return {
3471
- conflict: true,
3472
- error: "agent_conflict",
3473
- message: `Agent "${normalizedName}" is already active (last seen: ${lastSeenAt}). Wait 30 minutes or use force takeover.`,
3474
- existing_id: existing.id,
3475
- existing_name: normalizedName,
3476
- existing_session_id: existingSessionId,
3477
- last_seen_at: lastSeenAt,
3478
- session_hint: existingSessionId ? existingSessionId.slice(0, 8) : null,
3479
- working_dir: null
3480
- };
3470
+ const result = db2.transaction(() => {
3471
+ const existing = db2.prepare("SELECT * FROM agent_presence WHERE agent = ?").get(normalizedName);
3472
+ if (existing) {
3473
+ const lastSeenAt = existing.last_seen_at;
3474
+ const existingSessionId = existing.session_id;
3475
+ if (isActiveSession(lastSeenAt) && existingSessionId && existingSessionId !== sessionId) {
3476
+ return {
3477
+ conflict: true,
3478
+ error: "agent_conflict",
3479
+ message: `Agent "${normalizedName}" is already active (last seen: ${lastSeenAt}). Wait 30 minutes or use force takeover.`,
3480
+ existing_id: existing.id,
3481
+ existing_name: normalizedName,
3482
+ existing_session_id: existingSessionId,
3483
+ last_seen_at: lastSeenAt,
3484
+ session_hint: existingSessionId ? existingSessionId.slice(0, 8) : null,
3485
+ working_dir: null
3486
+ };
3487
+ }
3488
+ const tookOver = existingSessionId !== sessionId;
3489
+ db2.prepare(`
3490
+ UPDATE agent_presence
3491
+ SET session_id = ?, role = ?, project_id = ?, last_seen_at = strftime('%Y-%m-%dT%H:%M:%f', 'now')
3492
+ WHERE agent = ?
3493
+ `).run(sessionId, role || existing.role || "agent", projectId ?? existing.project_id ?? null, normalizedName);
3494
+ const updated = db2.prepare("SELECT * FROM agent_presence WHERE agent = ?").get(normalizedName);
3495
+ return { agent: parsePresence(updated), created: false, took_over: tookOver };
3481
3496
  }
3482
- const tookOver = existingSessionId !== sessionId;
3497
+ const id = crypto.randomUUID().slice(0, 8);
3498
+ const resolvedRole = role || "agent";
3483
3499
  db2.prepare(`
3484
- UPDATE agent_presence
3485
- SET session_id = ?, role = ?, last_seen_at = strftime('%Y-%m-%dT%H:%M:%f', 'now')
3486
- WHERE agent = ?
3487
- `).run(sessionId, role || existing.role || "agent", normalizedName);
3488
- const updated = db2.prepare("SELECT * FROM agent_presence WHERE agent = ?").get(normalizedName);
3489
- return { agent: parsePresence(updated), created: false, took_over: tookOver };
3490
- }
3491
- const id = crypto.randomUUID().slice(0, 8);
3492
- const resolvedRole = role || "agent";
3493
- db2.prepare(`
3494
- INSERT INTO agent_presence (id, agent, session_id, role, status, last_seen_at, created_at)
3495
- VALUES (?, ?, ?, ?, 'online', strftime('%Y-%m-%dT%H:%M:%f', 'now'), strftime('%Y-%m-%dT%H:%M:%f', 'now'))
3496
- `).run(id, normalizedName, sessionId, resolvedRole);
3497
- const created = db2.prepare("SELECT * FROM agent_presence WHERE agent = ?").get(normalizedName);
3498
- return { agent: parsePresence(created), created: true, took_over: false };
3500
+ INSERT INTO agent_presence (id, agent, session_id, role, project_id, status, last_seen_at, created_at)
3501
+ VALUES (?, ?, ?, ?, ?, 'online', strftime('%Y-%m-%dT%H:%M:%f', 'now'), strftime('%Y-%m-%dT%H:%M:%f', 'now'))
3502
+ `).run(id, normalizedName, sessionId, resolvedRole, projectId ?? null);
3503
+ const created = db2.prepare("SELECT * FROM agent_presence WHERE agent = ?").get(normalizedName);
3504
+ return { agent: parsePresence(created), created: true, took_over: false };
3505
+ }).immediate();
3506
+ return result;
3499
3507
  }
3500
3508
  function heartbeat(agent, status, metadata, sessionId) {
3501
3509
  const db2 = getDb();
@@ -1,6 +1,6 @@
1
1
  import type { AgentPresence, AgentConflictError, RegisterAgentResult } from "../types.js";
2
2
  export declare function isAgentConflict(result: RegisterAgentResult | AgentConflictError): result is AgentConflictError;
3
- export declare function registerAgent(name: string, sessionId: string, role?: string): RegisterAgentResult | AgentConflictError;
3
+ export declare function registerAgent(name: string, sessionId: string, role?: string, projectId?: string): RegisterAgentResult | AgentConflictError;
4
4
  export declare function heartbeat(agent: string, status?: string, metadata?: Record<string, unknown>, sessionId?: string): void;
5
5
  export declare function getPresence(agent: string): AgentPresence | null;
6
6
  export declare function listAgents(opts?: {
package/dist/types.d.ts CHANGED
@@ -116,6 +116,7 @@ export interface AgentPresence {
116
116
  agent: string;
117
117
  session_id: string | null;
118
118
  role: string;
119
+ project_id: string | null;
119
120
  status: string;
120
121
  last_seen_at: string;
121
122
  created_at: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/conversations",
3
- "version": "0.1.28",
3
+ "version": "0.1.29",
4
4
  "description": "Real-time CLI messaging for AI agents",
5
5
  "type": "module",
6
6
  "bin": {