Builds on the prior commit by introducing the typed surfaces the rest of
the plugin (and `openclaw doctor`-style consumers) can reuse:
- `inspectTelegramUpdateOffset` returns a discriminated union
(`absent | valid | rotated`) so callers can act on the rotation event
without re-implementing the bot-id / fingerprint comparison.
`readTelegramUpdateOffset` is now a thin adapter over it.
- `TelegramOffsetRotationReason` is exported as a named type alias so
downstream code can switch over it exhaustively.
- New `TelegramOffsetRotationHandler` class encapsulates the
"log warning + delete stale file" side effect that the monitor needs at
startup, plus a `createTelegramOffsetRotationHandler` factory and a
pure `formatTelegramOffsetRotationMessage` helper used to keep the
wording consistent.
- `monitor.ts` now constructs the handler once per polling startup
instead of inlining the closure, and the new surfaces are re-exported
through `monitor-polling.runtime.ts`.
Unit coverage:
pnpm test extensions/telegram/src/update-offset-store.test.ts \
extensions/telegram/src/offset-rotation-handler.test.ts \
extensions/telegram/src/monitor.test.ts
Closes#80653.
Persist a non-reversible SHA-256 fingerprint of the bot token alongside the
bot id in the long-poll update offset store (version 3). On read, treat the
persisted offset as stale when the fingerprint diverges from the current
token, even when the bot id still matches. This covers the BotFather
`/revoke` case where the bot id is unchanged but the secret rotates -- the
in-process update tracker would otherwise silently skip any new updates
whose `update_id` is `<=` the restored watermark.
The legacy v2 (bot-id-only) layout still parses, and offsets are preserved
when the bot id matches so existing installs don't lose a watermark on
upgrade; the next persistence upgrades the file to v3 and enables rotation
detection going forward.
`readTelegramUpdateOffset` now reports each rotation through a new
`onRotationDetected` callback. `monitor.ts` uses it to log a clear warning
naming the previous/new bot id and the discarded offset, and to delete the
stale file rather than waiting for the first update to overwrite it.
Acceptance suites pass:
pnpm test extensions/telegram/src/update-offset-store.test.ts \
extensions/telegram/src/bot-update-tracker.test.ts \
extensions/telegram/src/monitor.test.ts \
extensions/telegram/src/bot.create-telegram-bot.test.ts \
extensions/telegram/src/token.test.ts \
extensions/telegram/src/polling-lease.test.ts
Add a post-install seam so the wizard can prompt the user to import their
existing Codex CLI state (skills, archived config/hooks, advisory cached
plugins) through the existing `openclaw migrate codex` flow once the
harness plugin is in place. Fires on both fresh installs and repair runs;
the user can decline at any time.
Trigger sites, both routing through one helper:
- src/plugins/provider-auth-choice.ts: after
`ensureCodexRuntimePluginForModelSelection` reports `installed: true`,
dynamically import `offerPostInstallMigrations` and call it before the
wizard moves on.
- src/commands/onboard-non-interactive/local/auth-choice.plugin-providers.ts:
same call shape with `nonInteractive: true`, so the helper emits a hint
line only and never mutates state.
Helper (src/wizard/setup.post-install-migration.ts) is generic, not
Codex-hardcoded — it resolves migration providers via the manifest
`migrationProviders` contract, filters to providers owned by plugins the
caller flags as installed in this onboarding step, runs `provider.detect`,
and on TTY hands accepted runs to `migrateDefaultCommand`. All detect,
prompt, and migrate failures are swallowed so onboarding never aborts on
this optional offer.
Also harden the Codex app-server subprocess lifecycle now that `detect()`
runs from a hotter onboarding path: isolate the plugin-install
`plugin/read` call (extensions/codex/src/migration/apply.ts) and have the
isolated request wait for child exit with a SIGKILL fallback
(extensions/codex/src/app-server/request.ts) so parents are not held open
by an orphaned codex binary.
Tests:
- src/wizard/setup.post-install-migration.test.ts (new, 10 cases)
- src/commands/onboard-non-interactive/local/auth-choice.plugin-providers.test.ts
extended with hint-call assertions and a not-required-no-offer case.
* fix(memory-core): prevent staged dream candidates from leaking into MEMORY.md
* fix(memory-core): correct PromotionComponents shape in dream-fence test fixture