Commit Graph

456 Commits

Author SHA1 Message Date
adlee-was-taken
a332a9e80d Merge feature/v0.5.0-plan-a-security-cleanup: Plan A security + cleanup
v0.5.0 Plan A — Security Fixes + Repo Cleanup. 7 commits, ~800 net
insertions across the Rust workspace. Four items delivered:

- S1 (HIGH-severity authentication bypass fix): rewrite verify_commit
  in relicario-server. The previous implementation accepted any
  GOODSIG/Good signature line on stderr, ignoring whether the signing
  key was registered or revoked. The new implementation:
  * builds a temp gpg.ssh.allowedSignersFile from devices.json at the
    commit (no global git-config mutation)
  * parses the SHA-256 fingerprint from `git verify-commit --raw`
    stderr via regex
  * checks revocation FIRST (revoked entries may have been removed
    from devices.json), with the historical-commit case
    (committer_ts < revoked_at) explicitly allowed
  * uses committer date (GIT_COMMITTER_DATE / `git show -s
    --format=%ct`), not author date or wall clock
  * tightened the bootstrap guard to require BOTH devices and revoked
    to be empty (closes an empty-devices.json privilege-escalation
    route present in the original code)
  * 4 acceptance integration tests build real on-disk repos with
    SSH-signed commits and verify each scenario

- S2 (tar archive path-traversal hardening): replace
  tar::Archive::unpack with safe_unpack_git_archive. Located in
  relicario-core (per-spec, so integration tests can reach it without
  the bytes-in/bytes-out invariant breaking). Validates each entry's
  type (rejects symlinks/hardlinks), path components (rejects '..',
  RootDir, Windows drive Prefix), and declared size (rejects
  individual or cumulative > 100×compressed-or-1-GiB whichever is
  lower). The CLI's restore path adds a paranoid OS-level
  starts_with(.git/) check on the joined destination as
  defense-in-depth even after textual validation. 5 acceptance tests
  cover path traversal, symlinks, oversized headers (header claim of
  2 GiB tested without allocating disk).

- S3 (RELICARIO_* env-var audit): docs/SECURITY.md gains a
  "Configuration env vars" section enumerating each variable, its
  purpose, and trust assumption. Active-in-all-builds variables
  (RELICARIO_IMAGE, RELICARIO_GITEA_*) are documented; debug-only
  variables (RELICARIO_NO_GROUPS_CACHE, RELICARIO_TEST_*) are gated
  behind cfg(debug_assertions) so the env-var lookup is removed from
  --release binaries.

- C1 (stale feature branch prune): 5 merged feature branches and
  3 worktrees pruned interactively per dev report.

- Bonus: 4d02a50 fixes pre-existing clippy warnings across
  crates/relicario-{core,cli} (deref operators, Option::is_none_or
  vs map_or(true, ...), iter_mut().enumerate() patterns,
  div_ceil()) so the workspace builds clean under `-D warnings`.

Merge resolution: docs/SECURITY.md had a conflict where main's F11/F12
(Device Authentication paragraph naming relicario-server + simplified
"Device registration is optional" line) collided with Plan A's S3
section. Resolved by keeping both — F11/F12's wording for the
Device Authentication section, then Plan A's "Configuration env vars"
section appended below.

Cargo.lock regenerated. The previous committed lock was stale since
commit 8855078 (--totp-qr); cargo test on both devs' worktrees
produced identical regenerated locks. Plan A genuinely added regex +
tempfile to relicario-server (both already transitively present from
relicario-cli), so no new top-level deps; the Cargo.lock churn is
catch-up of crate-version bumps that have happened since the last
commit-of-record.

Tests: 248 cargo tests pass; extension tests unchanged (336/8 with 8
pre-existing device-auth scaffolding failures).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 19:54:12 -04:00
adlee-was-taken
d45dd10917 Merge feature/v0.5.0-plan-b-extension-ux: Plan B extension UX
v0.5.0 Plan B — Extension UX Polish + Bug Fixes. 15 commits, 22 files,
+853/-33 lines, all in extension/. Five features delivered:

