release: v0.7.0 — extension restructure complete (Plan C Phases 3/4/6)

Completes the extension restructure begun in v0.6.0. Phases 3 (setup
wizard SW migration + step registry), 4 (vault.ts split + vault_locked
lift), and 6 (get_vault_status + sidebar status indicator) all merged to
main (9df2fee, 3b8368d, 397cc78) via three parallel worktree streams.

This commit is the release-prep wrap-up:
- Version bump to v0.7.0 across the three relicario crates + Cargo.lock,
  extension/package.json, and both extension manifests (the manifests had
  lagged at 0.5.0 — corrected here).
- CHANGELOG.md v0.7.0 entry.
- STATUS.md: extension restructure moved to shipped; Phases 3/4/6 landing
  section added.
- ROADMAP.md: v0.7.0 row added; Up-next now command palette.
- extension/ARCHITECTURE.md: all three phases integrated (new vault-*
  modules, setup-steps.ts, get_vault_status protocol + status indicator,
  vault_locked lift, git-host sync cache).
- Plan completion checkboxes ticked.

Task 7.1 verification: done-criteria sweep all green; 423/423 vitest;
build:all clean (only the pre-existing 4MB WASM size warning).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
adlee-was-taken
2026-05-31 22:50:17 -04:00
parent 397cc78b86
commit 33c3752f85
12 changed files with 195 additions and 52 deletions

View File

@@ -1,5 +1,69 @@
# Changelog # Changelog
## v0.7.0 — 2026-06-01
Completes the extension restructure (Plan C) begun under v0.6.0. Phases
1/2/5 (StateHost typing, SW storage extract, the P2 cluster) shipped
2026-05-30; this tag adds the remaining three phases — executed as three
parallel worktree streams under PM coordination — which eliminate the
two steepest learning cliffs in the extension and close the last
`relicario status` CLI/extension parity gap. No crypto, wire-format, or
Rust-API changes; this is an internal-architecture + one-feature release.
### Added
- **`relicario status` parity in the extension.** New `get_vault_status`
service-worker message returns a cached sync summary
`{ ahead, behind, lastSyncAt, pendingItems }` with no network call —
`ahead`/`behind`/`lastSyncAt` read straight off the cached git-host
state (populated by the `sync` handler), `pendingItems` a live count of
active (non-trashed) manifest entries. A sidebar-footer status indicator
(`vault-status.ts``renderStatusIndicator`) renders `N pending` /
`N ahead` / `N behind` / `in sync` plus a `last sync …` / `never synced`
line, refreshed on mount and on a manual `↻` button — no timer polling,
matching the no-network-without-user-intent discipline.
### Changed
- **Setup wizard crypto moved into the service worker.** The wizard no
longer imports `relicario-wasm` or orchestrates the master key directly.
New `create_vault` / `attach_vault` SW handlers own the full flow
(image-secret embed/extract, unlock, manifest+settings encrypt + push,
`register_device` + `addDevice`, persist config + reference image,
`session.setCurrent`); on failure the SessionHandle is locked then freed,
with ownership transferring only on success. `setup.ts` collapses from
~1230 LOC to a 58-LOC UI-only shell; the six render/attach step pairs
become a `SetupStep` registry in the new `setup/setup-steps.ts`. Adds
`clearWizardState` (bound to `beforeunload` and `goto('mode')`) to wipe
sensitive Uint8Array fields when the wizard is abandoned. The
non-extension copy-vault-config-JSON escape hatch is preserved.
- **`vault.ts` split from a 1037-LOC monolith to 194 LOC of routing +
state.** Extracted into five focused modules — `vault-shell` (DOM
scaffolding, color-scheme, onMessage wiring), `vault-sidebar` (category
nav, 80ms debounced search, bottom nav, status-indicator footer),
`vault-list` (list + row rendering), `vault-drawer` (open/close/render +
`ensureDrawerClosedForRoute`), `vault-form-wrapper` (wrapped form + sticky
bar) — plus two support modules for an acyclic split (`vault-context`,
the VaultController contract; `vault-router`, hash routing + pane
dispatch).
- **`vault_locked` RPC intercept unified.** Lifted out of `vault.ts` into
the `sendMessage` wrapper in `shared/state.ts`, so both popup and
vault-tab surfaces share one lock-redirect path.
- **`state.gitHost` now nulled on explicit lock**, symmetric with the
session-timer expiry path, so the new status indicator can't surface a
stale `lastSyncAt` after a lock → re-unlock within one service-worker
lifetime.
### Internal
- Three-stream parallel execution (Dev-A Phase 3, Dev-B Phase 4, Dev-C
Phase 6) coordinated via the relay message bus; merges sequenced
Phase 3 → 4 → 6 with per-phase done-criteria verification.
- Final merged-tree validation: **423/423** vitest (62 files);
`npm run build:all` clean for both Chrome and Firefox targets (only the
pre-existing ~4 MB WASM asset-size warning). Task 7.1 done-criteria
sweep all green. No change to `wasm.d.ts`.
## v0.6.0 — 2026-05-30 ## v0.6.0 — 2026-05-30
Rolls up four weeks of post-v0.5.0 work into one tag: the Phase 2B Rolls up four weeks of post-v0.5.0 work into one tag: the Phase 2B

