switchroom 0.19.31 → 0.19.33
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/auth-broker/index.js +112 -6
- package/dist/cli/switchroom.js +177 -34
- package/dist/host-control/main.js +289 -27
- package/dist/vault/approvals/kernel-server.js +112 -6
- package/dist/vault/broker/server.js +112 -6
- package/package.json +1 -1
- package/telegram-plugin/dist/bridge/bridge.js +3 -0
- package/telegram-plugin/dist/gateway/gateway.js +434 -187
- package/telegram-plugin/dist/server.js +3 -0
- package/telegram-plugin/gateway/stale-pin-sweep-store.ts +14 -8
- package/telegram-plugin/gateway/stale-pin-sweep.test.ts +106 -1
- package/telegram-plugin/gateway/stale-pin-sweep.ts +156 -47
- package/telegram-plugin/gateway/status-pin-store.ts +44 -11
- package/telegram-plugin/gateway/stream-render.ts +578 -321
- package/telegram-plugin/session-tail.ts +13 -0
- package/telegram-plugin/tests/status-pin-store.test.ts +62 -6
- package/telegram-plugin/tests/stream-render-golden.test.ts +20 -5
- package/telegram-plugin/tests/turn-mint-defers-until-dequeue.test.ts +196 -0
- package/telegram-plugin/tests/turn-mint-harness.ts +155 -0
- package/telegram-plugin/tests/turn-supersede-finalizes-prior-card.test.ts +124 -0
- package/vendor/hindsight-memory/scripts/subagent_retain.py +30 -7
- package/vendor/hindsight-memory/scripts/tests/test_subagent_retain.py +100 -2
- package/vendor/hindsight-memory/settings.json +1 -1
|
@@ -117,19 +117,43 @@ export interface PersistedStatusPin {
|
|
|
117
117
|
* re-fail on every boot forever. */
|
|
118
118
|
export const BOOT_UNPIN_MAX_ATTEMPTS = 5
|
|
119
119
|
|
|
120
|
-
/**
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
120
|
+
/**
|
|
121
|
+
* Envelope version. v1 had no `pending` field; a v1 row loads as a confirmed
|
|
122
|
+
* pin (pending undefined). v2 adds the optional `pending` flag. v3 adds the
|
|
123
|
+
* optional `pinnedAt` claim timestamp (#3810). v4 adds the optional `threadId`
|
|
124
|
+
* so the claim is keyed by (chat, thread) and a forum topic can be drained
|
|
125
|
+
* after a crash.
|
|
126
|
+
*
|
|
127
|
+
* ── The bump rule, which the reader depends on (#3957) ───────────────────────
|
|
128
|
+
*
|
|
129
|
+
* EVERY field added since v1 is OPTIONAL, and every future bump must keep that
|
|
130
|
+
* property. That is what makes the versions mutually readable in both
|
|
131
|
+
* directions, and {@link loadStatusPins} now cashes it in: an envelope whose
|
|
132
|
+
* version this build does not know is still READ, row by row, through the same
|
|
133
|
+
* structural validator. Rows it cannot validate are dropped; rows it can are
|
|
134
|
+
* kept.
|
|
135
|
+
*
|
|
136
|
+
* Why that matters more than it looks: this file is the boot cleanup's only
|
|
137
|
+
* record of which messages the gateway pinned. A reader that discarded the
|
|
138
|
+
* whole file on an unfamiliar version turned every pin taken by the newer build
|
|
139
|
+
* into a permanent orphan the moment an operator rolled back — manufacturing
|
|
140
|
+
* exactly the bug this subsystem exists to prevent. Degrading (keep what
|
|
141
|
+
* validates) is strictly safer than failing open to `[]` here, because the
|
|
142
|
+
* fail-open outcome is not "do nothing", it is "forget an obligation".
|
|
143
|
+
*
|
|
144
|
+
* A bump that ever needs to be NON-additive — a field whose absence changes the
|
|
145
|
+
* meaning of a row — must therefore change the FILENAME, not just `v`, so old
|
|
146
|
+
* readers see "no file" rather than misreading rows. Do not quietly break the
|
|
147
|
+
* additive rule and leave `v` to carry it.
|
|
148
|
+
*/
|
|
127
149
|
interface SnapshotEnvelope {
|
|
128
|
-
v:
|
|
150
|
+
v: number
|
|
129
151
|
pins: PersistedStatusPin[]
|
|
130
152
|
}
|
|
131
153
|
|
|
132
|
-
|
|
154
|
+
/** The version THIS build writes. Reading is deliberately version-tolerant
|
|
155
|
+
* (see above); only the writer is pinned. */
|
|
156
|
+
const SNAPSHOT_VERSION = 4
|
|
133
157
|
|
|
134
158
|
function isPinRow(x: unknown): x is PersistedStatusPin {
|
|
135
159
|
if (x == null || typeof x !== 'object') return false
|
|
@@ -153,6 +177,13 @@ function isPinRow(x: unknown): x is PersistedStatusPin {
|
|
|
153
177
|
* file (fail-open to empty: a corrupt snapshot must never crash boot — worst
|
|
154
178
|
* case an orphaned pin isn't cleaned up this boot, strictly no worse than the
|
|
155
179
|
* pre-persistence behaviour).
|
|
180
|
+
*
|
|
181
|
+
* An UNRECOGNISED envelope version is NOT malformed and does not fail open
|
|
182
|
+
* (#3957). Any positive-integer `v` with an array of `pins` is read, and each
|
|
183
|
+
* row is kept iff {@link isPinRow} can structurally validate it. A row written
|
|
184
|
+
* by a newer build therefore survives a downgrade instead of being discarded
|
|
185
|
+
* into a permanent orphan — see the {@link SnapshotEnvelope} bump rule for the
|
|
186
|
+
* additive-fields property this relies on.
|
|
156
187
|
*/
|
|
157
188
|
export function loadStatusPins(
|
|
158
189
|
path: string,
|
|
@@ -173,7 +204,9 @@ export function loadStatusPins(
|
|
|
173
204
|
}
|
|
174
205
|
if (parsed == null || typeof parsed !== 'object') return []
|
|
175
206
|
const env = parsed as Record<string, unknown>
|
|
176
|
-
|
|
207
|
+
// Version-TOLERANT, structurally strict: an unknown `v` still yields the rows
|
|
208
|
+
// that validate. Only a shape that is not an envelope at all fails open.
|
|
209
|
+
if (!Number.isInteger(env.v) || (env.v as number) < 1 || !Array.isArray(env.pins)) return []
|
|
177
210
|
return env.pins.filter(isPinRow)
|
|
178
211
|
}
|
|
179
212
|
|
|
@@ -189,7 +222,7 @@ export function persistStatusPins(
|
|
|
189
222
|
snapshot: readonly PersistedStatusPin[],
|
|
190
223
|
log: (line: string) => void = (l) => process.stderr.write(l),
|
|
191
224
|
): void {
|
|
192
|
-
const env: SnapshotEnvelope = { v:
|
|
225
|
+
const env: SnapshotEnvelope = { v: SNAPSHOT_VERSION, pins: [...snapshot] }
|
|
193
226
|
const tmp = path + '.tmp'
|
|
194
227
|
try {
|
|
195
228
|
fs.writeFileSync(tmp, JSON.stringify(env))
|