switchroom 0.17.10 → 0.18.3
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/workspace-dynamic-hook.sh +12 -13
- package/dist/agent-scheduler/index.js +27 -1
- package/dist/auth-broker/index.js +6161 -151
- package/dist/cli/notion-write-pretool.mjs +29 -2
- package/dist/cli/switchroom.js +578 -454
- package/dist/host-control/main.js +6182 -172
- package/dist/vault/approvals/kernel-server.js +5891 -164
- package/dist/vault/broker/server.js +6597 -881
- package/package.json +1 -1
- package/profiles/_base/settings.json.hbs +2 -2
- package/profiles/_base/start.sh.hbs +170 -21
- package/profiles/coding/CLAUDE.md.hbs +1 -1
- package/profiles/default/CLAUDE.md +2 -2
- package/profiles/default/CLAUDE.md.hbs +2 -2
- package/profiles/executive-assistant/CLAUDE.md.hbs +1 -1
- package/profiles/health-coach/CLAUDE.md.hbs +1 -1
- package/telegram-plugin/auth-snapshot-format.ts +22 -24
- package/telegram-plugin/context-exhaustion.ts +124 -0
- package/telegram-plugin/dist/gateway/gateway.js +24086 -8727
- package/telegram-plugin/gateway/activity-card-store.ts +76 -0
- package/telegram-plugin/gateway/gateway.ts +480 -85
- package/telegram-plugin/gateway/inbound-delivery-gate.ts +26 -0
- package/telegram-plugin/gateway/model-command.ts +70 -10
- package/telegram-plugin/package.json +6 -0
- package/telegram-plugin/quota-watch.ts +4 -6
- package/telegram-plugin/registry/turns-schema.test.ts +97 -0
- package/telegram-plugin/registry/turns-schema.ts +78 -0
- package/telegram-plugin/render/ir.ts +209 -0
- package/telegram-plugin/render/parse.ts +363 -0
- package/telegram-plugin/render/render.ts +440 -0
- package/telegram-plugin/render/rich-render.ts +72 -0
- package/telegram-plugin/stream-controller.ts +14 -3
- package/telegram-plugin/tests/activity-card-store.test.ts +94 -0
- package/telegram-plugin/tests/auth-command-format2.test.ts +1 -1
- package/telegram-plugin/tests/auth-snapshot-format.test.ts +30 -16
- package/telegram-plugin/tests/claude-code-event-contract.test.ts +48 -0
- package/telegram-plugin/tests/feed-heartbeat-liveness-open.test.ts +11 -0
- package/telegram-plugin/tests/feed-survival.test.ts +39 -0
- package/telegram-plugin/tests/gateway-session-model-relaunch.test.ts +81 -0
- package/telegram-plugin/tests/inbound-emit-after-intercepts.test.ts +82 -0
- package/telegram-plugin/tests/liveness-tracker.test.ts +228 -0
- package/telegram-plugin/tests/model-command.test.ts +193 -16
- package/telegram-plugin/tests/narrative-render.test.ts +125 -0
- package/telegram-plugin/tests/orphaned-reply-rearm.test.ts +123 -163
- package/telegram-plugin/tests/quota-watch.test.ts +1 -4
- package/telegram-plugin/tests/rapid-fire-delivery-ordering.test.ts +149 -0
- package/telegram-plugin/tests/render/parse-torture.test.ts +136 -0
- package/telegram-plugin/tests/render/parse.test.ts +393 -0
- package/telegram-plugin/tests/render/render.test.ts +436 -0
- package/telegram-plugin/tests/render/rich-render.test.ts +85 -0
- package/telegram-plugin/tests/telegram-activity-visibility-integration.test.ts +155 -1
- package/telegram-plugin/tests/worktree-watch-cwds.test.ts +98 -3
- package/telegram-plugin/turn-liveness-floor.ts +35 -1
- package/telegram-plugin/uat/scenarios/jtbd-rich-formatting-render-dm.test.ts +99 -7
- package/telegram-plugin/worktree-watch-cwds.ts +92 -17
- package/vendor/hindsight-memory/scripts/lib/client.py +11 -1
- package/vendor/hindsight-memory/scripts/lib/config.py +9 -2
- package/vendor/hindsight-memory/scripts/recall.py +64 -6
- package/vendor/hindsight-memory/scripts/tests/test_recall_integration.py +1 -0
- package/vendor/hindsight-memory/tests/test_client.py +43 -0
- package/vendor/hindsight-memory/tests/test_recall_precision.py +114 -0
|
@@ -277,6 +277,82 @@ export async function runActivityCardBootReaper(args: {
|
|
|
277
277
|
return { finalized, vanished, unpinned, total: persisted.length }
|
|
278
278
|
}
|
|
279
279
|
|
|
280
|
+
/**
|
|
281
|
+
* Mid-session periodic orphan reaper (#2918). The boot reaper above only runs
|
|
282
|
+
* once at startup, so a card whose owning turn's process dies MID-session (SDK
|
|
283
|
+
* subprocess SIGKILL / OOM / crash) without a clean finalize stays frozen on
|
|
284
|
+
* its last "working…" frame until the NEXT gateway boot — hours later. This
|
|
285
|
+
* variant runs inside the LIVE gateway on a timer and finalizes ONLY records
|
|
286
|
+
* that are demonstrably orphaned:
|
|
287
|
+
*
|
|
288
|
+
* - `isLive(record)` — the caller's liveness predicate (gateway:
|
|
289
|
+
* `currentTurnMap.byKey.has(record.turnKey)` OR the singleton `currentTurn`
|
|
290
|
+
* mirror owns this topic). A record whose topic is still live is NEVER
|
|
291
|
+
* touched, so the currently-spinning card of an in-flight turn is safe.
|
|
292
|
+
* - age gate — `now - startedAt >= ttlMs`, a secondary guard so a card that
|
|
293
|
+
* JUST opened (before its turn populated the live map) is protected.
|
|
294
|
+
*
|
|
295
|
+
* Same AT-MOST-ONCE contract as the boot reaper: each record is deleted from
|
|
296
|
+
* the store BEFORE its finalize/unpin is attempted, and failures are swallowed
|
|
297
|
+
* without retry. The two reapers share `runOneCardFinalize` semantics via the
|
|
298
|
+
* identical delete-first ordering — a boot reaper and a mid-session sweep can
|
|
299
|
+
* never double-finalize the same message (whichever deletes the record first
|
|
300
|
+
* wins; the other sees an empty/short list).
|
|
301
|
+
*/
|
|
302
|
+
export async function runActivityCardMidSessionReaper(args: {
|
|
303
|
+
path: string
|
|
304
|
+
fs: ActivityCardStoreFsSeam
|
|
305
|
+
/** True IFF the record's topic is still owned by a live in-flight turn. */
|
|
306
|
+
isLive: (record: ActivityCardRecord) => boolean
|
|
307
|
+
ttlMs: number
|
|
308
|
+
now?: number
|
|
309
|
+
finalizeCard: (record: ActivityCardRecord) => Promise<unknown>
|
|
310
|
+
unpinCard: (record: ActivityCardRecord) => Promise<unknown>
|
|
311
|
+
log?: (line: string) => void
|
|
312
|
+
}): Promise<{ finalized: number; vanished: number; unpinned: number; total: number }> {
|
|
313
|
+
const log = args.log ?? ((l: string) => process.stderr.write(l))
|
|
314
|
+
const now = args.now ?? Date.now()
|
|
315
|
+
const cutoff = now - args.ttlMs
|
|
316
|
+
const persisted = loadActivityCards(args.path, args.fs)
|
|
317
|
+
// Only ownerless cards aged past the TTL. Liveness does the real work; the
|
|
318
|
+
// age gate only closes the just-opened-not-yet-tracked race window.
|
|
319
|
+
const stale = persisted.filter(
|
|
320
|
+
(r) => !args.isLive(r) && r.startedAt <= cutoff,
|
|
321
|
+
)
|
|
322
|
+
if (stale.length === 0) return { finalized: 0, vanished: 0, unpinned: 0, total: 0 }
|
|
323
|
+
let finalized = 0
|
|
324
|
+
let vanished = 0
|
|
325
|
+
let unpinned = 0
|
|
326
|
+
for (const record of stale) {
|
|
327
|
+
// Delete BEFORE the edit — the same idempotency guard the boot reaper uses.
|
|
328
|
+
clearActivityCardRecord(args.path, args.fs, record.turnKey, record.activityMessageId, log)
|
|
329
|
+
try {
|
|
330
|
+
const res = await args.finalizeCard(record)
|
|
331
|
+
if (res != null) finalized++
|
|
332
|
+
else vanished++
|
|
333
|
+
} catch (err) {
|
|
334
|
+
log(
|
|
335
|
+
`activity-card-store: mid-session reaper finalize failed ` +
|
|
336
|
+
`(chat=${record.chatId} msg=${record.activityMessageId}): ` +
|
|
337
|
+
`${(err as Error).message}\n`,
|
|
338
|
+
)
|
|
339
|
+
}
|
|
340
|
+
if (record.pinned) {
|
|
341
|
+
try {
|
|
342
|
+
await args.unpinCard(record)
|
|
343
|
+
unpinned++
|
|
344
|
+
} catch (err) {
|
|
345
|
+
log(
|
|
346
|
+
`activity-card-store: mid-session reaper unpin failed ` +
|
|
347
|
+
`(chat=${record.chatId} msg=${record.activityMessageId}): ` +
|
|
348
|
+
`${(err as Error).message}\n`,
|
|
349
|
+
)
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return { finalized, vanished, unpinned, total: stale.length }
|
|
354
|
+
}
|
|
355
|
+
|
|
280
356
|
/**
|
|
281
357
|
* Honest finalize text for an orphaned card — the single edit the boot
|
|
282
358
|
* reaper applies. Mirrors `silentEndFallbackText`'s honesty-about-elapsed
|