6
Cargo.lock generated
View File

@@ -2156,7 +2156,7 @@ checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
[[package]] [[package]]
name = "relicario-cli" name = "relicario-cli"
version = "0.6.0" version = "0.7.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"arboard", "arboard",
@@ -2185,7 +2185,7 @@ dependencies = [
[[package]] [[package]]
name = "relicario-core" name = "relicario-core"
version = "0.6.0" version = "0.7.0"
dependencies = [ dependencies = [
"argon2", "argon2",
"base64", "base64",
@@ -2231,7 +2231,7 @@ dependencies = [
[[package]] [[package]]
name = "relicario-wasm" name = "relicario-wasm"
version = "0.6.0" version = "0.7.0"
dependencies = [ dependencies = [
"base64", "base64",
"ed25519-dalek", "ed25519-dalek",

View File

@@ -7,6 +7,7 @@
| Version | Highlights | | Version | Highlights |
|---|---| |---|---|
| v0.7.0 *(2026-06-01)* | Extension restructure (Plan C) complete — Phases 3/4/6 merged via 3 parallel worktree streams under PM coordination: setup wizard crypto migrated into the SW (`create_vault`/`attach_vault`; `setup.ts` 1230→58 LOC + step registry); `vault.ts` split 1037→194 LOC into 5 focused + 2 support modules; `vault_locked` intercept lifted into `shared/state.ts`; `get_vault_status` SW message + sidebar status indicator closing the last `relicario status` CLI/extension parity gap |
| v0.6.0 *(2026-05-30)* | Security audit fixes; device authentication; backup/restore + LastPass import; fullscreen UX Phases 1+2A+2B; v0.5.1 Streams A/B/C (3-column vault layout + bottom-sheet picker + toast system; left-nav settings; Recovery QR end-to-end + setup wizard Style C); 1C-γ (attachments + Document type + device registration + trash + field history); Plan B multi-stream refactor (commands/ split, prompt_or_flag, core/WASM seam); vault-tab management surfaces revamp (settings synced/local split, devices fingerprint, trash purge countdown, field-history polish, item-history-index, `#history/<id>` routing); doc-structure redesign (rename to DESIGN/CRYPTO/docs/FORMATS, scope headers + Next: footers); GPL-3.0-or-later license | | v0.6.0 *(2026-05-30)* | Security audit fixes; device authentication; backup/restore + LastPass import; fullscreen UX Phases 1+2A+2B; v0.5.1 Streams A/B/C (3-column vault layout + bottom-sheet picker + toast system; left-nav settings; Recovery QR end-to-end + setup wizard Style C); 1C-γ (attachments + Document type + device registration + trash + field history); Plan B multi-stream refactor (commands/ split, prompt_or_flag, core/WASM seam); vault-tab management surfaces revamp (settings synced/local split, devices fingerprint, trash purge countdown, field-history polish, item-history-index, `#history/<id>` routing); doc-structure redesign (rename to DESIGN/CRYPTO/docs/FORMATS, scope headers + Next: footers); GPL-3.0-or-later license |
| v0.2.0 | Typed-item rewrite (Plans 1A/1B/1C-α/β₁/β₂) | | v0.2.0 | Typed-item rewrite (Plans 1A/1B/1C-α/β₁/β₂) |
@@ -14,15 +15,13 @@ See `CHANGELOG.md` for tagged-release detail and `STATUS.md` for the per-train c
## Up next ## Up next
Per the 2026-05-30 post-v0.6.0 audit: of the three 2026-05-04 architecture-review specs, two are already shipped (CLI restructure = Plan B Cycles 1+2; security polish = Stream A Cycle 1). Only the third is genuinely outstanding: All three 2026-05-04 architecture-review specs are now shipped (CLI restructure = Plan B Cycles 1+2; security polish = Stream A Cycle 1; extension restructure = Plan C Phases 16, completed v0.7.0 2026-06-01). The next committed item is:
- **Extension restructure** — half-shipped 2026-05-30. Phases 1 (StateHost typing) + 2 (SW storage extract) + 5 (P2 cluster) merged via 3 parallel worktrees. Remaining: Phase 3 (setup wizard SW migration, L), Phase 4 (vault.ts split, M), Phase 6 (vault status indicator, S-M). - **Phase 4: command palette** — ⌘K global search + action dispatch across the vault tab (no spec yet)
Spec: `docs/superpowers/specs/2026-05-04-extension-restructure-design.md`
Plan: `docs/superpowers/plans/2026-05-30-extension-restructure.md`
## Medium-term ## Medium-term
- **Phase 4: command palette** — ⌘K global search + action dispatch across the vault tab (no spec yet) _(promote here once specced)_
## Long-term / backlog ## Long-term / backlog

View File

@@ -5,7 +5,7 @@
## Version ## Version
**Last release tagged:** v0.6.0 — rolled up Phase 2B, v0.5.1 Streams A/B/C, 1C-γ, Plan B refactor (Cycles 1+2), management-surfaces revamp, and the doc-structure redesign into one tag. **Last release tagged:** v0.6.0 — rolled up Phase 2B, v0.5.1 Streams A/B/C, 1C-γ, Plan B refactor (Cycles 1+2), management-surfaces revamp, and the doc-structure redesign into one tag.
**Active track:** extension restructure execution — Plan C Phases 1, 2, 5 merged 2026-05-30 (three parallel worktree streams). Phases 3, 4, 6 remain. **Active track:** **extension restructure (Plan C) — COMPLETE.** All six phases merged. Phases 1, 2, 5 merged 2026-05-30; Phases 3, 4, 6 merged 2026-05-31/06-01 via three parallel worktree streams (Dev-A/B/C under PM coordination). Versions bumped to v0.7.0; tag pending.
## What landed on main since the v0.5.0 version bump ## What landed on main since the v0.5.0 version bump
@@ -98,6 +98,19 @@ Plan: `docs/superpowers/plans/2026-05-24-vault-tab-management-surfaces-revamp.md
- Item-history-index pane — top-level "items with history" list (`32e1632`) - Item-history-index pane — top-level "items with history" list (`32e1632`)
- Sidebar slot wiring + `#history/<id>` route with `#field-history/<id>` legacy normalization (`88d7228`) - Sidebar slot wiring + `#history/<id>` route with `#field-history/<id>` legacy normalization (`88d7228`)
### Extension restructure — Plan C Phases 3, 4, 6 (merged 2026-05-31 → 06-01, v0.7.0)
Spec: `docs/superpowers/specs/2026-05-04-extension-restructure-design.md`
Plan: `docs/superpowers/plans/2026-05-30-extension-restructure.md`
Three parallel worktree streams under PM coordination (relay-bus), completing the restructure begun with Phases 1/2/5:
- **Phase 3 — setup wizard SW migration + step registry** (Dev-A, merge `9df2fee`). `create_vault` / `attach_vault` SW handlers own the full vault-creation/attach flow (embed/unlock, encrypt+push, register_device+addDevice, persist config+image, `session.setCurrent`; failure path locks+frees the handle). `setup.ts` collapses 1230→58 LOC (UI-only shell, no `relicario-wasm` import); step registry + state + `clearWizardState` + `finishSetup` extracted to new `setup/setup-steps.ts`. `clearWizardState` bound to `beforeunload` + `goto('mode')`. Copy-vault-JSON escape hatch preserved.
- **Phase 4 — vault.ts split + vault_locked lift** (Dev-B, merge `3b8368d`). `vault.ts` 1037→194 LOC. Five named modules (`vault-shell`, `vault-sidebar`, `vault-list`, `vault-drawer`, `vault-form-wrapper`) plus two support modules (`vault-context` — the VaultController contract; `vault-router` — hash routing + pane dispatch, to hold vault.ts ≤250). `vault_locked` RPC intercept lifted into `shared/state.ts`'s `sendMessage` wrapper. 80ms debounced sidebar search (`SEARCH_DEBOUNCE_MS`); `ensureDrawerClosedForRoute`; `#vault-status-slot` footer staged for Phase 6.
- **Phase 6 — get_vault_status + sidebar status indicator** (Dev-C, merge `397cc78`). `get_vault_status` SW handler returns cached `{ahead, behind, lastSyncAt, pendingItems}` with no network call; `vault-status.ts` renders the sidebar-footer indicator (`renderStatusIndicator` into `#vault-status-slot`, refreshed on mount + manual `↻` button, no timer polling). Closes the last `relicario status` CLI/extension parity gap. Also nulls `state.gitHost` on the explicit `lock` handler (symmetric with session-expiry) so the indicator can't show a stale `lastSyncAt`.
Final merged-tree validation: **423/423 vitest** (62 files), `build:all` clean (only the pre-existing 4MB WASM size warning). Task 7.1 done-criteria sweep: all green.
### Doc-structure redesign (2026-05-30, complete) ### Doc-structure redesign (2026-05-30, complete)
Spec: `docs/superpowers/specs/2026-05-30-doc-structure-redesign-design.md` Spec: `docs/superpowers/specs/2026-05-30-doc-structure-redesign-design.md`
@@ -128,15 +141,8 @@ Per the 2026-05-30 post-v0.6.0 audit of the three 2026-05-04 architecture-review
- **CLI restructure** (`2026-05-04-cli-restructure-design.md`) — *already shipped* as Plan B Cycles 1+2 (`b9bd152`, `3dd1e1b`, `3759f6a`, `e69b347`); the last gap (read-side `refresh_groups_cache` callers in list/get) closed in `d717f0d`. Done-criteria all met. - **CLI restructure** (`2026-05-04-cli-restructure-design.md`) — *already shipped* as Plan B Cycles 1+2 (`b9bd152`, `3dd1e1b`, `3759f6a`, `e69b347`); the last gap (read-side `refresh_groups_cache` callers in list/get) closed in `d717f0d`. Done-criteria all met.
- **Security polish** (`2026-05-04-security-polish-design.md`) — *already shipped* as Stream A Cycle 1 (`89090a8`) plus follow-ups (`0c9387f` start.sh fourth window, `229e483` recovery_qr.rs docs). All four phases done. - **Security polish** (`2026-05-04-security-polish-design.md`) — *already shipped* as Stream A Cycle 1 (`89090a8`) plus follow-ups (`0c9387f` start.sh fourth window, `229e483` recovery_qr.rs docs). All four phases done.
- **Extension restructure** (`2026-05-04-extension-restructure-design.md`, plan `docs/superpowers/plans/2026-05-30-extension-restructure.md`) — half-shipped: - **Extension restructure** (`2026-05-04-extension-restructure-design.md`, plan `docs/superpowers/plans/2026-05-30-extension-restructure.md`) — **COMPLETE** (all six phases merged; see the dated landing section above). Phases 1/2/5 merged 2026-05-30; Phases 3/4/6 merged 2026-05-31 → 06-01. Final tree: 423/423 vitest, build:all clean. v0.7.0 versions bumped; tag pending.
-**Phase 1 (StateHost typing)** — merged `c3f8e35` (4 commits, 378/378 tests). View+PopupState moved to `shared/popup-state.ts`; `StateHost` interface fully typed; `__resetHostForTests` exported; double-registration guard. PopupState widened to absorb VaultState's vault-tab-only fields.
-**Phase 2 (SW storage extract)** — merged `b6707f4` (1 commit, 376/376 tests). `loadDeviceSettings` / `saveDeviceSettings` / `loadBlacklist` / `saveBlacklist` consolidated in `service-worker/storage.ts`; `itemToManifestEntry` moved to `service-worker/vault.ts`. Router files shrank ~70 LOC combined.
-**Phase 5 (P2 cluster)** — merged `0496dfe` (5 commits, 377/377 tests). Inactivity timer rule inverted (READ_ONLY_CONTENT_CALLABLE exclusion set); `state.gitHost` cleared on session expiry; `teardownSettingsCommon` extracted; `Promise.allSettled` in devices (trash.ts was a no-op — single-message load path on current main); MutationObserver `scan()` debounced 200ms.
-**Phase 3 (Setup wizard SW migration + step registry)** — Effort: L. Depends on Phase 1 ✅. Biggest single phase. Adds `create_vault` / `attach_vault` SW handlers; setup.ts drops direct WASM imports + collapses six renderStepN/attachStepN pairs into a step registry + adds `clearWizardState`.
-**Phase 4 (vault.ts split + vault_locked channel lift)** — Effort: M. Depends on Phase 1 ✅. Splits 1037-LOC vault.ts into 5 modules (vault-shell, vault-sidebar, vault-list, vault-drawer, vault-form-wrapper); lifts the vault_locked RPC intercept into shared/state.ts's sendMessage wrapper.
-**Phase 6 (get_vault_status + sidebar status indicator)** — Effort: S-M. Depends on Phase 4. Closes the `relicario status` CLI/extension parity gap.
- Combined test count at end of three-stream merge: **389/389** vitest passing (baseline 371 + 18 new across the three phases).
Beyond extension restructure, ROADMAP medium-term holds Phase 4 command palette (no spec yet). Long-term: relay server, mobile. Beyond extension restructure, ROADMAP medium-term holds Phase 4 command palette (no spec yet). Long-term: relay server, mobile.
See `ROADMAP.md` for the longer arc and `CHANGELOG.md` for tagged-release history (current head: `v0.5.0` entry, dated 2026-05-02 — predates the v0.5.1 train work and will be revised when the next tag cuts). See `ROADMAP.md` for the longer arc and `CHANGELOG.md` for tagged-release history (current head: `v0.6.0`; the `v0.7.0` entry covers this extension-restructure completion).

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "relicario-cli" name = "relicario-cli"
version = "0.6.0" version = "0.7.0"
edition = "2021" edition = "2021"
description = "CLI for relicario password manager" description = "CLI for relicario password manager"
license = "GPL-3.0-or-later" license = "GPL-3.0-or-later"

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "relicario-core" name = "relicario-core"
version = "0.6.0" version = "0.7.0"
edition = "2021" edition = "2021"
description = "Core library for relicario password manager" description = "Core library for relicario password manager"
license = "GPL-3.0-or-later" license = "GPL-3.0-or-later"

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "relicario-wasm" name = "relicario-wasm"
version = "0.6.0" version = "0.7.0"
edition = "2021" edition = "2021"
description = "WASM bindings for relicario password manager" description = "WASM bindings for relicario password manager"
license = "GPL-3.0-or-later" license = "GPL-3.0-or-later"

View File

@@ -2627,13 +2627,13 @@ git push origin main
## Completion Checklist ## Completion Checklist
- [ ] Phase 1: `StateHost` typed end-to-end (Tasks 1.1-1.5) - [x] Phase 1: `StateHost` typed end-to-end (Tasks 1.1-1.5) — merged 2026-05-30
- [ ] Phase 2: SW helpers consolidated in `storage.ts` + `vault.ts` (Tasks 2.1-2.3) - [x] Phase 2: SW helpers consolidated in `storage.ts` + `vault.ts` (Tasks 2.1-2.3) — merged 2026-05-30
- [ ] Phase 3: Setup wizard SW-orchestrated + step registry + `clearWizardState` (Tasks 3.1-3.7) - [x] Phase 3: Setup wizard SW-orchestrated + step registry + `clearWizardState` (Tasks 3.1-3.7) — merged `9df2fee` 2026-05-31
- [ ] Phase 4: `vault.ts` split into 5 modules + `vault_locked` channel unified (Tasks 4.1-4.7) - [x] Phase 4: `vault.ts` split into 5 modules + `vault_locked` channel unified (Tasks 4.1-4.7) — merged `3b8368d` 2026-06-01
- [ ] Phase 5: Five P2 fixes (Tasks 5.1-5.5) - [x] Phase 5: Five P2 fixes (Tasks 5.1-5.5) — merged 2026-05-30
- [ ] Phase 6: `get_vault_status` + sidebar status indicator (Tasks 6.1-6.3) - [x] Phase 6: `get_vault_status` + sidebar status indicator (Tasks 6.1-6.3) — merged `397cc78` 2026-06-01
- [ ] Task 7.1: Final verification + STATUS/ROADMAP update - [x] Task 7.1: Final verification + STATUS/ROADMAP update — done-criteria sweep all green; 423/423 vitest; build:all clean; STATUS/ROADMAP/CHANGELOG/ARCHITECTURE updated; versions bumped to v0.7.0
--- ---

View File

@@ -37,7 +37,7 @@ Firefox build (the vault tab is Chrome-only for the moment). Verify in
| `service-worker` | `src/service-worker/index.ts` | extension SW / bg | yes — initialized lazily on first message | | `service-worker` | `src/service-worker/index.ts` | extension SW / bg | yes — initialized lazily on first message |
| `popup` | `src/popup/popup.ts` | popup.html | no — goes through SW | | `popup` | `src/popup/popup.ts` | popup.html | no — goes through SW |
| `vault` | `src/vault/vault.ts` (Chrome only) | vault.html (tab) | no — goes through SW | | `vault` | `src/vault/vault.ts` (Chrome only) | vault.html (tab) | no — goes through SW |
| `setup` | `src/setup/setup.ts` | setup.html (tab) | yes — direct dynamic import (predates SW handle) | | `setup` | `src/setup/setup.ts` | setup.html (tab) | no — goes through SW (`create_vault`/`attach_vault`) |
| `content` | `src/content/detector.ts` | host page (top frame only by router check) | no | | `content` | `src/content/detector.ts` | host page (top frame only by router check) | no |
### What each bundle owns ### What each bundle owns
@@ -183,17 +183,51 @@ before any new render.
### `src/vault/` ### `src/vault/`
- `vault.ts` — fullscreen tab entry. Hash-based router (`#detail/<id>`, - `vault.ts` (194 lines) — fullscreen tab entry, now a thin
`#add/<type>`, `#trash`, `#devices`, `#settings`, `#settings-vault`, routing + state shell after the Phase 4 split. Registers itself as
`#history`, `#history/<id>`, `#backup`, `#import`). Legacy the StateHost so all `popup/components/*` renderers run unchanged,
`#field-history/<id>` URLs are normalized to `#history/<id>` on maintains its own `selectedItem` cache so hash navigation between
`parseHash` (`vault.ts:139-173`); the internal view value stays already-loaded items doesn't refetch, and delegates DOM scaffolding,
`'field-history'` so the per-item pane renders unchanged. Sidebar navigation, list/drawer/form rendering, and route dispatch to the
bottom-nav: `+ new item · ▦ trash · ⌬ devices · ⚙ settings · ◷ history sibling modules below. The hash-route set is
· ⏻ lock`. Registers itself as the StateHost so all `#detail/<id>`, `#add/<type>`, `#trash`, `#devices`, `#settings`,
`popup/components/*` renderers run unchanged. Maintains its own `#settings-vault`, `#history`, `#history/<id>`, `#backup`, `#import`.
`selectedItem` cache so hash navigation between already-loaded items - `vault-context.ts` — the `VaultController` contract plus the shared
doesn't refetch. types and pure helpers the split modules depend on. Added so the
split is acyclic: the rendering modules import the controller
interface from here rather than from `vault.ts`.
- `vault-router.ts` — hash routing + pane dispatch + data loading,
extracted to keep `vault.ts` ≤250 LOC. Owns `parseHash`; legacy
`#field-history/<id>` URLs are normalized to `#history/<id>` here, but
the internal view value stays `'field-history'` so the per-item pane
renders unchanged.
- `vault-shell.ts` — DOM scaffolding, color-scheme apply, and the
`onMessage` wiring for the tab.
- `vault-sidebar.ts` — sidebar categories nav, 80ms-debounced search
(`SEARCH_DEBOUNCE_MS`), and the bottom-nav
(`+ new item · ▦ trash · ⌬ devices · ⚙ settings · ◷ history · ⏻ lock`).
Also owns the footer: a `#vault-status-slot` plus a manual `↻` refresh
button (`GLYPH_REFRESH`). `wireSidebar` calls `refreshStatus()` once on
mount and again on the button's click — sending `get_vault_status` via
`ctx.sendMessage` and rendering the result into the slot through
`vault-status.ts`. There is **no timer polling**: the indicator only
refreshes on mount + explicit button press, matching the spec's
no-network-without-user-intent discipline (sync is user-initiated).
- `vault-status.ts` — sidebar-footer sync indicator renderer.
`renderStatusIndicator(el, status)` is pure DOM: it renders, by
priority, `N pending` / `N ahead` / `N behind`, falling back to
`in sync`, plus a `last sync <relativeTime>` / `never synced` line.
Reuses `shared/glyphs.ts` (`GLYPH_PENDING`/`AHEAD`/`BEHIND`/`SYNCED`)
and `shared/relative-time.ts`. `VaultStatus` is an alias of
`GetVaultStatusResponse['data']`, so the renderer's input shape is
single-sourced from the message contract and can't drift from the SW
handler.
- `vault-list.ts` — the list pane and its row rendering.
- `vault-drawer.ts` — drawer open/close/render plus
`ensureDrawerClosedForRoute`, which closes the drawer on any
non-list navigation.
- `vault-form-wrapper.ts``renderFormWrapped` plus the sticky bar and
header that wrap form panes.
- `vault.html` / `vault.css` — sidebar + pane layout. - `vault.html` / `vault.css` — sidebar + pane layout.
### `src/vault/components/` ### `src/vault/components/`
@@ -211,12 +245,19 @@ exports `render…(app)` and a `teardown()`, same convention as
### `src/setup/` ### `src/setup/`
- `setup.ts` (1137 lines) — the wizard state machine. Six steps - `setup.ts` (58 lines) — a thin UI-only shell after the Phase 3
(0..5): mode picker (new vault / attach this device), host type split: the render loop + progress track + boot + re-exports. No longer
(Gitea/GitHub), host config + connection test + repo probe, the imports `relicario-wasm`; the wizard now drives vault creation/attach
forking step 3 (create-vault vs attach-this-device), device name, through the SW. Binds `clearWizardState` to
finish. Loads WASM directly. State-coupled `updateStrengthUi` stays `window.addEventListener('beforeunload', clearWizardState)`
here because it walks the live wizard state. (`setup.ts:53`) and also calls it on `goto('mode')` (`setup.ts:44`).
- `setup-steps.ts` (extracted in Phase 3) — the setup step registry +
wizard state + `clearWizardState` + `finishSetup`. One-directional
import (`setup.ts``setup-steps.ts`, no cycle). Crypto orchestration
no longer lives in the wizard: the device step (where `deviceName`
exists) fires `create_vault` and `attach_vault` SW messages instead of
calling WASM directly. State-coupled `updateStrengthUi` stays here
because it walks the live wizard state.
- `setup-helpers.ts` (84 lines, extracted in commit `f79a67b`) — pure - `setup-helpers.ts` (84 lines, extracted in commit `f79a67b`) — pure
helpers: `escapeHtml`, `ratePassphrase`, `scheduleRate` (150ms helpers: `escapeHtml`, `ratePassphrase`, `scheduleRate` (150ms
debounced zxcvbn round-trip), `STRENGTH_LABELS`, `entropyText`, the debounced zxcvbn round-trip), `STRENGTH_LABELS`, `entropyText`, the
@@ -273,7 +314,23 @@ exports `render…(app)` and a `teardown()`, same convention as
`session.getCurrent()`, load via `vault.fetchAndDecrypt*`, mutate, `session.getCurrent()`, load via `vault.fetchAndDecrypt*`, mutate,
re-encrypt, and `gitHost.writeFile`. `fill_credentials` lives here re-encrypt, and `gitHost.writeFile`. `fill_credentials` lives here
with its own captured-tab verification (see Key flows). New in with its own captured-tab verification (see Key flows). New in
commit `a7dbf35`: `register_this_device`. commit `a7dbf35`: `register_this_device`. Phase 3 added
`create_vault` and `attach_vault` (full SW-side vault
creation/attach: embed/unlock, encrypt+push, `register_device` +
`addDevice`, persist config+image, `session.setCurrent`; the failure
path locks and frees the handle). The `lock` handler now also nulls
`state.gitHost` (symmetric with session-expiry) so the status cache
can't go stale across a lock→unlock. Phase 6 added `get_vault_status`
(popup-only, read-only) — returns the cached sync summary
`{ ahead, behind, lastSyncAt, pendingItems }` with **no network
call**. `ahead`/`behind`/`lastSyncAt` are read straight off
`state.gitHost` (populated by the `sync` handler, which records
`lastSyncAt = Math.floor(Date.now()/1000)` — unix **seconds** — after
a successful manifest fetch). `pendingItems` is a live count of active
(non-trashed) manifest entries via `vault.listItems(manifest).length`.
`ahead`/`behind` are structurally always `0` in the extension (it
writes straight to the host via the Contents REST API; there is no
local commit graph) and exist for parity with `relicario status`.
- `router/content-callable.ts` — handler match arms for every - `router/content-callable.ts` — handler match arms for every
`CONTENT_CALLABLE_TYPES` message. Origin always derived from `CONTENT_CALLABLE_TYPES` message. Origin always derived from
`sender.tab.url`, never from message fields. `capture_save_login` `sender.tab.url`, never from message fields. `capture_save_login`
@@ -287,7 +344,13 @@ exports `render…(app)` and a `teardown()`, same convention as
no www-stripping, no public-suffix), trash helpers no www-stripping, no public-suffix), trash helpers
(`listTrashed`, `restoreItem`, `purgeItem`, `purgeAllTrash`), and (`listTrashed`, `restoreItem`, `purgeItem`, `purgeAllTrash`), and
attachment helpers (`addAttachmentToItem`, `removeAttachmentsFromItem`, attachment helpers (`addAttachmentToItem`, `removeAttachmentsFromItem`,
with manifest summary sync). with manifest summary sync). Now also includes the
`create_vault`/`attach_vault` orchestration handlers (Phase 3) and
`handleGetVaultStatus(state)` (Phase 6) — synchronous, no network;
returns the cached `{ ahead, behind, lastSyncAt, pendingItems }`. Its
`Pick<GitHost,'lastSyncAt'|'ahead'|'behind'>`-typed param both breaks
the `PopupState` import cycle and structurally forbids it from making
a network call.
- `session.ts` — single module-scope `SessionHandle | null`. α assumes - `session.ts` — single module-scope `SessionHandle | null`. α assumes
one vault per install. Multi-vault would replace this with a `Map` one vault per install. Multi-vault would replace this with a `Map`
keyed by vault id. keyed by vault id.
@@ -301,6 +364,15 @@ exports `render…(app)` and a `teardown()`, same convention as
`putBlob`, `getBlob`, `deleteBlob`) and the `createGitHost` factory. `putBlob`, `getBlob`, `deleteBlob`) and the `createGitHost` factory.
`BLOB_THRESHOLD_BYTES = 900*1024` is the cutover point at which `BLOB_THRESHOLD_BYTES = 900*1024` is the cutover point at which
attachment writes switch from the Contents API to the Git Data API. attachment writes switch from the Contents API to the Git Data API.
The `GitHost` interface also carries cached sync metadata —
`lastSyncAt: number | null` (unix seconds), `ahead: number`,
`behind: number` — initialized to `null`/`0`/`0` in both `GiteaHost`
and `GitHubHost`. The cache rides the gitHost lifecycle: created on
unlock and cleared whenever `state.gitHost` is nulled — on
session-timer expiry (`index.ts`) **and** on the explicit `lock`
message handler (`popup-only.ts`), which now nulls `state.gitHost`
symmetrically so a lock→unlock cycle can't surface a stale
`lastSyncAt`.
- `gitea.ts` / `github.ts` — the two GitHost implementations. Both use - `gitea.ts` / `github.ts` — the two GitHost implementations. Both use
the host's Contents API for files under threshold, and Git Data API the host's Contents API for files under threshold, and Git Data API
(blobs + tree + commit) for large attachment uploads. Auth differs (blobs + tree + commit) for large attachment uploads. Auth differs
@@ -322,7 +394,9 @@ exports `render…(app)` and a `teardown()`, same convention as
- `state.ts``StateHost` interface + module-scope singleton. Both - `state.ts``StateHost` interface + module-scope singleton. Both
`popup.ts` and `vault.ts` register themselves on boot. All `popup.ts` and `vault.ts` register themselves on boot. All
`popup/components/*` import from here, never from popup.ts directly, `popup/components/*` import from here, never from popup.ts directly,
so the same render code runs in both bundles. so the same render code runs in both bundles. Its `sendMessage`
wrapper intercepts `vault_locked` responses (lifted out of `vault.ts`
in Phase 4, so the intercept now applies uniformly to both bundles).
- `types.ts` — TypeScript mirrors of the Rust core's serde shapes: - `types.ts` — TypeScript mirrors of the Rust core's serde shapes:
`Item`, `ItemCore` (internally-tagged on `type`), `Field` and `Item`, `ItemCore` (internally-tagged on `type`), `Field` and
`FieldValue` (adjacently-tagged on `kind` / `value`), `Manifest`, `FieldValue` (adjacently-tagged on `kind` / `value`), `Manifest`,

View File

@@ -1,7 +1,7 @@
{ {
"manifest_version": 3, "manifest_version": 3,
"name": "Relicario", "name": "Relicario",
"version": "0.5.0", "version": "0.7.0",
"description": "Two-factor encrypted password manager", "description": "Two-factor encrypted password manager",
"icons": { "icons": {
"16": "icons/icon-16.png", "16": "icons/icon-16.png",

View File

@@ -1,7 +1,7 @@
{ {
"manifest_version": 3, "manifest_version": 3,
"name": "Relicario", "name": "Relicario",
"version": "0.5.0", "version": "0.7.0",
"description": "Two-factor encrypted password manager", "description": "Two-factor encrypted password manager",
"icons": { "icons": {
"16": "icons/icon-16.png", "16": "icons/icon-16.png",

View File

@@ -1,6 +1,6 @@
{ {
"name": "relicario-extension", "name": "relicario-extension",
"version": "0.6.0", "version": "0.7.0",
"private": true, "private": true,
"scripts": { "scripts": {
"build": "webpack --mode production", "build": "webpack --mode production",