@mirasoth/soothe-client 0.2.1 → 0.4.1

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.
@@ -63,7 +63,7 @@ var ConnectionError = class extends Error {
63
63
  }
64
64
  };
65
65
  var DaemonError = class extends Error {
66
- /** Numeric error code from the RFC-450 §7.3 registry. */
66
+ /** Numeric error code from the daemon error registry. */
67
67
  code;
68
68
  /** The daemon's error message text. */
69
69
  daemonMessage;
@@ -293,11 +293,335 @@ var DEFAULT_DELIVERABLE_PHASES = /* @__PURE__ */ new Set([
293
293
  "embed"
294
294
  ]);
295
295
 
296
+ // src/verbosity.ts
297
+ var VerbosityTier = /* @__PURE__ */ ((VerbosityTier2) => {
298
+ VerbosityTier2[VerbosityTier2["Quiet"] = 0] = "Quiet";
299
+ VerbosityTier2[VerbosityTier2["Normal"] = 1] = "Normal";
300
+ VerbosityTier2[VerbosityTier2["Detailed"] = 2] = "Detailed";
301
+ VerbosityTier2[VerbosityTier2["Debug"] = 3] = "Debug";
302
+ VerbosityTier2[VerbosityTier2["Internal"] = 99] = "Internal";
303
+ return VerbosityTier2;
304
+ })(VerbosityTier || {});
305
+ var verbosityLevelValues = {
306
+ quiet: 0,
307
+ normal: 1,
308
+ debug: 3
309
+ };
310
+ function shouldShow(tier, verbosity) {
311
+ if (tier === 99 /* Internal */) {
312
+ return false;
313
+ }
314
+ const level = verbosityLevelValues[verbosity] ?? 1;
315
+ return tier <= level;
316
+ }
317
+ function isValidVerbosityLevel(s) {
318
+ return s in verbosityLevelValues;
319
+ }
320
+
321
+ // src/events.ts
322
+ var EventPlanCreated = "soothe.cognition.plan.created";
323
+ var EventExploreStarted = "soothe.subagent.explore.started";
324
+ var EventExploreMilestone = "soothe.subagent.explore.milestone";
325
+ var EventExploreStepCompleted = "soothe.subagent.explore.step.completed";
326
+ var EventExploreCompleted = "soothe.subagent.explore.completed";
327
+ var EventTacitusStarted = "soothe.subagent.tacitus.started";
328
+ var EventTacitusGatherSummary = "soothe.subagent.tacitus.gather.summary";
329
+ var EventTacitusCompleted = "soothe.subagent.tacitus.completed";
330
+ var EventReplayComplete = "replay_complete";
331
+ var EventLoopReattachedWire = "loop_reattached";
332
+ var EventCardReplayBegin = "card.replay_begin";
333
+ var EventCardCreated = "card.created";
334
+ var EventCardReplayEnd = "card.replay_end";
335
+ var EventToolStarted = "soothe.tool.execution.started";
336
+ var EventToolCompleted = "soothe.tool.execution.completed";
337
+ var EventToolError = "soothe.tool.execution.error";
338
+ var EventStreamToolCallUpdate = "soothe.stream.tool_call.update";
339
+ var EventToolCallUpdatesBatch = "tool_call_updates_batch";
340
+ var EventStrangeLoopStarted = "soothe.cognition.strange_loop.started";
341
+ var EventStrangeLoopCompleted = "soothe.cognition.strange_loop.completed";
342
+ var EventStrangeLoopPlanDecision = "soothe.cognition.strange_loop.plan.decision";
343
+ var EventStrangeLoopReasoned = "soothe.cognition.strange_loop.reasoned";
344
+ var EventStrangeLoopStepStarted = "soothe.cognition.strange_loop.step.started";
345
+ var EventStrangeLoopStepQueued = "soothe.cognition.strange_loop.step.queued";
346
+ var EventStrangeLoopStepCompleted = "soothe.cognition.strange_loop.step.completed";
347
+ var EventStrangeLoopContextCompacted = "soothe.cognition.strange_loop.context.compacted";
348
+ var EventMessageReceived = "soothe.protocol.message.received";
349
+ var EventMessageSent = "soothe.protocol.message.sent";
350
+ var EventFinalReport = "soothe.output.autonomous.final_report.reported";
351
+ var EventAutopilotGoalStatus = "soothe.autopilot.goal.status";
352
+ var EventAutopilotGoalProgress = "soothe.autopilot.goal.progress";
353
+ var EventAutopilotGoalCreated = "soothe.autopilot.goal.created";
354
+ var EventAutopilotGoalCompleted = "soothe.autopilot.goal.completed";
355
+ var EventAutopilotWorkerAssigned = "soothe.autopilot.worker.assigned";
356
+ var EventAutopilotWorkerUnassigned = "soothe.autopilot.worker.unassigned";
357
+ var EventGeneralFailed = "soothe.error.general.failed";
358
+ function parseNamespace(ns) {
359
+ const parts = splitNamespace(ns);
360
+ if (parts.length < 4 || parts[0] !== "soothe") {
361
+ return null;
362
+ }
363
+ if (parts[1] === "internal") {
364
+ return null;
365
+ }
366
+ return { domain: parts[1], component: parts[2], action: parts[3] };
367
+ }
368
+ function splitNamespace(ns) {
369
+ const parts = [];
370
+ let start = 0;
371
+ for (let i = 0; i < ns.length; i++) {
372
+ if (ns[i] === ".") {
373
+ parts.push(ns.slice(start, i));
374
+ start = i + 1;
375
+ }
376
+ }
377
+ parts.push(ns.slice(start));
378
+ return parts;
379
+ }
380
+ function classifyEventVerbosity(eventTypeOrNamespace) {
381
+ const parsed = parseNamespace(eventTypeOrNamespace);
382
+ if (!parsed) {
383
+ return classifyByEventTypeString(eventTypeOrNamespace);
384
+ }
385
+ return classifyByDomainAndComponent(parsed.domain, parsed.component, eventTypeOrNamespace);
386
+ }
387
+ function classifyByDomainAndComponent(domain, _component, full) {
388
+ switch (domain) {
389
+ case "cognition":
390
+ return 1 /* Normal */;
391
+ case "protocol":
392
+ return 2 /* Detailed */;
393
+ case "tool":
394
+ return 99 /* Internal */;
395
+ case "subagent":
396
+ return classifySubagentEvent(full);
397
+ case "autopilot":
398
+ return 1 /* Normal */;
399
+ case "output":
400
+ case "error":
401
+ return 0 /* Quiet */;
402
+ default:
403
+ return 1 /* Normal */;
404
+ }
405
+ }
406
+ function classifySubagentEvent(full) {
407
+ const parsed = parseNamespace(full);
408
+ if (!parsed) return 1 /* Normal */;
409
+ switch (parsed.action) {
410
+ case "started":
411
+ case "completed":
412
+ return 1 /* Normal */;
413
+ default:
414
+ return 2 /* Detailed */;
415
+ }
416
+ }
417
+ function classifyByEventTypeString(eventType) {
418
+ if (eventType === EventFinalReport || eventType === EventGeneralFailed) {
419
+ return 0 /* Quiet */;
420
+ }
421
+ if (eventType === EventToolStarted) {
422
+ return 99 /* Internal */;
423
+ }
424
+ return 1 /* Normal */;
425
+ }
426
+ function isCompletionEvent(eventType) {
427
+ return eventType.endsWith(".completed") || eventType.endsWith(".failed") || eventType === EventGeneralFailed;
428
+ }
429
+ function isSubagentProgressEvent(eventType) {
430
+ const parsed = parseNamespace(eventType);
431
+ if (!parsed || parsed.domain !== "subagent") {
432
+ return false;
433
+ }
434
+ return parsed.action === "started" || parsed.action === "completed";
435
+ }
436
+
437
+ // src/stream_terminal.ts
438
+ var STREAM_END = "soothe.stream.end";
439
+ var TURN_END_CUSTOM_TYPES = /* @__PURE__ */ new Set([
440
+ STREAM_END,
441
+ EventStrangeLoopCompleted
442
+ ]);
443
+ var TURN_PROGRESS_CUSTOM_TYPES = /* @__PURE__ */ new Set([
444
+ EventPlanCreated,
445
+ EventStrangeLoopStepStarted,
446
+ EventStrangeLoopStepQueued,
447
+ EventStrangeLoopStepCompleted
448
+ ]);
449
+ var STALE_TURN_PENDING_TYPES = /* @__PURE__ */ new Set([
450
+ "connection_ack",
451
+ EventCardReplayBegin,
452
+ EventCardReplayEnd,
453
+ EventCardCreated,
454
+ "complete"
455
+ ]);
456
+ function isTurnEndCustomData(data) {
457
+ if (!data || typeof data !== "object") return false;
458
+ const customType = String(data.type ?? "").trim();
459
+ if (!TURN_END_CUSTOM_TYPES.has(customType)) return false;
460
+ if (customType === STREAM_END) {
461
+ const scope = String(data.scope ?? "turn").trim().toLowerCase();
462
+ return scope === "" || scope === "turn";
463
+ }
464
+ return true;
465
+ }
466
+ function isTurnProgressChunk(mode, data) {
467
+ if (mode === "messages" || mode === "updates") return true;
468
+ if (mode !== "custom" || !data || typeof data !== "object") return false;
469
+ if (isTurnEndCustomData(data)) return false;
470
+ const customType = String(data.type ?? "").trim();
471
+ if (TURN_PROGRESS_CUSTOM_TYPES.has(customType)) return true;
472
+ if (customType.startsWith("soothe.cognition.strange_loop.step")) return true;
473
+ return false;
474
+ }
475
+ function stalePendingFrameLabel(event) {
476
+ const eventType = String(event.type ?? "");
477
+ if (STALE_TURN_PENDING_TYPES.has(eventType)) return eventType;
478
+ if (eventType === "next") {
479
+ const payload = event.payload;
480
+ if (!payload || typeof payload !== "object") return null;
481
+ const p = payload;
482
+ const staleMode = String(p.mode ?? "");
483
+ if (STALE_TURN_PENDING_TYPES.has(staleMode)) return staleMode;
484
+ const inner = p.data;
485
+ if (inner && typeof inner === "object") {
486
+ return stalePendingFrameLabel(inner);
487
+ }
488
+ return null;
489
+ }
490
+ if (eventType === "event") {
491
+ const mode = String(event.mode ?? "");
492
+ const data = event.data;
493
+ if (mode === "custom" && isTurnEndCustomData(data)) {
494
+ return String(data.type ?? "").trim();
495
+ }
496
+ }
497
+ return null;
498
+ }
499
+ function inboundNeedsDeliveryAck(event) {
500
+ const eventType = String(event.type ?? "");
501
+ if (eventType === "complete") return true;
502
+ if (eventType === "next") {
503
+ const payload = event.payload;
504
+ if (!payload || typeof payload !== "object") return false;
505
+ const p = payload;
506
+ const inner = p.data;
507
+ if (!inner || typeof inner !== "object") return false;
508
+ if (String(p.mode ?? "") === "event") {
509
+ return inboundNeedsAckFromEventShape(inner);
510
+ }
511
+ return false;
512
+ }
513
+ if (eventType === "event") return inboundNeedsAckFromEventShape(event);
514
+ return false;
515
+ }
516
+ function inboundNeedsAckFromEventShape(event) {
517
+ const mode = String(event.mode ?? "");
518
+ const data = event.data;
519
+ if (mode === "custom" && isTurnEndCustomData(data)) return true;
520
+ if (mode === "messages" && Array.isArray(data) && data.length > 0) {
521
+ const body = data[0];
522
+ if (!body || typeof body !== "object") return false;
523
+ const t = String(body.type ?? "");
524
+ return t === STREAM_END || t.includes("stream.end");
525
+ }
526
+ return false;
527
+ }
528
+ function extractLoopIdFromInbound(event) {
529
+ const direct = String(event.loop_id ?? "").trim();
530
+ if (direct) return direct;
531
+ if (String(event.type ?? "") !== "next") return "";
532
+ const payload = event.payload;
533
+ if (!payload || typeof payload !== "object") return "";
534
+ const p = payload;
535
+ const fromPayload = String(p.loop_id ?? "").trim();
536
+ if (fromPayload) return fromPayload;
537
+ const inner = p.data;
538
+ if (inner && typeof inner === "object") {
539
+ return String(inner.loop_id ?? "").trim();
540
+ }
541
+ return "";
542
+ }
543
+
544
+ // src/inbound_priority.ts
545
+ var DROP_PRIORITY_CRITICAL = 0;
546
+ var DROP_PRIORITY_HIGH = 1;
547
+ var DROP_PRIORITY_NORMAL = 2;
548
+ var DEFAULT_INBOUND_MAX_SIZE = 2e4;
549
+ function inboundFrameDropPriority(event) {
550
+ if (!event) return DROP_PRIORITY_CRITICAL;
551
+ let eventType = String(event.type ?? "");
552
+ if (eventType === "event_batch" || eventType === "tool_call_updates_batch") {
553
+ return DROP_PRIORITY_HIGH;
554
+ }
555
+ if (eventType === "next") {
556
+ const payload = event.payload;
557
+ if (payload && typeof payload === "object") {
558
+ const p = payload;
559
+ const innerMode = String(p.mode ?? "");
560
+ const innerData = p.data;
561
+ if (innerMode === "messages") {
562
+ if (messagesWireTerminal(innerData)) return DROP_PRIORITY_CRITICAL;
563
+ if (Array.isArray(innerData) && innerData[0] && typeof innerData[0] === "object") {
564
+ if (String(innerData[0].phase ?? "") === "goal_completion") {
565
+ return DROP_PRIORITY_CRITICAL;
566
+ }
567
+ }
568
+ }
569
+ if (String(p.type ?? "") === "complete") return DROP_PRIORITY_CRITICAL;
570
+ if (innerData && typeof innerData === "object") {
571
+ return inboundFrameDropPriority(innerData);
572
+ }
573
+ eventType = String(p.type ?? "");
574
+ }
575
+ }
576
+ if (eventType === "complete" || eventType === "error" || eventType === "connection_ack") {
577
+ return DROP_PRIORITY_CRITICAL;
578
+ }
579
+ if (eventType === "status") {
580
+ const state = String(event.state ?? "");
581
+ if (["idle", "running", "stopped", "detached"].includes(state)) {
582
+ return DROP_PRIORITY_CRITICAL;
583
+ }
584
+ }
585
+ if (eventType === "event") {
586
+ const mode = String(event.mode ?? "");
587
+ const data = event.data;
588
+ if (mode === "custom") {
589
+ if (isTurnEndCustomData(data)) return DROP_PRIORITY_CRITICAL;
590
+ if (data && typeof data === "object") {
591
+ const customType = String(data.type ?? "");
592
+ if (customType.startsWith("soothe.cognition.")) return DROP_PRIORITY_HIGH;
593
+ if (customType.startsWith("soothe.error.") || customType === "stream_degraded") {
594
+ return DROP_PRIORITY_CRITICAL;
595
+ }
596
+ if (customType === "soothe.ux.stream_tool_wire.tool_call_updates_batch") {
597
+ return DROP_PRIORITY_HIGH;
598
+ }
599
+ }
600
+ }
601
+ if (mode === "messages") {
602
+ if (messagesWireTerminal(data)) return DROP_PRIORITY_CRITICAL;
603
+ if (Array.isArray(data) && data[0] && typeof data[0] === "object") {
604
+ if (String(data[0].phase ?? "") === "goal_completion") {
605
+ return DROP_PRIORITY_CRITICAL;
606
+ }
607
+ }
608
+ }
609
+ }
610
+ return DROP_PRIORITY_NORMAL;
611
+ }
612
+ function messagesWireTerminal(data) {
613
+ if (!Array.isArray(data) || data.length === 0) return false;
614
+ const body = data[0];
615
+ if (!body || typeof body !== "object") return false;
616
+ const t = String(body.type ?? "");
617
+ return t === STREAM_END || t.includes("stream.end");
618
+ }
619
+
296
620
  // src/protocol.ts
297
621
  import { randomUUID } from "crypto";
298
622
  var PROTO_VERSION = "1";
299
623
  var DEFAULT_CLIENT_CAPABILITIES = ["streaming", "batch", "heartbeat", "receipts"];
300
- var CLIENT_VERSION = "0.1.0";
624
+ var CLIENT_VERSION = "0.4.1";
301
625
  function encodeMessage(msg) {
302
626
  return JSON.stringify(msg) + "\n";
303
627
  }
@@ -465,8 +789,11 @@ var Client = class extends EventEmitter {
465
789
  config;
466
790
  ws = null;
467
791
  messageBuffer = [];
792
+ inboundMaxSize = DEFAULT_INBOUND_MAX_SIZE;
793
+ inboundDroppedCount = 0;
794
+ onStreamDegraded = null;
468
795
  resolvers = [];
469
- // Protocol-1 handshake state (RFC-450 §8.2)
796
+ // Protocol-1 handshake state
470
797
  handshakeComplete = false;
471
798
  negotiatedCapabilities = /* @__PURE__ */ new Set();
472
799
  protocolVersion = null;
@@ -474,14 +801,16 @@ var Client = class extends EventEmitter {
474
801
  heartbeatIntervalMs = 0;
475
802
  heartbeatTimer = null;
476
803
  lastPongMonotonic = 0;
477
- // Mid-session drop signal (RFC-450 §8.3). The 'disconnected' event is
804
+ // Mid-session drop signal. The 'disconnected' event is
478
805
  // emitted exactly once when the connection drops, carrying a DisconnectCause
479
806
  // that distinguishes clean (peer `disconnect`) from unclean (read/write
480
807
  // error or missed pong). `disconnFired` guards the once-only delivery.
481
808
  disconnFired = false;
482
- // Pending-request/subscription multiplexer (RFC-629 constraint #1). Routes
809
+ // Pending-request/subscription multiplexer. Routes
483
810
  // inbound frames by (type, id) instead of discarding non-matching events.
484
811
  mux = new Multiplexer();
812
+ deliveryRecvSeq = /* @__PURE__ */ new Map();
813
+ deliveryAckedSeq = /* @__PURE__ */ new Map();
485
814
  constructor(url, config) {
486
815
  super();
487
816
  this.url = url;
@@ -549,13 +878,15 @@ var Client = class extends EventEmitter {
549
878
  this._signalDisconnect(1 /* Clean */);
550
879
  }
551
880
  if (this.mux.route(m)) {
881
+ this._trackInboundDeliveryAck(m);
552
882
  continue;
553
883
  }
884
+ this._trackInboundDeliveryAck(m);
554
885
  const resolver = this.resolvers.shift();
555
886
  if (resolver) {
556
887
  resolver(msg);
557
888
  } else {
558
- this.messageBuffer.push(msg);
889
+ this.enqueueMessageBuffer(msg);
559
890
  }
560
891
  this.emit("message", msg);
561
892
  }
@@ -592,7 +923,7 @@ var Client = class extends EventEmitter {
592
923
  return this.ws !== null && this.ws.readyState === WebSocket.OPEN && this.handshakeComplete;
593
924
  }
594
925
  // ---------------------------------------------------------------------------
595
- // Mid-session drop signal + reconnect/reattach (RFC-450 §8.3, RFC-629 L0)
926
+ // Mid-session drop signal + reconnect/reattach
596
927
  // ---------------------------------------------------------------------------
597
928
  /**
598
929
  * Returns whether the connection has dropped (the `'disconnected'` event has
@@ -627,8 +958,8 @@ var Client = class extends EventEmitter {
627
958
  }
628
959
  }
629
960
  /**
630
- * Re-dials the daemon and re-handshakes after a connection drop (RFC-450
631
- * §8.3). Does not re-establish loop subscriptions; follow with
961
+ * Re-dials the daemon and re-handshakes after a connection drop.
962
+ * Does not re-establish loop subscriptions; follow with
632
963
  * `reattachAndProbe()` to resume a loop session. The caller should invoke
633
964
  * this after the `'disconnected'` event fires. Reuses the same Client,
634
965
  * resetting the drop signal and multiplexer.
@@ -662,7 +993,7 @@ var Client = class extends EventEmitter {
662
993
  * Returns a `StaleLoopError` when the probe fails; callers should fall back
663
994
  * to a fresh `loop_new` bootstrap.
664
995
  *
665
- * Per RFC-629: connection-level readiness is the handshake's readiness_state
996
+ * Note: connection-level readiness is the handshake's readiness_state
666
997
  * (+ daemon_status); loop_get is a loop-scoped probe only, not a readiness
667
998
  * probe.
668
999
  */
@@ -703,7 +1034,7 @@ var Client = class extends EventEmitter {
703
1034
  }
704
1035
  }
705
1036
  // ---------------------------------------------------------------------------
706
- // Protocol-1 handshake (RFC-450 §8.2)
1037
+ // Protocol-1 handshake
707
1038
  // ---------------------------------------------------------------------------
708
1039
  /** Send connection_init and wait for connection_ack with readiness "ready". */
709
1040
  async _performHandshake() {
@@ -752,7 +1083,7 @@ var Client = class extends EventEmitter {
752
1083
  throw new Error(`timeout after ${this.config.daemonReadyTimeout}ms waiting for connection_ack`);
753
1084
  }
754
1085
  // ---------------------------------------------------------------------------
755
- // Heartbeat (RFC-450 §8.3)
1086
+ // Heartbeat
756
1087
  // ---------------------------------------------------------------------------
757
1088
  _startHeartbeat() {
758
1089
  if (!this.negotiatedCapabilities.has("heartbeat")) return;
@@ -868,8 +1199,86 @@ var Client = class extends EventEmitter {
868
1199
  this.resolvers.push(resolver);
869
1200
  });
870
1201
  }
1202
+ /**
1203
+ * Remove stale handshake/terminal frames left in `messageBuffer` before a turn.
1204
+ * Returns labels of removed frames (in order).
1205
+ */
1206
+ peelStalePendingControlEvents() {
1207
+ if (this.messageBuffer.length === 0) return [];
1208
+ const kept = [];
1209
+ const removed = [];
1210
+ while (this.messageBuffer.length > 0) {
1211
+ const event = this.messageBuffer.shift();
1212
+ const label = stalePendingFrameLabel(event);
1213
+ if (label !== null) {
1214
+ removed.push(label);
1215
+ continue;
1216
+ }
1217
+ kept.push(event);
1218
+ }
1219
+ this.messageBuffer = kept;
1220
+ return removed;
1221
+ }
1222
+ /** True when the underlying socket is still open (may not be handshaked). */
1223
+ isConnectionAlive() {
1224
+ return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
1225
+ }
1226
+ /** Override pending buffer cap (tests / tuning). */
1227
+ setInboundMaxSize(n) {
1228
+ if (n > 0) this.inboundMaxSize = n;
1229
+ }
1230
+ /** How many NORMAL-priority frames were dropped under backpressure. */
1231
+ inboundDropped() {
1232
+ return this.inboundDroppedCount;
1233
+ }
1234
+ /** Hook invoked on the first inbound overflow drop. */
1235
+ setStreamDegradedCallback(fn) {
1236
+ this.onStreamDegraded = fn;
1237
+ }
1238
+ enqueueMessageBuffer(msg) {
1239
+ const max = this.inboundMaxSize > 0 ? this.inboundMaxSize : DEFAULT_INBOUND_MAX_SIZE;
1240
+ if (this.messageBuffer.length < max) {
1241
+ this.messageBuffer.push(msg);
1242
+ return;
1243
+ }
1244
+ const ev = msg;
1245
+ let dropIdx = -1;
1246
+ let dropPri = -1;
1247
+ for (let i = 0; i < this.messageBuffer.length; i++) {
1248
+ const p = inboundFrameDropPriority(this.messageBuffer[i]);
1249
+ if (p > dropPri) {
1250
+ dropPri = p;
1251
+ dropIdx = i;
1252
+ }
1253
+ }
1254
+ const incomingPri = inboundFrameDropPriority(ev);
1255
+ if (dropIdx >= 0 && dropPri >= DROP_PRIORITY_NORMAL) {
1256
+ this.messageBuffer.splice(dropIdx, 1);
1257
+ this.messageBuffer.push(msg);
1258
+ this.noteInboundDrop();
1259
+ return;
1260
+ }
1261
+ if (incomingPri >= DROP_PRIORITY_NORMAL) {
1262
+ this.noteInboundDrop();
1263
+ return;
1264
+ }
1265
+ if (this.messageBuffer.length > 0) {
1266
+ this.messageBuffer.shift();
1267
+ this.noteInboundDrop();
1268
+ }
1269
+ this.messageBuffer.push(msg);
1270
+ }
1271
+ noteInboundDrop() {
1272
+ this.inboundDroppedCount += 1;
1273
+ if (this.onStreamDegraded && this.inboundDroppedCount === 1) {
1274
+ try {
1275
+ this.onStreamDegraded(1, "inbound_queue_overflow");
1276
+ } catch {
1277
+ }
1278
+ }
1279
+ }
871
1280
  // ---------------------------------------------------------------------------
872
- // Protocol-1 RPC primitives (RFC-450 §5/§9)
1281
+ // Protocol-1 RPC primitives
873
1282
  // ---------------------------------------------------------------------------
874
1283
  /**
875
1284
  * Reads the next frame directly from the live socket (via a resolver),
@@ -895,16 +1304,16 @@ var Client = class extends EventEmitter {
895
1304
  });
896
1305
  }
897
1306
  /**
898
- * Sends a `request` envelope and waits for the matching `response` (or
899
- * `error`) correlated by `id` (RFC-450 §5/§9). Returns the `result` object.
900
- *
901
- * Multiplexer-aware (RFC-629 constraint #1): registers a pending RPC wait
902
- * keyed by the request id so that, even when a `receiveMessages()` reader
903
- * is concurrently active, the matching `response`/`error` is routed to
904
- * this caller instead of being discarded or buffered behind a stream.
905
- * Non-matching frames are routed to their own waiters by the multiplexer
906
- * or flow on to the resolver queue for stream readers.
907
- */
1307
+ * Sends a `request` envelope and waits for the matching `response` (or
1308
+ * `error`) correlated by `id`. Returns the `result` object.
1309
+ *
1310
+ * Multiplexer-aware: registers a pending RPC wait
1311
+ * keyed by the request id so that, even when a `receiveMessages()` reader
1312
+ * is concurrently active, the matching `response`/`error` is routed to
1313
+ * this caller instead of being discarded or buffered behind a stream.
1314
+ * Non-matching frames are routed to their own waiters by the multiplexer
1315
+ * or flow on to the resolver queue for stream readers.
1316
+ */
908
1317
  async requestResponse(method, params, responseType, timeout = 15e3) {
909
1318
  const req = requestEnvelope(method, params);
910
1319
  const rid = req.id;
@@ -972,6 +1381,35 @@ var Client = class extends EventEmitter {
972
1381
  notify(method, params) {
973
1382
  return this.sendMessage(notificationEnvelope(method, params));
974
1383
  }
1384
+ _trackInboundDeliveryAck(event) {
1385
+ if (String(event.type ?? "") === "event_batch") {
1386
+ const events = event.events;
1387
+ if (Array.isArray(events)) {
1388
+ for (const sub of events) {
1389
+ if (sub && typeof sub === "object") {
1390
+ this._trackInboundDeliveryAck(sub);
1391
+ }
1392
+ }
1393
+ }
1394
+ return;
1395
+ }
1396
+ if (!inboundNeedsDeliveryAck(event)) return;
1397
+ const loopId = extractLoopIdFromInbound(event);
1398
+ if (!loopId) return;
1399
+ const next = (this.deliveryRecvSeq.get(loopId) ?? 0) + 1;
1400
+ this.deliveryRecvSeq.set(loopId, next);
1401
+ void this._sendDeliveryAck(loopId, next);
1402
+ }
1403
+ async _sendDeliveryAck(loopId, seq) {
1404
+ const acked = this.deliveryAckedSeq.get(loopId) ?? 0;
1405
+ if (seq <= acked) return;
1406
+ this.deliveryAckedSeq.set(loopId, seq);
1407
+ if (!this.isConnected()) return;
1408
+ try {
1409
+ await this.notify("delivery_ack", { loop_id: loopId, seq });
1410
+ } catch {
1411
+ }
1412
+ }
975
1413
  /**
976
1414
  * Starts a subscription stream. Returns the subscription `id` for later
977
1415
  * correlation and `unsubscribe()`. Stream events arrive as `next` frames
@@ -989,7 +1427,7 @@ var Client = class extends EventEmitter {
989
1427
  if (ev === null) break;
990
1428
  const evId = ev.id;
991
1429
  if (evId !== subId) {
992
- this.messageBuffer.push(ev);
1430
+ this.enqueueMessageBuffer(ev);
993
1431
  continue;
994
1432
  }
995
1433
  const typ = ev.type;
@@ -1026,7 +1464,7 @@ var Client = class extends EventEmitter {
1026
1464
  return ev;
1027
1465
  }
1028
1466
  // ---------------------------------------------------------------------------
1029
- // High-level API methods (Loop-first, RFC-503)
1467
+ // High-level API methods
1030
1468
  // ---------------------------------------------------------------------------
1031
1469
  /** Sends user input to the daemon (loop_input notification; requires loopID). */
1032
1470
  sendInput(text, options) {
@@ -1065,7 +1503,7 @@ var Client = class extends EventEmitter {
1065
1503
  return this.notify("slash_command", { cmd });
1066
1504
  }
1067
1505
  // ---------------------------------------------------------------------------
1068
- // Loop lifecycle methods (RFC-503)
1506
+ // Loop lifecycle methods
1069
1507
  // ---------------------------------------------------------------------------
1070
1508
  /** Requests the daemon to create a new StrangeLoop and waits for the response. */
1071
1509
  sendLoopNew(opts) {
@@ -1160,7 +1598,7 @@ var Client = class extends EventEmitter {
1160
1598
  sendLoopCardsFetch(loopID) {
1161
1599
  return this.sendMessage(requestEnvelope("loop_cards_fetch", { loop_id: loopID }));
1162
1600
  }
1163
- /** Requests the full loop history (RFC-631). */
1601
+ /** Requests the full loop history. */
1164
1602
  sendLoopHistoryFetch(loopID) {
1165
1603
  return this.sendMessage(requestEnvelope("loop_history_fetch", { loop_id: loopID }));
1166
1604
  }
@@ -1255,7 +1693,7 @@ var Client = class extends EventEmitter {
1255
1693
  );
1256
1694
  }
1257
1695
  // ---------------------------------------------------------------------------
1258
- // RFC-228 Job IPC methods
1696
+ // Job IPC methods
1259
1697
  // ---------------------------------------------------------------------------
1260
1698
  /** Creates an autopilot job and waits for the response. */
1261
1699
  createJob(goal, verificationRules, workspace, timeout) {
@@ -1290,6 +1728,98 @@ var Client = class extends EventEmitter {
1290
1728
  if (goalId) params.goal_id = goalId;
1291
1729
  return this.requestResponse("job_guidance", params, "job_guidance", timeout ?? 3e4);
1292
1730
  }
1731
+ // ---------------------------------------------------------------------------
1732
+ // Autopilot goal RPCs (protocol-1 request methods)
1733
+ // ---------------------------------------------------------------------------
1734
+ /** Return autopilot scheduler status (running / dreaming / pool). */
1735
+ autopilotStatus(timeout) {
1736
+ return this.requestResponse("autopilot_status", {}, "autopilot_status", timeout ?? 15e3);
1737
+ }
1738
+ /** Submit a new autopilot goal (returns goal_id). */
1739
+ autopilotSubmit(description, opts) {
1740
+ const params = {
1741
+ description,
1742
+ priority: opts?.priority ?? 50
1743
+ };
1744
+ if (opts?.workspace) params.workspace = opts.workspace;
1745
+ return this.requestResponse(
1746
+ "autopilot_submit",
1747
+ params,
1748
+ "autopilot_submit",
1749
+ opts?.timeout ?? 15e3
1750
+ );
1751
+ }
1752
+ /** List all goals (including non-root children). */
1753
+ autopilotListGoals(timeout) {
1754
+ return this.requestResponse(
1755
+ "autopilot_list_goals",
1756
+ {},
1757
+ "autopilot_list_goals",
1758
+ timeout ?? 15e3
1759
+ );
1760
+ }
1761
+ /** Fetch one goal by id. */
1762
+ autopilotGetGoal(goalId, timeout) {
1763
+ return this.requestResponse(
1764
+ "autopilot_get_goal",
1765
+ { goal_id: goalId },
1766
+ "autopilot_get_goal",
1767
+ timeout ?? 15e3
1768
+ );
1769
+ }
1770
+ /** Cancel a goal and its non-terminal descendants. */
1771
+ autopilotCancelGoal(goalId, timeout) {
1772
+ return this.requestResponse(
1773
+ "autopilot_cancel_goal",
1774
+ { goal_id: goalId },
1775
+ "autopilot_cancel_goal",
1776
+ timeout ?? 15e3
1777
+ );
1778
+ }
1779
+ /** Cancel every open (non-terminal) goal. */
1780
+ autopilotCancelAll(timeout) {
1781
+ return this.requestResponse(
1782
+ "autopilot_cancel_all",
1783
+ {},
1784
+ "autopilot_cancel_all",
1785
+ timeout ?? 15e3
1786
+ );
1787
+ }
1788
+ /** Exit dreaming mode and resume scheduling. */
1789
+ autopilotWake(timeout) {
1790
+ return this.requestResponse("autopilot_wake", {}, "autopilot_wake", timeout ?? 15e3);
1791
+ }
1792
+ /** Force dreaming mode. */
1793
+ autopilotDream(timeout) {
1794
+ return this.requestResponse("autopilot_dream", {}, "autopilot_dream", timeout ?? 15e3);
1795
+ }
1796
+ /** Resume a suspended or blocked goal. */
1797
+ autopilotResume(goalId, timeout) {
1798
+ return this.requestResponse(
1799
+ "autopilot_resume",
1800
+ { goal_id: goalId },
1801
+ "autopilot_resume",
1802
+ timeout ?? 15e3
1803
+ );
1804
+ }
1805
+ /** List root goals only (jobs). Prefer createJob / getJobStatus for job control. */
1806
+ autopilotListJobs(timeout) {
1807
+ return this.requestResponse(
1808
+ "autopilot_list_jobs",
1809
+ {},
1810
+ "autopilot_list_jobs",
1811
+ timeout ?? 15e3
1812
+ );
1813
+ }
1814
+ /** Get a root job with DAG snapshot. Prefer getJobStatus / getJobDag. */
1815
+ autopilotGetJob(jobId, timeout) {
1816
+ return this.requestResponse(
1817
+ "autopilot_get_job",
1818
+ { job_id: jobId },
1819
+ "autopilot_get_job",
1820
+ timeout ?? 15e3
1821
+ );
1822
+ }
1293
1823
  /** Subscribes to autopilot worker events. */
1294
1824
  autopilotSubscribe(timeout) {
1295
1825
  return this.subscribe("autopilot_events", {}, timeout ?? 15e3);
@@ -1300,7 +1830,7 @@ var Client = class extends EventEmitter {
1300
1830
  return this._requestResponseForEnvelope(req, "autopilot_unsubscribe", timeout ?? 15e3);
1301
1831
  }
1302
1832
  // ---------------------------------------------------------------------------
1303
- // RFC-229 Cron IPC methods
1833
+ // Cron IPC methods
1304
1834
  // ---------------------------------------------------------------------------
1305
1835
  /** Creates a scheduled job from natural language. */
1306
1836
  cronAdd(text, priority, timeout) {
@@ -1364,6 +1894,9 @@ export {
1364
1894
  disconnectCauseName,
1365
1895
  ReconnectError,
1366
1896
  StaleLoopError,
1897
+ VerbosityTier,
1898
+ shouldShow,
1899
+ isValidVerbosityLevel,
1367
1900
  defaultConfig,
1368
1901
  loadConfigFromEnv,
1369
1902
  PROTO_VERSION,
@@ -1393,7 +1926,50 @@ export {
1393
1926
  validateLoopInputIntentHint,
1394
1927
  LOOP_ASSISTANT_OUTPUT_PHASES,
1395
1928
  DEFAULT_DELIVERABLE_PHASES,
1396
- Multiplexer,
1929
+ EventPlanCreated,
1930
+ EventExploreStarted,
1931
+ EventExploreMilestone,
1932
+ EventExploreStepCompleted,
1933
+ EventExploreCompleted,
1934
+ EventTacitusStarted,
1935
+ EventTacitusGatherSummary,
1936
+ EventTacitusCompleted,
1937
+ EventReplayComplete,
1938
+ EventLoopReattachedWire,
1939
+ EventCardReplayBegin,
1940
+ EventCardCreated,
1941
+ EventCardReplayEnd,
1942
+ EventToolStarted,
1943
+ EventToolCompleted,
1944
+ EventToolError,
1945
+ EventStreamToolCallUpdate,
1946
+ EventToolCallUpdatesBatch,
1947
+ EventStrangeLoopStarted,
1948
+ EventStrangeLoopCompleted,
1949
+ EventStrangeLoopPlanDecision,
1950
+ EventStrangeLoopReasoned,
1951
+ EventStrangeLoopStepStarted,
1952
+ EventStrangeLoopStepQueued,
1953
+ EventStrangeLoopStepCompleted,
1954
+ EventStrangeLoopContextCompacted,
1955
+ EventMessageReceived,
1956
+ EventMessageSent,
1957
+ EventFinalReport,
1958
+ EventAutopilotGoalStatus,
1959
+ EventAutopilotGoalProgress,
1960
+ EventAutopilotGoalCreated,
1961
+ EventAutopilotGoalCompleted,
1962
+ EventAutopilotWorkerAssigned,
1963
+ EventAutopilotWorkerUnassigned,
1964
+ EventGeneralFailed,
1965
+ parseNamespace,
1966
+ classifyEventVerbosity,
1967
+ isCompletionEvent,
1968
+ isSubagentProgressEvent,
1969
+ STREAM_END,
1970
+ isTurnEndCustomData,
1971
+ isTurnProgressChunk,
1972
+ inboundNeedsDeliveryAck,
1397
1973
  Client
1398
1974
  };
1399
- //# sourceMappingURL=chunk-AQZACDIC.js.map
1975
+ //# sourceMappingURL=chunk-YYUVHZ3W.js.map