- P4: ERROR_COPY centralized map; popup humanizeError now a thin shell
  over lookupErrorCopy; fullscreen tab gets friendly title/body/CTA blocks
  (closes B2). Generated test enumerates every grep'd error code so the
  registry can't drift.
- B1: applyGeneratedPassword dispatches a synthetic input event after
  the regenerate handler sets the password value, so the strength-meter
  listener re-rates the new value.
- P1: end-to-end password coloring — pure colorizePassword utility,
  chrome.storage.sync round-trip via applyColorScheme, CSS rules with
  custom properties, four reveal surfaces (popup item-detail, vault
  item-detail, field-history, generator preview), boot wiring + storage
  listener, Display section in settings with color pickers + swatch +
  reset.
- P3: .form-lower wrapper constrains lower form sections (notes,
  custom-fields, attachments, actions) to the same max-width: 960px
  envelope as .form-grid above, gated on surface === 'fullscreen' so
  the popup is unaffected.
- P2: finishSetup() opens the fullscreen vault tab and best-effort
  closes the setup tab after successful device registration. Both
  create-new and attach-existing flows funnel through it.

Implementation notes:
- vault.ts uses event delegation on the stable #vault-app root for
  .error-cta clicks (better than the plan's per-render handler attach;
  survives re-renders without leaking listeners).
- fields.ts gained a kind: 'password' | 'concealed' option on
  ConcealedRowOpts so wireFieldHandlers can apply colorizePassword
  selectively at the shared rendering layer.
- New WASM stub at src/__stubs__/relicario_wasm.stub.ts + vitest config
  alias lets unit tests import setup.ts without exploding on the
  runtime-only WASM module.

