switchroom 0.14.56 → 0.14.57
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/dist/cli/switchroom.js
CHANGED
|
@@ -49463,8 +49463,8 @@ var {
|
|
|
49463
49463
|
} = import__.default;
|
|
49464
49464
|
|
|
49465
49465
|
// src/build-info.ts
|
|
49466
|
-
var VERSION = "0.14.
|
|
49467
|
-
var COMMIT_SHA = "
|
|
49466
|
+
var VERSION = "0.14.57";
|
|
49467
|
+
var COMMIT_SHA = "ddb0b353";
|
|
49468
49468
|
|
|
49469
49469
|
// src/cli/agent.ts
|
|
49470
49470
|
init_source();
|
package/package.json
CHANGED
|
@@ -52195,10 +52195,10 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
52195
52195
|
}
|
|
52196
52196
|
|
|
52197
52197
|
// ../src/build-info.ts
|
|
52198
|
-
var VERSION = "0.14.
|
|
52199
|
-
var COMMIT_SHA = "
|
|
52200
|
-
var COMMIT_DATE = "2026-06-
|
|
52201
|
-
var LATEST_PR =
|
|
52198
|
+
var VERSION = "0.14.57";
|
|
52199
|
+
var COMMIT_SHA = "ddb0b353";
|
|
52200
|
+
var COMMIT_DATE = "2026-06-03T22:37:37Z";
|
|
52201
|
+
var LATEST_PR = 2140;
|
|
52202
52202
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
52203
52203
|
|
|
52204
52204
|
// gateway/boot-version.ts
|
|
@@ -57090,7 +57090,7 @@ async function drainActivitySummary(turn) {
|
|
|
57090
57090
|
turn.activityInFlight = null;
|
|
57091
57091
|
}
|
|
57092
57092
|
}
|
|
57093
|
-
function clearActivitySummary(turn) {
|
|
57093
|
+
function clearActivitySummary(turn, finalHtmlOverride) {
|
|
57094
57094
|
const chat = turn.sessionChatId;
|
|
57095
57095
|
const thread = turn.sessionThreadId;
|
|
57096
57096
|
const inFlight = turn.activityInFlight ?? Promise.resolve();
|
|
@@ -57108,7 +57108,7 @@ function clearActivitySummary(turn) {
|
|
|
57108
57108
|
}
|
|
57109
57109
|
return;
|
|
57110
57110
|
}
|
|
57111
|
-
const finalHtml = composeTurnActivity(turn, true);
|
|
57111
|
+
const finalHtml = finalHtmlOverride !== undefined ? finalHtmlOverride : composeTurnActivity(turn, true);
|
|
57112
57112
|
if (finalHtml == null)
|
|
57113
57113
|
return;
|
|
57114
57114
|
try {
|
|
@@ -63416,16 +63416,18 @@ var didOneTimeSetup = false;
|
|
|
63416
63416
|
const isBackground = dispatch.isBackground;
|
|
63417
63417
|
if (!isBackground) {
|
|
63418
63418
|
const turn = currentTurn;
|
|
63419
|
-
|
|
63420
|
-
if (turn != null && removed) {
|
|
63419
|
+
if (turn != null && turn.foregroundSubAgents.has(agentId)) {
|
|
63421
63420
|
const action = foregroundFinishAction({
|
|
63422
|
-
removed,
|
|
63421
|
+
removed: true,
|
|
63423
63422
|
replyCalled: turn.replyCalled,
|
|
63424
|
-
remainingForeground: turn.foregroundSubAgents.size
|
|
63423
|
+
remainingForeground: turn.foregroundSubAgents.size - 1
|
|
63425
63424
|
});
|
|
63426
63425
|
if (action === "handoff-clear") {
|
|
63427
|
-
|
|
63426
|
+
const finalHtml = composeTurnActivity(turn, true);
|
|
63427
|
+
turn.foregroundSubAgents.delete(agentId);
|
|
63428
|
+
clearActivitySummary(turn, finalHtml);
|
|
63428
63429
|
} else if (action === "recompose") {
|
|
63430
|
+
turn.foregroundSubAgents.delete(agentId);
|
|
63429
63431
|
const rendered = composeTurnActivity(turn);
|
|
63430
63432
|
if (rendered != null) {
|
|
63431
63433
|
turn.activityPendingRender = rendered;
|
|
@@ -8467,8 +8467,18 @@ async function drainActivitySummary(turn: CurrentTurn): Promise<void> {
|
|
|
8467
8467
|
* Called on the first reply (hand-off) and again at turn_end (no-reply safety
|
|
8468
8468
|
* net); finalize edits are idempotent (a 'message is not modified' on the
|
|
8469
8469
|
* second call is swallowed).
|
|
8470
|
+
*
|
|
8471
|
+
* `finalHtmlOverride` (finalize path only): a render captured by the caller
|
|
8472
|
+
* BEFORE it tore down turn state the finalize render depends on. The
|
|
8473
|
+
* foreground handoff-clear path passes this — it deletes the just-finished
|
|
8474
|
+
* sub-agent's narrative right after this call, so the async
|
|
8475
|
+
* `composeTurnActivity(turn, true)` below would see an emptied feed (and, on
|
|
8476
|
+
* ack-first turns, empty `mirrorLines`), render null, and skip the finalize —
|
|
8477
|
+
* freezing the last live "→ in-progress" line. The captured render keeps the
|
|
8478
|
+
* persisted record reading done (✓). Omitted → compute it here (the common
|
|
8479
|
+
* reply/turn_end callers, where state is stable).
|
|
8470
8480
|
*/
|
|
8471
|
-
function clearActivitySummary(turn: CurrentTurn): void {
|
|
8481
|
+
function clearActivitySummary(turn: CurrentTurn, finalHtmlOverride?: string | null): void {
|
|
8472
8482
|
const chat = turn.sessionChatId
|
|
8473
8483
|
const thread = turn.sessionThreadId
|
|
8474
8484
|
const inFlight = turn.activityInFlight ?? Promise.resolve()
|
|
@@ -8489,7 +8499,8 @@ function clearActivitySummary(turn: CurrentTurn): void {
|
|
|
8489
8499
|
}
|
|
8490
8500
|
// Default: leave the status message as a record, edited to a terminal
|
|
8491
8501
|
// all-done state so it doesn't freeze on a misleading "→ in-progress" line.
|
|
8492
|
-
const finalHtml =
|
|
8502
|
+
const finalHtml =
|
|
8503
|
+
finalHtmlOverride !== undefined ? finalHtmlOverride : composeTurnActivity(turn, true)
|
|
8493
8504
|
if (finalHtml == null) return
|
|
8494
8505
|
try {
|
|
8495
8506
|
await robustApiCall(
|
|
@@ -19278,20 +19289,32 @@ void (async () => {
|
|
|
19278
19289
|
// tool result, so there's no handback to deliver. Reaction
|
|
19279
19290
|
// promotion already ran above.
|
|
19280
19291
|
const turn = currentTurn
|
|
19281
|
-
|
|
19282
|
-
|
|
19292
|
+
// has()-then-delete (not delete-up-front): the handoff-clear
|
|
19293
|
+
// branch must render the finished sub-agent's steps as done
|
|
19294
|
+
// WHILE its narrative is still in the map, then remove it.
|
|
19295
|
+
if (turn != null && turn.foregroundSubAgents.has(agentId)) {
|
|
19283
19296
|
const action = foregroundFinishAction({
|
|
19284
|
-
removed,
|
|
19297
|
+
removed: true,
|
|
19285
19298
|
replyCalled: turn.replyCalled,
|
|
19286
|
-
|
|
19299
|
+
// size AFTER this agent's impending removal
|
|
19300
|
+
remainingForeground: turn.foregroundSubAgents.size - 1,
|
|
19287
19301
|
})
|
|
19288
19302
|
if (action === 'handoff-clear') {
|
|
19289
19303
|
// Post-ack: the last foreground sub-agent finished and
|
|
19290
19304
|
// the parent will now produce its answer inline. Hand
|
|
19291
19305
|
// the re-opened feed off to the answer, mirroring the
|
|
19292
|
-
// first-reply clear (turn_end is the safety net).
|
|
19293
|
-
|
|
19306
|
+
// first-reply clear (turn_end is the safety net). Capture
|
|
19307
|
+
// the finalized render (child steps done ✓) BEFORE the
|
|
19308
|
+
// delete, then pass it so the persisted record doesn't
|
|
19309
|
+
// freeze on a stale "→ in-progress" line (the emptied-feed
|
|
19310
|
+
// skip — see clearActivitySummary's finalHtmlOverride doc).
|
|
19311
|
+
const finalHtml = composeTurnActivity(turn, true)
|
|
19312
|
+
turn.foregroundSubAgents.delete(agentId)
|
|
19313
|
+
clearActivitySummary(turn, finalHtml)
|
|
19294
19314
|
} else if (action === 'recompose') {
|
|
19315
|
+
// Collapse the finished sub-agent's block: delete first,
|
|
19316
|
+
// then render WITHOUT it (live feed keeps its → step).
|
|
19317
|
+
turn.foregroundSubAgents.delete(agentId)
|
|
19295
19318
|
const rendered = composeTurnActivity(turn)
|
|
19296
19319
|
if (rendered != null) {
|
|
19297
19320
|
turn.activityPendingRender = rendered
|
|
@@ -222,4 +222,30 @@ describe("renderActivityFeedWithNested — foreground sub-agent nesting (Model A
|
|
|
222
222
|
"<i>✓ Reading a.ts</i>",
|
|
223
223
|
);
|
|
224
224
|
});
|
|
225
|
+
|
|
226
|
+
// Pins the invariant the gateway's foreground handoff-clear path relies on:
|
|
227
|
+
// on an ack-first turn the parent feed is empty (mirrorLines=[]) and the only
|
|
228
|
+
// content is the foreground sub-agent's nested narrative. The finalized
|
|
229
|
+
// render MUST be captured WHILE that narrative is present — once the gateway
|
|
230
|
+
// removes the finished sub-agent from the map, the render collapses to null
|
|
231
|
+
// and the finalize would be skipped, freezing the last live "→" line. This is
|
|
232
|
+
// exactly why clearActivitySummary takes a pre-delete finalHtmlOverride.
|
|
233
|
+
describe("foreground handoff-clear: capture-before-delete invariant", () => {
|
|
234
|
+
it("ack-first (empty parent) + child present → non-null all-done render (✓, no →)", () => {
|
|
235
|
+
const out = renderActivityFeedWithNested(
|
|
236
|
+
[],
|
|
237
|
+
["Sleep 2 for step 8", "Step 8 done; final echo", "All eight steps completed"],
|
|
238
|
+
true,
|
|
239
|
+
);
|
|
240
|
+
expect(out).not.toBeNull();
|
|
241
|
+
expect(out).not.toContain("→");
|
|
242
|
+
expect(out).toContain("All eight steps completed");
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it("ack-first (empty parent) + child REMOVED → null (the emptied-feed skip the gateway must avoid)", () => {
|
|
246
|
+
// After foregroundSubAgents.delete(agentId), the parent has nothing left
|
|
247
|
+
// to render on an ack-first turn → null → finalize would no-op.
|
|
248
|
+
expect(renderActivityFeedWithNested([], [], true)).toBeNull();
|
|
249
|
+
});
|
|
250
|
+
});
|
|
225
251
|
});
|