switchroom 0.13.33 → 0.13.36
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/timezone-hook.sh +1 -1
- package/dist/agent-scheduler/index.js +8 -1
- package/dist/auth-broker/index.js +8 -1
- package/dist/cli/switchroom.js +176 -26
- package/dist/host-control/main.js +5222 -203
- package/dist/vault/approvals/kernel-server.js +9 -2
- package/dist/vault/broker/server.js +9 -2
- package/package.json +1 -1
- package/profiles/default/CLAUDE.md.hbs +1 -1
- package/telegram-plugin/dist/gateway/gateway.js +234 -31
- package/telegram-plugin/docs/waiting-ux-spec.md +40 -0
- package/telegram-plugin/gateway/config-approval-handler.test.ts +188 -1
- package/telegram-plugin/gateway/config-approval-handler.ts +170 -15
- package/telegram-plugin/gateway/diff-preview-card.test.ts +2 -2
- package/telegram-plugin/gateway/diff-preview-card.ts +2 -2
- package/telegram-plugin/gateway/drive-write-approval.test.ts +70 -0
- package/telegram-plugin/gateway/drive-write-approval.ts +51 -2
- package/telegram-plugin/gateway/error-envelope-card.ts +64 -0
- package/telegram-plugin/gateway/gateway.ts +112 -15
- package/telegram-plugin/gateway/ipc-protocol.ts +10 -1
- package/telegram-plugin/gateway/oversize-card-body.test.ts +108 -0
- package/telegram-plugin/gateway/oversize-card-body.ts +114 -0
- package/telegram-plugin/gateway/unhandled-rejection-policy.ts +46 -1
- package/telegram-plugin/hooks/silent-end-interrupt-stop.mjs +118 -41
- package/telegram-plugin/hooks/silent-end-scan.mjs +190 -0
- package/telegram-plugin/pending-work-progress.ts +37 -1
- package/telegram-plugin/tests/boot-clears-clean-shutdown-marker.test.ts +75 -0
- package/telegram-plugin/tests/error-envelope-unlock-card.test.ts +79 -0
- package/telegram-plugin/tests/pending-work-progress.test.ts +134 -0
- package/telegram-plugin/tests/silent-end-integration.test.ts +268 -0
- package/telegram-plugin/tests/silent-end-interrupt-stop-integration.test.ts +242 -0
- package/telegram-plugin/tests/silent-end-interrupt-stop-scan.test.ts +314 -0
- package/telegram-plugin/tests/silent-end.test.ts +227 -38
- package/telegram-plugin/tests/unhandled-rejection-policy.test.ts +51 -6
|
@@ -103,11 +103,6 @@ describe('classifyRejection — genuine errors still crash', () => {
|
|
|
103
103
|
expect(classifyRejection(err)).toBe('shutdown')
|
|
104
104
|
})
|
|
105
105
|
|
|
106
|
-
it('returns "shutdown" for GrammyError 429 (rate limit) — should be retried not masked', () => {
|
|
107
|
-
const err = grammyError(429, 'Too Many Requests: retry after 5')
|
|
108
|
-
expect(classifyRejection(err)).toBe('shutdown')
|
|
109
|
-
})
|
|
110
|
-
|
|
111
106
|
it('returns "shutdown" for GrammyError 400 with NEW unknown description', () => {
|
|
112
107
|
// Use a description that's not in the benign list — the policy is
|
|
113
108
|
// intentionally narrow so genuinely new bug categories still crash
|
|
@@ -115,9 +110,59 @@ describe('classifyRejection — genuine errors still crash', () => {
|
|
|
115
110
|
const err = grammyError(400, 'Bad Request: PHOTO_INVALID_DIMENSIONS')
|
|
116
111
|
expect(classifyRejection(err)).toBe('shutdown')
|
|
117
112
|
})
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
describe('classifyRejection — transient API errors (2026-05-25 follow-up)', () => {
|
|
116
|
+
// The pre-fix policy crashed on 429 + 5xx + network errors. That's
|
|
117
|
+
// wrong shape: those errors are already handled by retry-api-call.ts
|
|
118
|
+
// (3 attempts with backoff). When one leaks past the retry policy —
|
|
119
|
+
// either because the caller didn't wrap, or because 3 sustained
|
|
120
|
+
// attempts all failed — crashing the gateway is the worst outcome
|
|
121
|
+
// (one bad packet = visible "agent-crashed" banner + restart loop
|
|
122
|
+
// risk). log_only matches the daemon-stays-up posture.
|
|
123
|
+
//
|
|
124
|
+
// Surfaced 2026-05-25 on clerk: a sendMessage hit 429 after exhausting
|
|
125
|
+
// retries, the rejection bubbled to the unhandledRejection handler,
|
|
126
|
+
// shutdown fired, operator-event banner posted, "clerk seems to be
|
|
127
|
+
// crashing" user-visible.
|
|
128
|
+
|
|
129
|
+
it('returns "log_only" for GrammyError 429 (rate limit) — already handled by retry-api-call', () => {
|
|
130
|
+
const err = grammyError(429, 'Too Many Requests: retry after 5')
|
|
131
|
+
expect(classifyRejection(err)).toBe('log_only')
|
|
132
|
+
})
|
|
118
133
|
|
|
119
|
-
it('returns "
|
|
134
|
+
it('returns "log_only" for GrammyError 500 (server error)', () => {
|
|
120
135
|
const err = grammyError(500, 'Internal Server Error')
|
|
136
|
+
expect(classifyRejection(err)).toBe('log_only')
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
it('returns "log_only" for GrammyError 502 (Bad Gateway)', () => {
|
|
140
|
+
const err = grammyError(502, 'Bad Gateway')
|
|
141
|
+
expect(classifyRejection(err)).toBe('log_only')
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
it('returns "log_only" for GrammyError 503 (Service Unavailable)', () => {
|
|
145
|
+
const err = grammyError(503, 'Service Unavailable')
|
|
146
|
+
expect(classifyRejection(err)).toBe('log_only')
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
it('returns "log_only" for HttpError (network failure) via injected detector', () => {
|
|
150
|
+
// Real grammy HttpError surfaces as e.g. "Network request for
|
|
151
|
+
// 'sendMessage' failed!" wrapping ECONNRESET / ETIMEDOUT / fetch
|
|
152
|
+
// failed. We inject the detector so this test doesn't depend on
|
|
153
|
+
// grammy internals; the production path uses `err instanceof
|
|
154
|
+
// HttpError`.
|
|
155
|
+
const fakeHttp = new Error("Network request for 'sendMessage' failed!")
|
|
156
|
+
expect(
|
|
157
|
+
classifyRejection(fakeHttp, { isHttpError: () => true }),
|
|
158
|
+
).toBe('log_only')
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
it('still returns "shutdown" for GrammyError 403 (forbidden) — must not be masked', () => {
|
|
162
|
+
// 401 (covered above at line 101) and 403 are NOT transient — they
|
|
163
|
+
// indicate a genuine configuration bug (revoked bot token, removed
|
|
164
|
+
// from chat) and must crash so systemd surfaces the failure.
|
|
165
|
+
const err = grammyError(403, 'Forbidden: bot was blocked by the user')
|
|
121
166
|
expect(classifyRejection(err)).toBe('shutdown')
|
|
122
167
|
})
|
|
123
168
|
})
|