Tests: +28 (336/8 vs main's 308/8); 8 pre-existing device-auth
scaffolding failures unchanged. Builds clean: cargo wasm + Chrome
bundle + Firefox bundle.

Manual acceptance items (P3 viewport sweep at 1920/1440/1024/768,
P2 setup-flow smoke) deferred to user's pre-tag smoke walk.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 19:42:22 -04:00
adlee-was-taken
4d02a50cc8 chore(core): fix pre-existing clippy warnings (-D warnings gate)
Resolves pre-existing lint issues in imgsecret.rs, time.rs, totp.rs,
and crypto.rs that blocked the cargo clippy --workspace -D warnings
gate. No logic changes: loop-index → iterator, manual div_ceil →
.div_ceil(), manual range contains → .contains(), auto-deref cleanup.

Also fixes pre-existing warnings in relicario-cli (main.rs, session.rs,
device.rs, gitea.rs, helpers.rs, test helpers): dead_code suppression,
too_many_arguments, literal_with_empty_format_string, manual_char_cmp,
map_or → is_none_or, and repeat().take() → vec! in test helpers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 19:32:45 -04:00
adlee-was-taken
4e9d834920 feat(ext/setup): hand off completion to fullscreen vault tab (P2)
After successful device registration (state.configPushed = true), the
wizard now opens vault.html in a new tab and closes the setup tab.
Both create-new and attach-existing flows funnel through the same
finishSetup() handler. Closing the setup tab is best-effort --
chrome.tabs.remove failures don't block the vault open.

Add src/__stubs__/relicario_wasm.stub.ts + vitest.config alias so
setup.ts can be imported in unit tests without the runtime WASM file.
Exclude the stubs dir from the webpack/tsc build in tsconfig.json.
2026-05-02 19:15:35 -04:00
adlee-was-taken
631e9af470 fix(ext/login): constrain lower form sections to .form-grid envelope (P3)
Notes, custom-fields disclosure, attachments disclosure, and form-actions
in fullscreen logins now sit inside a .form-lower wrapper with the same
max-width: 960px; margin: 0 auto envelope as .form-grid above. Removes
the visual rhythm break at the 2-col -> full-width transition.

Popup keeps its current single-column behavior (gated on surface flag).
2026-05-02 19:07:33 -04:00
adlee-was-taken
b2fc56709a feat(ext/settings): Display section with color pickers + swatch + reset
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 19:03:23 -04:00
adlee-was-taken
b928ed407b feat(ext): apply color scheme on popup + vault startup
Import applyColorScheme in popup.ts and vault.ts, await it at boot,
and register a chrome.storage.onChanged listener so live color-picker
changes take effect without a reload.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 18:55:28 -04:00
adlee-was-taken
5d9a7ee8d3 docs(multi-agent): expand kickoff section with full spec→plans→launch workflow 2026-05-02 18:51:52 -04:00
adlee-was-taken
006e67c361 fix(cli): cfg-gate RELICARIO_NO_GROUPS_CACHE to debug builds (audit S3)
The groups-cache opt-out is a developer debugging knob, not a
user-facing config. Gating the env-var lookup behind cfg!(debug_assertions)
makes release builds ignore the variable; the optimiser removes the
lookup entirely, so the variable name doesn't appear in release binary
strings output.

Doc-comments updated to reflect the new behaviour.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-02 18:51:15 -04:00
adlee-was-taken
95d1ff833c docs: enumerate RELICARIO_* env vars in SECURITY.md (audit S3)
Adds a "Configuration env vars" section listing every RELICARIO_*
variable read by production code, with purpose and trust boundary.
Splits user-facing vars from debug-only ones (cfg(debug_assertions))
to make the attack surface explicit for security reviewers.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-02 18:50:44 -04:00
adlee-was-taken
6bca0b3526 feat(ext/popup/item-detail): colorize revealed password field
Add data-field-kind attribute to renderConcealedRow so wireFieldHandlers
can distinguish password fields from other concealed rows (TOTP secrets,
CVV, PIN, private keys). Apply colorizePassword() on reveal when kind is
"password"; plain textContent otherwise. Pass kind through renderSections
for custom-section password fields.
2026-05-02 18:49:56 -04:00
adlee-was-taken
f45c275566 feat(ext/generator): colorize live password preview 2026-05-02 18:49:56 -04:00
adlee-was-taken
3e4312ca6f feat(ext/popup/field-history): colorize revealed password entries
Import colorizePassword and post-process .revealed value cells after
innerHTML render, replacing escaped-HTML text with colored spans via
the valueStore plaintext lookup.
2026-05-02 18:47:12 -04:00
adlee-was-taken
4fc1357368 docs: add multi-agent development paradigm README 2026-05-02 17:19:25 -04:00
adlee-was-taken
518b41e9cd style(ext): add password-coloring CSS rules + custom property defaults 2026-05-02 17:19:06 -04:00
adlee-was-taken
df58b0dda1 chore(relay): add relay MCP server to project Claude config 2026-05-02 17:18:47 -04:00
adlee-was-taken
ed9fcbe6ba feat(relay): start.sh launcher with --manual/--tmux/--kitty modes 2026-05-02 17:18:31 -04:00
adlee-was-taken
0172a06698 feat(relay): MCP SSE server with post_message/read_messages/list_pending 2026-05-02 17:17:41 -04:00
adlee-was-taken
1de7cda1b0 feat(ext/shared): add colorizePassword utility
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 17:17:05 -04:00
adlee-was-taken
6d5a2570d4 feat(relay): in-memory queue with consume-once semantics 2026-05-02 17:16:21 -04:00
adlee-was-taken
6a1c6d5875 fix(core,cli): harden backup-restore tar unpack against path traversal (audit S2)
cmd_backup_restore previously called tar::Archive::unpack with default
settings, allowing malicious .relbak archives to escape the target
directory via .. entries, absolute paths, or symlinks. No size cap
meant tar bombs could exhaust disk space.

Replaced with relicario_core::safe_unpack_git_archive which:
- Rejects .. (ParentDir), absolute (RootDir), and drive-prefix
  (Prefix) components with "path traversal blocked" error.
- Rejects symlinks and hardlinks outright.
- Checks declared header size before reading body; rejects entries or
  cumulative totals exceeding the caller's cap.
- Returns (relative-path, bytes) pairs; the CLI re-checks
  dest.starts_with(git_dir) after OS-level path resolution.
- CLI cap: min(100 × compressed size, 1 GiB).

Acceptance: 5 unit tests in relicario-core (traversal, absolute path,
symlink, size bomb, happy path); existing CLI backup roundtrip tests
remain green.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 17:16:11 -04:00
adlee-was-taken
6d8f699fcb chore(relay): scaffold tools/relay with MCP SDK dep 2026-05-02 17:15:46 -04:00
adlee-was-taken
25c9eb52a0 feat(ext/shared): color-scheme storage + applyColorScheme
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 16:49:03 -04:00
adlee-was-taken
2df636e454 fix(ext/login): dispatch input event after regenerate sets password (B1)
Programmatic input.value = newPassword does not fire input events, so
the strength-meter listener at shared/form-affordances/password-tools.ts:65
never re-rates the new value — meter stays stuck on the prior reading.

Extract applyGeneratedPassword(input, value) helper that sets value, type,
then dispatches new InputEvent('input', { bubbles: true }). Vitest covers
the dispatch + a sanity check that bubbling listeners fire.
2026-05-02 16:46:06 -04:00
adlee-was-taken
c0921b134d docs(plan): relay server implementation plan
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 16:44:06 -04:00
adlee-was-taken
575343dc19 refactor(ext/vault): event delegation for error-cta + CSS variable consistency 2026-05-02 16:41:39 -04:00
adlee-was-taken
0443f6a3b4 docs(spec): add top-level README section to relay server design
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 16:38:30 -04:00
adlee-was-taken
5e8e617a4d docs(spec): relay server design for multi-agent message bus
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 16:37:17 -04:00
adlee-was-taken
1c641b4911 fix(ext/vault): friendly error block in fullscreen tab (closes B2)
Replaces raw escapeHtml(state.error) renders with lookupErrorCopy()-driven
title/body/CTA blocks. vault_locked specifically gets an 'Unlock vault'
CTA that refocuses the passphrase input. Other CTAs route to setup.html
or chrome.runtime.reload().

Closes B2; concludes P4.
2026-05-02 16:37:16 -04:00
adlee-was-taken
efac53d527 fix(server): real signature verification in pre-receive hook (audit S1)
verify_commit previously loaded devices.json/revoked.json and threw
both away, accepting any commit whose stderr contained "GOODSIG" or
"Good signature". This left device registration and revocation as
no-ops: unregistered keys could push, revoked keys kept working.

The fix:
- Build a temp gpg.ssh.allowedSignersFile from devices.json at the
  commit, passed via GIT_CONFIG_COUNT/KEY/VALUE env (no global git
  config mutation).
- Run git verify-commit --raw and parse SHA256 fingerprint from stderr
  regardless of exit code (SSH git outputs the "Good" line even for
  keys not in allowed-signers, with "No principal matched" + exit 1).
- Check revoked.json FIRST: reject if committer_ts >= revoked_at;
  accept historical commits (committer_ts < revoked_at).
- Reject if fingerprint is not in active devices.json.
- Bootstrap: accept only when BOTH devices.json AND revoked.json are
  empty/absent (not just devices.json alone).

Acceptance: 4 integration tests covering the matrix.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 16:34:37 -04:00
adlee-was-taken
214e1e49f8 test(ext/shared): pin fallback title assertion in error-copy test 2026-05-02 16:30:09 -04:00
adlee-was-taken
af8626fb5f docs(audit): mark all 8 proposed findings fixed (PM follow-up)
Updates each Status: line from "Proposed; needs user decision" to
the actual fix-commit SHA. The audit doc now records the full state:
6 trivial findings fixed in the initial 900ccf1 pass; 8 deeper
findings fixed across ca059e7, 8fd9a05, 1342228, 76d092d, 9c97f9f
during v0.5.0 PM kickoff.

Pre-tag checklist: doc-audit follow-ups item is now done.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 16:28:08 -04:00
adlee-was-taken
9c97f9f939 docs(spec): banner foundational design spec as historical (audit F13)
The 2026-04-11 design spec lists secure notes, secure documents, TOTP,
Firefox extension, LastPass import, and device authentication as
"Post-V1 Ideas" — most of which shipped over the following weeks.
Per the doc/architecture/overview.md convention, specs are frozen
decision artifacts and shouldn't be retro-edited; instead, add a
one-line status banner pointing readers at CHANGELOG.md and the
overview doc for current state.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 16:26:39 -04:00
adlee-was-taken
76d092d4f6 docs(architecture): note settings.enc + typed items in vault-creation flow (audit F10)
The Vault Creation Flow ASCII showed only manifest.enc as init's
encrypted artifact; cmd_init has been writing settings.enc in parallel
since the VaultSettings rollout. Update the encrypt step to show both
artifacts side-by-side with independent nonces.

Below the ASCII, add a short pointer noting that the per-item lifecycle
(typed-item envelope, attachment encryption, field-history) lives in
crates/relicario-core/ARCHITECTURE.md and reuses the same master_key +
XChaCha20-Poly1305 primitives. The doc-audit framing is "this top-level
doc could just point at the per-crate docs" — taking that trim path.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 16:26:09 -04:00
adlee-was-taken
648dcf386e feat(ext/shared): centralize error-message copy in ERROR_COPY map
Replaces the popup's regex-chain humanizeError with a total lookup over
every error code returned by extension/src/service-worker/router/. A
generated test discovers codes via grep so the registry can't drift.
The popup keeps its small set of regex translators for Rust/serde error
phrasing that doesn't go through the router's error vocabulary.

Subsumes B2 — fullscreen consumer lands in the next commit.
2026-05-02 16:26:01 -04:00
adlee-was-taken
1342228a51 docs(security): name relicario-server in device-auth section (audit F11/F12)
- F12: Device Authentication section now names the relicario-server crate
  and its two subcommands (generate-hook, verify-commit), and notes that
  signed commits without the server-side hook provide authorship only —
  any pusher can still land an unsigned commit.
- F11: drop the "optional before v0.4.0" version line (v0.4.0 was never
  tagged; v0.5.0 is the first release with the hook) and replace with a
  one-liner: registration is optional but recommended for shared vaults.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 16:25:21 -04:00
adlee-was-taken
d539050aec chore(server): add assert_cmd/predicates/tempfile dev-deps
Needed for the upcoming verify-commit acceptance suite (audit S1).

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-02 16:23:24 -04:00
adlee-was-taken
8fd9a05875 docs(claude): refresh project tree, IDs line, and roadmap (audit F2/F3/F4)
- F2: add relicario-server crate to the project-structure tree
- F3: replace stale "Next: WASM + Chrome MV3 (Plan 2)" roadmap line with
  the v0.5.0/Phase-3/1C-γ/LastPass picture
- F4: ItemIds and FieldIds are 16-char hex (64 bits) per audit M8;
  AttachmentIds are first 32 hex of SHA-256 (128 bits) per audit I2/B4

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 16:23:17 -04:00
adlee-was-taken
8a72b5e192 feat(core): add device::fingerprint helper for SSH SHA256 fingerprints
Wraps ssh-key's PublicKey::fingerprint(HashAlg::Sha256). Output format
matches ssh-keygen -lf and git verify-commit --raw stderr
(SHA256:<43-char base64>). Used by the upcoming relicario-server
verify-commit rewrite (audit S1).

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-02 16:23:10 -04:00
adlee-was-taken
ca059e7507 docs(overview): add relicario-server crate to four-codebase framing
Doc-audit Finding 1. The repo has had four Rust crates since early May
when the pre-receive hook crate landed, but docs/architecture/overview.md
still framed itself around three. Update:

- "The three codebases" → "The four codebases" (intro + heading)
- ASCII diagram fans core out to cli + server + wasm, with wasm feeding
  the extension
- Table gains a relicario-server row noting it lives on the git server
  and only sees public key material
- Build matrix adds `cargo build -p relicario-server --release`
- "Where to look next" points at server src + the device-auth design spec

Server has no user-facing surface, so the CLI/extension parity rule is
clarified to exclude it (it is server-side enforcement of an invariant
the clients already agreed to).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 16:20:45 -04:00
adlee-was-taken
c3d8778042 docs: add v0.5.0 PM/Dev-A/Dev-B kickoff prompts
Three-terminal coordination paradigm: a PM session reviews and
integrates while two senior-dev sessions work parallel feature
branches in their own worktrees, dispatching subagents per
task. Prompts encode roles, boundaries, status/directive/question
block formats for user-relayed cross-terminal coordination, and
pre-tag checklists.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 16:07:14 -04:00
adlee-was-taken
900ccf1cf4 docs: refresh README, ARCHITECTURE, overview for current state
Apply trivial-fix findings from the 2026-05-02 doc audit:
- README: items/ vs entries/, settings.enc + attachments/ +
  revoked.json in vault layout, full crate tree (relicario-wasm
  + relicario-server + typed-items modules), 16-char hex IDs,
  roadmap reflects shipped trains
- ARCHITECTURE.md: git-server box reflects items/ + 16-char IDs;
  relicario-core inner box lists typed-items modules
- architecture/overview.md: ID width / 128-bit AttachmentId

8 deeper findings still proposed for v0.5.0 release prep.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 16:04:02 -04:00
adlee-was-taken
3caa7af194 docs(plan): v0.5.0 plans A/B and doc audit
Plan A (Rust + docs): S1 pre-receive hook fix, S2 tar
path-traversal hardening, S3 RELICARIO_* env-var audit, C1
stale branch cleanup. ~9 tasks, ~50 steps.

Plan B (extension UX): P4 error-copy centralization (subsumes
B2), B1 strength-meter regenerate fix, P1 password coloring
(inlined), P3 form-layout envelope, P2 setup → fullscreen tab.
~15 tasks, ~85 steps.

Doc audit: 14 findings, 6 fixed inline (README, ARCHITECTURE,
overview), 8 proposed for v0.5.0 release prep.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 16:03:53 -04:00
adlee-was-taken
57237af39e docs(spec): v0.5.0 polish + harden bundle
Anchors on a HIGH-severity auth bypass in the relicario-server
pre-receive hook (revocation + registered-device checks both
unimplemented), bundles two hardening follow-ups, two confirmed
bugs, and four UX improvements. Splits into Plan A (Rust + docs)
and Plan B (extension UX) for independent merge cadence.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 15:45:57 -04:00
adlee-was-taken
5da1e520e3 Merge feature/phase-2b-polish: polish foundation + form layout 2026-05-02 15:10:03 -04:00
adlee-was-taken
f1c615c0ed feat(ext/vault): fullscreen form header with dirty-state subtitle
Title left ('new login' / 'edit login'), subtitle below cycles between
'no changes' and 'unsaved · esc to cancel' on input events. Right side
shows the platform-aware save hint ('⌘+S to save' / 'Ctrl+S to save').
The actual ⌘+S keymap arrives in Phase 3 — this is a visual hint only.
2026-05-02 15:06:42 -04:00
adlee-was-taken
b270dfedb4 feat(ext/vault): sticky save bar in fullscreen forms
The form pane gets a flex column layout: scrollable content above,
sticky save bar at bottom. Bar uses translucent fill with backdrop-blur
and a 24px gradient fade so content scrolls under it. Save / cancel
buttons reuse the form's existing handlers via externalActions flag.
2026-05-02 15:05:09 -04:00
adlee-was-taken
a28b456191 feat(ext/login): add surface flag for two-column fullscreen form
renderForm() takes an optional { surface: 'popup' | 'fullscreen' }
parameter. When 'fullscreen', the Identity and Credentials field
groups render as glass cards inside a .form-grid (two columns,
stacks at <=720px). Popup keeps its single-column layout.
2026-05-02 15:01:35 -04:00
adlee-was-taken
058a49f68b style(ext/vault): apply .surface-backdrop to fullscreen body
Subtle radial top-glow + grid texture behind the existing vault shell.
No layout changes — existing panes sit above the backdrop's ::before.
2026-05-02 14:55:37 -04:00
adlee-was-taken
97e351fa61 feat(ext/setup): apply polish vocabulary to setup wizard
- Wraps setup content in .surface-backdrop
- Each wizard step gets a .glass card
- Mode-picker cards become glass cards
- 'next' / 'continue' buttons get the ▸ glyph
- Migrate from .btn .btn-primary to the new .btn-primary class
2026-05-02 14:52:14 -04:00