Skip to content

Packs: repair older packs, plugin scope refs, OAuth tokens stay local - #351

Merged
fylorn merged 1 commit into
feat/sync-backupfrom
feat/pack-followups
Oct 19, 2026
Merged

fylorn merged 1 commit into
feat/sync-backupfrom
feat/pack-followups

Conversation

@fylorn

@fylorn fylorn commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

Follow-ups to #348 and #349.

  • Older packs: when the configuration in a pack does not read and the pack is not from a newer core, it is repaired in memory by the one-click repair rules (an unknown field is removed, an unknown value goes back to its default) and then previewed and imported as usual. ImportPreview.repairs and RestorePreview.repairs (ConfigFix[]) list what was repaired; a backup kept before an upgrade gets the same treatment. A pack from a newer core is still pack.too_new. The CLI prints the repairs too.
  • Plugin scope: the upstreams a plugin's match.upstreams names are references of the plugin. Exporting a plugin brings them, skipping one of them on import refuses the plugin (import.skipped_reference), renaming one rewrites the scope in the plugin file. Wildcard patterns (relay-*) are not references, and a named upstream that is neither here nor in the pack is not an error for a plugin.
  • OAuth upstreams: the gateway writes back a rotated refresh token (tw_gateway::oauth), so the same token on two devices invalidates the other. oauth.refresh, access and expires_at now stay on the device, like a ChatGPT sign-in: they are not in a snapshot or an export (omitted_logins names the upstream), an overwrite keeps the local tokens when the token endpoint is the same, a new OAuth upstream arrives disabled and flagged missing_key, and a restore of an upstream that is no longer here takes its tokens from the restored version. A rotation no longer changes the content id.
  • control.config_not_repairable is replaced by control.config_unrepairable, which points at restoring a backup.

Local runs: cargo fmt --check, cargo clippy --workspace --all-targets -D warnings (stable and 1.99), cargo test --workspace (3680 passed), the TypeScript export through tsc --strict, scripts/smoke.sh (84 passed).

🤖 Generated with Claude Code

- A pack exported by an older version whose config does not read is
  repaired in memory by the one-click repair rules (unknown fields
  removed, unknown values back to the default) before preview and import;
  ImportPreview and RestorePreview list the repairs. A pack from a newer
  core is still too new.
- A plugin's scope (match.upstreams) refers to the upstreams it names, so
  an export brings them, skipping one refuses the plugin on import, and a
  rename follows. Wildcard patterns are not references, and an upstream
  that is nowhere is not an error for a plugin.
- OAuth upstreams: the refresh token rotates (the gateway writes back the
  new one), so the tokens stay on the device like a ChatGPT sign-in. They
  are not exported, an overwrite keeps the local ones when the token
  endpoint is the same, a new one arrives disabled and flagged
  missing_key, and a restore brings back the tokens of an upstream that
  is no longer here from the version restored.
- control.config_not_repairable becomes control.config_unrepairable and
  points at restoring a backup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@fylorn
fylorn merged commit 23d64a4 into feat/sync-backup Oct 19, 2026
7 checks passed
@fylorn
fylorn deleted the feat/pack-followups branch October 19, 2026 02:43
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 19, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant