switchroom 0.14.59 → 0.14.60

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.
@@ -49452,8 +49452,8 @@ var {
49452
49452
  } = import__.default;
49453
49453
 
49454
49454
  // src/build-info.ts
49455
- var VERSION = "0.14.59";
49456
- var COMMIT_SHA = "178c6d14";
49455
+ var VERSION = "0.14.60";
49456
+ var COMMIT_SHA = "7a03004e";
49457
49457
 
49458
49458
  // src/cli/agent.ts
49459
49459
  init_source();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "switchroom",
3
- "version": "0.14.59",
3
+ "version": "0.14.60",
4
4
  "description": "Run Claude Code 24/7 on your Claude Pro/Max subscription over Telegram. Open-source alternative to OpenClaw and NanoClaw — no API keys.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -52310,10 +52310,10 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
52310
52310
  }
52311
52311
 
52312
52312
  // ../src/build-info.ts
52313
- var VERSION = "0.14.59";
52314
- var COMMIT_SHA = "178c6d14";
52315
- var COMMIT_DATE = "2026-06-04T07:31:45Z";
52316
- var LATEST_PR = 2146;
52313
+ var VERSION = "0.14.60";
52314
+ var COMMIT_SHA = "7a03004e";
52315
+ var COMMIT_DATE = "2026-06-04T07:56:20Z";
52316
+ var LATEST_PR = 2148;
52317
52317
  var COMMITS_AHEAD_OF_TAG = 0;
52318
52318
 
52319
52319
  // gateway/boot-version.ts
@@ -53806,6 +53806,9 @@ function endCurrentTurnAtomic(turn) {
53806
53806
  if (currentTurn !== turn)
53807
53807
  return;
53808
53808
  currentTurn = null;
53809
+ if (OBLIGATION_LEDGER_ENABLED && turn.finalAnswerDelivered) {
53810
+ obligationLedger.close(turn.turnId);
53811
+ }
53809
53812
  if (turn.noReplyDrainTimer != null) {
53810
53813
  clearTimeout(turn.noReplyDrainTimer);
53811
53814
  turn.noReplyDrainTimer = null;
@@ -2354,6 +2354,21 @@ function releaseTurnBufferGate(key: string, endingTurn?: CurrentTurn): void {
2354
2354
  function endCurrentTurnAtomic(turn: CurrentTurn): void {
2355
2355
  if (currentTurn !== turn) return
2356
2356
  currentTurn = null
2357
+ // PR2 obligation-ledger CLOSE-at-turn-end. Close the ended turn's obligation
2358
+ // when it delivered a final answer. finalAnswerDelivered is the right signal
2359
+ // HERE (not isSubstantiveFinalReply at reply-time): a SHORT genuine answer
2360
+ // ("4") is final-but-not-substantive, so the reply-time substantive-close
2361
+ // missed it → it looked unanswered → the idle sweep double-asked every short
2362
+ // turn (canary, v0.14.59). At turn_end the #2141 logic has already demoted a
2363
+ // bare interim ack to non-final, so finalAnswerDelivered===true means GENUINELY
2364
+ // answered. This runs before the next idle sweep, so a short answer closes
2365
+ // cleanly (no double-ask); an ack-then-ghost / no-reply turn ends with
2366
+ // finalAnswerDelivered===false → stays open → re-presented (the intended
2367
+ // catch). close() is a no-op for synthetic turns (turnId not in the ledger).
2368
+ // No-op when the flag is off.
2369
+ if (OBLIGATION_LEDGER_ENABLED && turn.finalAnswerDelivered) {
2370
+ obligationLedger.close(turn.turnId)
2371
+ }
2357
2372
  // Component 2 — clear any prior no-reply drain timer for this turn; a
2358
2373
  // fresh end re-evaluates below. (Idempotent — null when never armed.)
2359
2374
  if (turn.noReplyDrainTimer != null) {