@cello-protocol/daemon 0.0.41 → 0.0.42

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.
@@ -1 +1 @@
1
- {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAKH,OAAO,KAAK,EACV,YAAY,EACZ,oBAAoB,EAQrB,MAAM,YAAY,CAAC;AAIpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAQ/D,OAAO,EAAoD,KAAK,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAsB7G,OAAO,KAAK,EAAE,kBAAkB,EAA+C,MAAM,yBAAyB,CAAC;AAQ/G,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,2BAA2B,CAAC;AA0InF,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,SAAS,IAAI,oBAAoB,CAAC;IAClC;;;;OAIG;IACH,qBAAqB,IAAI,kBAAkB,CAAC;IAC5C;;;;;;;;OAQG;IACH,gBAAgB,IAAI,SAAS,GAAG,IAAI,CAAC;IACrC;;;;OAIG;IACH,oBAAoB,IAAI,kBAAkB,CAAC;IAC3C;;;OAGG;IACH,iBAAiB,IAAI,eAAe,CAAC;CACtC;AA2CD,eAAO,MAAM,sBAAsB,QAAsB,CAAC;AAE1D,wBAAsB,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CA0rL7E"}
1
+ {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAKH,OAAO,KAAK,EACV,YAAY,EACZ,oBAAoB,EAQrB,MAAM,YAAY,CAAC;AAIpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAQ/D,OAAO,EAAoD,KAAK,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAsB7G,OAAO,KAAK,EAAE,kBAAkB,EAA+C,MAAM,yBAAyB,CAAC;AAQ/G,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,2BAA2B,CAAC;AA0InF,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,SAAS,IAAI,oBAAoB,CAAC;IAClC;;;;OAIG;IACH,qBAAqB,IAAI,kBAAkB,CAAC;IAC5C;;;;;;;;OAQG;IACH,gBAAgB,IAAI,SAAS,GAAG,IAAI,CAAC;IACrC;;;;OAIG;IACH,oBAAoB,IAAI,kBAAkB,CAAC;IAC3C;;;OAGG;IACH,iBAAiB,IAAI,eAAe,CAAC;CACtC;AA2CD,eAAO,MAAM,sBAAsB,QAAsB,CAAC;AAE1D,wBAAsB,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAktL7E"}
package/dist/daemon.js CHANGED
@@ -5168,12 +5168,22 @@ export async function startDaemon(config) {
5168
5168
  return { ok: false, reason: "missing_params", guidance: "Provide 'session_id' (hex) to receive content for a specific session." };
5169
5169
  }
5170
5170
  const record = sessionNodeManager.getSessionRecord(agentName, sessionId);
5171
+ // DOD-UNREAD-1 D4b: a TRANSCRIPT-ONLY session — received rows exist but no sessions row (the
5172
+ // pre-D3/D4a phantom residue: the counterparty's reply landed while this side refused the
5173
+ // session). Those rows are counted unread by getUnreadSummary, so cello_receive MUST be able
5174
+ // to read them or the badge can never clear. Reading is a transcript operation: the since_seq
5175
+ // catch-up below works from the durable transcript alone. Only a session with NEITHER a row
5176
+ // NOR transcript rows is truly not found.
5177
+ let transcriptOnly = false;
5171
5178
  if (!record) {
5172
- return { ok: false, reason: "session_not_found", guidance: "No session found with this ID. Check cello_list_sessions." };
5173
- }
5174
- if (record.agent_name !== agentName) {
5175
- return { ok: false, reason: "session_not_owned", guidance: "This session belongs to a different agent. Call cello_use_agent to switch to the agent that owns it, then retry." };
5179
+ if (sessionNodeManager.readTranscript(agentName, sessionId).messages.length === 0) {
5180
+ return { ok: false, reason: "session_not_found", guidance: "No session found with this ID. Check cello_list_sessions." };
5181
+ }
5182
+ transcriptOnly = true;
5176
5183
  }
5184
+ // (D4 review F3: the old `record.agent_name !== agentName` → session_not_owned branch was dead
5185
+ // code — getSessionRecord is keyed by (agent_name, session_id), so a record can never belong to
5186
+ // a different agent. A cross-agent session id simply has no record under this agent.)
5177
5187
  // M8C-SINCESEQ-1: stateless catch-up. When since_seq is provided, return a BATCH of received
5178
5188
  // transcript messages with sequence > since_seq (durable transcript, not the ephemeral buffer —
5179
5189
  // so concurrent arrivals don't shift what a given since_seq returns; no replay race). Replaces
@@ -5183,7 +5193,9 @@ export async function startDaemon(config) {
5183
5193
  const rawSince = params?.since_seq;
5184
5194
  if (typeof rawSince === "number" && Number.isFinite(rawSince)) {
5185
5195
  const sinceSeq = rawSince;
5186
- const from = record.counterparty_pubkey;
5196
+ // D4b AC2: a transcript-only session has no record to attribute from `from` is null,
5197
+ // NEVER the string "unknown" (the transcript stores no counterparty; don't invent one).
5198
+ const from = record ? record.counterparty_pubkey : null;
5187
5199
  const { messages } = sessionNodeManager.readTranscript(agentName, sessionId);
5188
5200
  const received = messages.filter((m) => m.direction === "received" && m.sequence > sinceSeq);
5189
5201
  if (received.length > 0) {
@@ -5204,6 +5216,17 @@ export async function startDaemon(config) {
5204
5216
  messages: received.map((m) => ({ sequence: m.sequence, content: m.text, from })),
5205
5217
  };
5206
5218
  }
5219
+ // D4b AC3: the plain (blocking) receive waits on a LIVE session's buffer — a transcript-only
5220
+ // session has no live node and nothing will ever arrive. Waiting to a null timeout would be
5221
+ // misleading and session_not_found would be a lie (the transcript exists). A distinct reason
5222
+ // points the caller at the read that works.
5223
+ if (transcriptOnly) {
5224
+ return {
5225
+ ok: false,
5226
+ reason: "session_not_live",
5227
+ guidance: "This session exists only as a durable transcript (no live session — it was never established or predates this daemon). Read it with cello_receive { since_seq } (e.g. since_seq: -1 for everything) or cello_get_transcript.",
5228
+ };
5229
+ }
5207
5230
  const rawTimeout = params?.timeout_ms;
5208
5231
  const timeoutMs = typeof rawTimeout === "number" && Number.isFinite(rawTimeout) && rawTimeout >= 0
5209
5232
  ? rawTimeout