Moves the routing core — parseHash/setHash, the renderPane pane-dispatch +
teardownPaneComponents, loadManifest, and selectItem — out of vault.ts into
vault-router.ts (carrying the popup-component imports with it). vault.ts is now
just the entry point: state singleton, the VaultController assembly, the
StateHost registration, and the DOMContentLoaded bootstrap (1037 -> 203 LOC).
No behavior change.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Moves renderFormWrapped (sticky save bar + header + dirty-state wiring), the
SAVE_HINT/isMac consts, and the __test__ export out of vault.ts into
vault-form-wrapper.ts, taking the VaultController ctx. Repoints the source-text
form-wrapper test to read the new module. No behavior change.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Moves the drawer (open/close/render + getDrawerCoreFields + selectItemForDrawer)
out of vault.ts into vault-drawer.ts, taking the VaultController ctx. Adds
ensureDrawerClosedForRoute(state, route) — called in renderPane before the view
switch — so drawer state cannot leak across navigation to non-list/detail
routes (P2 safety net). New drawer-state.test.ts covers it (TDD).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Moves the list-pane rendering (renderListPane: row markup, empty state, and
row-click → selectItemForDrawer) out of vault.ts into vault-list.ts, taking
the VaultController ctx. No behavior change.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Moves the sidebar column out of vault.ts/vault-shell.ts into vault-sidebar.ts:
its markup (now incl. an empty #vault-status-slot footer for Phase 6), the
category nav rendering, nav-button wiring, and search. The search input gains
an 80ms trailing-edge debounce (P2 fix — it re-filtered on every keystroke).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Introduces vault-context.ts (VaultView/HashRoute/VaultState types, the
VaultController contract, and the pure helpers escapeHtml/typeIcon/typeLabel/
getFilteredEntries). Extracts the shell concerns — render entry, lock screen,
3-column shell scaffolding, type picker panel, color-scheme apply, and the
session_expired listener — into vault-shell.ts. vault.ts now assembles the
ctx object and delegates shell rendering through it. No behavior change.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Moves all setup-wizard crypto orchestration into the service worker via new
create_vault / attach_vault SW handlers (full Option-A flow: embed/unlock,
encrypt+push, register_device+addDevice, persist config+image, session.setCurrent;
failure path locks+frees the handle, ownership transfers only on success).
setup.ts collapses from ~1230 LOC to a 58-LOC UI-only shell + setup-steps.ts
step registry (one-directional import, no cycle, no relicario-wasm import).
clearWizardState bound to beforeunload + goto(mode). Copy-vault-JSON escape
hatch preserved; redundant register-device button dropped.
Tasks 3.1-3.7. 397/397 vitest green; build:all clean. Unblocks nothing
directly (Phase 6 SW handler is Dev-C) but completes the setup-wizard cliff.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fixes a TS2345 that npx tsc --noEmit missed (it cannot resolve the generated
wasm/relicario_wasm types, degrading SessionHandle) but the webpack build
catches with real types: session.setCurrent(handle) was passed a
SessionHandle|null. Capture the unlock result in a non-null `const h:
SessionHandle` for the in-scope ops; `handle` remains the ownership tracker
the finally block cleans up.
Simplify pass: extract the shared register_device + addDevice + persist-config
tail into registerDeviceAndPersistConfig (both handlers ended identically),
hoist the Argon2 params literal to DEFAULT_PARAMS_JSON, and fan out the two
independent read-only GETs in the attach path via Promise.all.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Asserts STEPS has the six steps in canonical order, each renders non-empty
HTML and returns a teardown from attach, and clearWizardState zero-fills the
reachable Uint8Array fields before resetting state. Keeps the existing
finishSetup tests.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Both vault-step buttons now read "continue" -- they collect input and advance
to the device step, where the SW actually performs create_vault/attach_vault
(with its own busy spinner). The old "create vault" / "verify and attach"
labels implied the action happened on that click, which is no longer true.
Drops the unused export on vaultConfig().
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Hits the Task 7.1 <=500 LOC gate for setup.ts by extracting the SetupStep
registry, the WizardState singleton, clearWizardState and finishSetup into a
sibling setup-steps.ts; setup.ts is now a thin shell (progress track + render
loop + boot + re-exports). The import is one-directional (setup -> setup-steps),
no cycle. Also restores the non-extension copy-vault-config-JSON escape hatch on
the done step (per product decision) while keeping the redundant register-device
button dropped (the SW handler registers the device).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
setup.ts is now UI-only: deletes all direct WASM orchestration (loadWasm,
the wasm binding, verifiedHandle, the SessionHandle import). Vault creation
and attach go through sendMessage({type:'create_vault'|'attach_vault'}) fired
from the device step (where the device name is known); the SW owns the entire
crypto+remote+device flow. The six renderStepN/attachStepN pairs collapse into
the SetupStep registry (mode/host/connection/vault/device/done). The done step
drops the now-redundant register-device + copy-JSON paths, keeping reference
download + recovery QR (off the SW session) + open-vault. clearWizardState
zero-fills sensitive Uint8Array fields on beforeunload and on goto('mode').
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Same shape as create_vault: the SW owns the attach flow end to end -- fetch
salt/params/manifest from the remote, unlock with the user's reference image,
manifest_decrypt to verify the passphrase+image, register this device, persist
config + reference image, and transition the SW to the unlocked state. On
failure the handle is locked then freed; ownership transfers to the session
only on success.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Standalone fast-track merge of the messages.ts type contract (commit 2cf7496)
ahead of the rest of Phase 3, to unblock Dev-C's Phase 6 Task 6.1. Pure
additive: 3 request types + 3 response interfaces + POPUP_ONLY_TYPES entries,
plus a default case in popup-only.ts router to keep the switch exhaustive
(handlers land in Tasks 3.2/3.3/6.1).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lifts the full create-vault flow out of setup.ts into the SW: embed image
secret, unlock, encrypt empty manifest + default settings, push the vault
layout (create-only), register this device + write devices.json, persist
config + reference image locally, and transition the SW to the unlocked
state (handle becomes SW-owned, enabling recoveryQrAvailable). On failure
the handle is locked then freed per Plan A's .free() policy; ownership only
transfers to the session on success.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds the request shapes + response interfaces. POPUP_ONLY_TYPES set grows
by three. SW handlers in service-worker/vault.ts land in the next tasks.
The new union members would make popup-only.ts's exhaustive handle() switch
non-total (TS2366), so a default case is added returning an explicit
"unhandled popup message" error. create_vault/attach_vault get real cases
in Tasks 3.2-3.3; get_vault_status in Dev-C's Phase 6.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a "Release lifecycle" section to CLAUDE.md that makes the release
workflow the canonical way to develop, debug, verify, and tag — for both
single-agent (phone/remote) and multi-agent (supervised, tmux) modes.
Updates the planning section to route plan execution through the workflow
rather than directly to subagent-driven-development or executing-plans.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds dev-d, dev-e, dev-f to Role type, KNOWN_ROLES, RelayQueue map,
and all three MCP tool enums in server.ts. Updates the isRole test
to assert the new roles are valid and dev-g is still rejected.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5 commits landing 5 independent P2 fixes:
- ba5d218 inactivity timer resets on all non-passive messages (READ_ONLY_CONTENT_CALLABLE exclusion set in session-timer.ts; index.ts inverts the gate)
- 35444e0 state.gitHost cleared on session expiry (alongside state.manifest)
- e43f121 teardownSettingsCommon extracted; both settings.ts + settings-vault.ts call it (parameterized over each file's own activeKeyHandler module variable)
- 39fac68 Promise.allSettled with per-slot fallback in devices.ts (list_devices+list_revoked + sshFingerprint map). trash.ts is a no-op on this branch — it doesn't have a Promise.all to migrate (single list_trashed call); plan was written against a different snapshot.
- fce1962 MutationObserver scan() debounced to 200ms in content/detector.ts (no test harness on this branch — manual verification per plan note)
377/377 vitest tests pass (baseline 371 + 6 new tests in session-timer + devices). Zero regressions.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DEV-C P2: SPA churn was re-running the full scan many times per second.
Trailing-edge debounce coalesces bursts so scan() runs at most once per
quiet 200ms window.
No test harness exists for content/detector.ts on this branch; relies
on manual verification on a real SPA page.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
P1.6 closed: shared/state.ts is type-checked end to end. StateHost
interface defines every field; double-registration throws; vitest gets
__resetHostForTests to break inter-test leakage. View + PopupState moved
to shared/popup-state.ts (broke the popup→shared circular-dep blocker).
PopupState widened to absorb VaultState's vault-tab-only fields (unlocked,
drawerOpen, typePanelOpen) with optional + commented justification, so the
two surfaces share one typed contract.
378/378 vitest tests pass (baseline 371 + 7 new state.test.ts cases).
Phase 5 still running in parallel. Cross-stream note from Phase 1 subagent:
settings.ts was not touched here, so Phase 5's teardownSettingsCommon
extraction rebases cleanly.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DEV-C P2: Promise.all meant one rejected RPC failed the whole render.
allSettled + per-slot fallback keeps the active-devices surface usable
when the revoked-list feed (or one bad ssh fingerprint) is down.
Two call sites converted in devices.ts:
1. list_devices + list_revoked pair — revoked failures now render an
inline "couldn't load" slot instead of failing the page.
2. sshFingerprint map — one bad public key falls back to '(unknown)'
instead of killing the whole device list.
trash.ts only has a single sendMessage in its load path on this branch,
so it has no Promise.all to migrate. Plan was written against a slightly
different snapshot; documented divergence in report.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Removes the re-export shim from popup/popup.ts now that all callers point
at the canonical shared/popup-state. No external callers were depending on
the popup.ts re-export, so this drop is a strict tightening.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces the previously any-typed StateHost contract with a typed interface.
Adds double-registration guard and __resetHostForTests for vitest.
sendMessage wrapper is currently a pass-through; Phase 4 will fill its body
with the vault_locked intercept lifted from vault.ts.
Widens PopupState/View on shared/popup-state.ts to cover vault-tab-only
views (history, backup, import) and vault-tab-only fields (unlocked,
drawerOpen, typePanelOpen) so VaultState satisfies StateHost.getState()
without a cast. The popup surface ignores the new optional fields.
Drops the `any` annotations on vault.ts's registerHost callbacks now that
the typed StateHost contract infers them from PopupState.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
P1.9 dedup landed: loadDeviceSettings, saveDeviceSettings, loadBlacklist,
saveBlacklist all live in service-worker/storage.ts; itemToManifestEntry
in service-worker/vault.ts. Both router files import from one home each.
popup-only.ts shrank 727 → 690 LOC; content-callable.ts shrank 204 → 171.
376/376 vitest tests pass (baseline 371 + 5 new storage.test.ts cases).
Phases 1 + 5 still running in parallel in their own worktrees.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DEV-C P2: settings.ts:56-65 and settings-vault.ts:15-22 had near-
identical cleanup paths. Single source for closeGeneratorPanel +
activeKeyHandler removal. Helper takes the handler as a parameter and
returns null so each caller still owns its own module-scoped handler
state.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
P1.9: loadDeviceSettings / loadBlacklist / saveBlacklist / saveDeviceSettings
+ itemToManifestEntry were duplicated across popup-only.ts and
content-callable.ts. Lifts the four storage helpers into service-worker/
storage.ts and itemToManifestEntry into service-worker/vault.ts.
Both router files now import from one home each. Adds storage.test.ts
covering round-trips and defaults.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DEV-C P2: expiry cleared manifest but left the cached git-host client.
The initializer rebuilds gitHost on demand, so clearing here is safe.
No new test: index.ts has top-level chrome.* side effects that make it
expensive to import in a unit test, and the change is a one-liner state
mutation in an inline callback. Manually verified by tracing call sites.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DEV-C P2: an active autofiller never opens the popup, so under the old
rule it got force-locked despite continuous use. Inverts the rule:
reset on all messages except a documented exclusion set (only
get_autofill_candidates today).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Foundation for Plan C Phase 1: shared/state.ts (next task) needs to import
PopupState without creating a popup->shared circular dep. popup.ts now
re-exports from the new location so existing callers don't break in this
task. Task 1.4 will sweep them onto the canonical import path.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
24 tasks across 6 phases derived from the 2026-05-04 extension restructure
spec. Per-task bite-sized steps (TDD where new behavior, verify-existing-
tests where pure relocation) with explicit file/line citations and full
code snippets.
Phase 1 (StateHost typing, S-M, blocks 3+4): 5 tasks
Phase 2 (storage.ts + itemToManifestEntry, S): 3 tasks
Phase 3 (setup wizard SW migration + step registry, L): 7 tasks
Phase 4 (vault.ts split into 5 modules + vault_locked lift, M): 7 tasks
Phase 5 (P2 cluster: timer/gitHost/teardown/allSettled/debounce, M): 5 tasks
Phase 6 (get_vault_status + sidebar status indicator, S-M): 3 tasks
Task 7.1 (final verification sweep against spec Done criteria).
Recommended sequence: 1 → 2 → 5 → 4 → 6 → 3 (independents first, then
the typed-StateHost-dependent phases, then Phase 3 last because it's the
biggest single phase and benefits from all the supporting infra in
place). Max subagent parallelism: 3 streams.
Cross-plan: explicit out-of-scope notes for Plan A (security/docs polish,
already shipped) and Plan B (CLI restructure, already shipped). The
wasm.d.ts file is not touched by this plan (verify empty diff at done).
STATUS + ROADMAP updated to point at the plan.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Post-v0.6.0 spot-check of the three 2026-05-04 architecture-review
specs (per CLAUDE.md rule #4) confirms:
- CLI restructure: shipped as Plan B Cycles 1+2 (b9bd152, 3dd1e1b,
3759f6a, e69b347). Last gap (read-side refresh_groups_cache
callers) closed in d717f0d. Done-criteria all met.
- Security polish: shipped as Stream A Cycle 1 (89090a8) plus
follow-ups for start.sh fourth window (0c9387f) and recovery_qr.rs
docs (229e483). All four phases done.
- Extension restructure: genuinely outstanding. vault.ts is 1037 LOC
(criterion ~200); the five-module split has not happened; setup.ts
still imports relicario-wasm directly; shared/state.ts still has
any-typed StateHost; SW router helpers still duplicated; CLI parity
gap (relicario status) still open. Effort estimate: L.
Removes the incorrect "subcommand reorganization, interactive TUI
mode" descriptor — the original CLI restructure spec is about file
structure, not TUI or renames. The TUI descriptor was a roadmap
mis-paraphrase, not a real outstanding item.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Plan B Phase 4 wanted "every mutating handler must call
refresh_groups_cache" to be a compile-time invariant, with all
callers funneled through Vault::after_manifest_change. The
mutating-handler sweep happened, but two read-side callsites
(commands/list.rs and commands/get.rs) still called the public
helper directly for opportunistic shell-completion cache freshness.
Closes the gap:
- helpers::refresh_groups_cache demoted from pub to pub(crate).
- list.rs and get.rs drop their explicit calls. Cache freshness
between mutations is unaffected: every mutating handler still
funnels through after_manifest_change. The minor staleness
window (manifest changed externally via git pull, no local
mutation since) is the trade-off the spec accepts in exchange
for the compile-time invariant.
The Plan B done-criterion "grep refresh_groups_cache outside
session.rs returns zero" now passes apart from the function
definition itself, which lives in helpers.rs (the natural place
for a flat utility). The visibility scoping achieves the
architectural intent.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The router migrated from generate_device_keypair → register_device
(returns signing_public_key + deploy_public_key with private keys
staying internal to WASM). Test still mocked the old function under
the old return shape (public_key_hex / private_key_base64), so the
router's state.wasm.register_device() call failed with
"is not a function".
Updates the mock function name, response shape, and assertion to the
current contract. Test intent (treat the WASM return as a JS object,
not a JSON string) is preserved.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Tests were written against the pre-Stream B flat settings page. After
the left-nav restructure (bd6a301) and the management-surfaces revamp,
the Display section's IDs are only in the DOM once the user navigates
there, and renderSettings makes additional sendMessage calls (is_unlocked,
per-section data) that the original mocks didn't cover.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Tests predated the 2026-05-24 management-surfaces revamp (047df6e): popup
devices pane now shows SHA-256 fingerprint + added-by + inline two-step
revoke confirm, and the SW revokeDevice signature may have shifted to
match. Mocks + assertions updated accordingly.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Three commits landed since the prior sync (72a59c6) that should be
reflected here:
- cccb7d7 rule #4 + doc-structure plan ticks
- 39ae629 vault lock-screen logo
- (this commit)
Moves the doc-structure redesign from "in progress" to "complete"
(Task 5 verified clean), drops the lock-screen logo from in-flight,
and trims Up next to the four genuinely-outstanding items: tag cut,
CLI restructure, extension restructure, security polish.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Mirrors the logo-lockup treatment already used in the popup unlock view
(Phase 2B) and the setup wizard. Lock-screen rendering now shows the
relicario-logo.svg above the wordmark instead of just the wordmark.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Rule #4 codifies the discipline that prevents the kind of drift the
2026-05-30 status-audit found: Phase 2B, v0.5.1 Streams A/B/C, and 1C-γ
all stealth-shipped 2-3 weeks earlier with their plan checkboxes never
ticked and STATUS.md still listing them as "Up next".
Two halves to the rule:
- Ship side: ticking the boxes is part of shipping. A commit that lands
plan work also ticks that plan's boxes (or an immediately-following
docs commit does).
- Execute side: before starting an unchecked plan, spot-check git log
for distinctive symbols/files — re-executing already-merged work is
the worst failure mode of the drift.
Also applies the rule retroactively to the doc-structure redesign plan:
all 37 sub-step checkboxes flipped to [x]. Tasks 1-4 (rename, scope
headers + Next: footers, link fixes, CLAUDE.md table) shipped in
36a59cd..bae3f7c. Task 5's six verification steps all pass (Step 3's
grep matches are false positives — they're correct new-path sibling
links from inside docs/ to docs/, not stale old-path uses).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The 2026-05-30 sync commit (fa659eb) only covered the vault-tab
management surfaces revamp. It missed three earlier merges that landed
2026-05-02..05-03 and have been on main since:
- Phase 2B polish foundation + form layout (5da1e52, 2026-05-02)
- v0.5.1 Stream A — 3-column vault layout + bottom sheet + toast +
GLYPH_VAULT_TAB + emoji sweep (c16adc4, 2026-05-03)
- v0.5.1 Stream B — left-nav settings (Autofill / Display / Security /
Generator / Retention / Backup / Import) (bd6a301, 2026-05-03)
- v0.5.1 Stream C — Recovery QR end-to-end (core + WASM + CLI +
settings-security.ts + setup wizard banner) + setup wizard Style C
redesign (934dfe0, 2026-05-03)
Also missing: 1C-γ (attachments + Document type + device registration
+ trash + history), Plan B multi-stream refactor (Cycles 1+2), and
the in-flight doc-structure redesign Tasks 1-4 (commits 36a59cd..bae3f7c
since spec 3209bfb).
STATUS now lists each train with merge SHA, spec/plan pointers, and
per-feature bullets. ROADMAP's "Up next" / "Medium-term" / "Long-term"
sections retrimmed: the only genuinely outstanding work is doc-structure
Task 5 verification, the lock-screen logo, the v0.5.x tag, and the
three 2026-05-04 architecture-review specs (CLI restructure, extension
restructure, security polish — none have plans yet).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Table row labels now reference DESIGN.md / docs/CRYPTO.md /
docs/FORMATS.md. Adds three new discipline rules attacking the
structural causes of the 2026-05-30 drift audit findings:
1. Scope-boundary check — content goes in the doc whose scope
header claims it; if it doesn't fit, move it instead of
stretching the header.
2. Code-constant pinning — docs that cite code constants must
cite source file + line; constant changes update doc and
code in the same commit.
3. New-doc rule — adding a tour doc also requires updating
DESIGN's code-map, the Next: footer chain, and this table.
Spec: docs/superpowers/specs/2026-05-30-doc-structure-redesign-design.md
Rewrites every markdown reference to the old paths:
- ARCHITECTURE.md → DESIGN.md
- docs/ARCHITECTURE.md → docs/CRYPTO.md
- FORMATS.md → docs/FORMATS.md
Touches CLAUDE.md (living-docs table + planning-references list),
per-crate ARCHITECTURE.md cross-refs, and any specs in
docs/superpowers/specs/ that referenced the old paths. Audit
history and test-run logs intentionally left untouched.
Spec: docs/superpowers/specs/2026-05-30-doc-structure-redesign-design.md