Skip to content

Staging#15

Merged
AustinKelsay merged 11 commits intomasterfrom
staging
Jan 6, 2026
Merged

Staging#15
AustinKelsay merged 11 commits intomasterfrom
staging

Conversation

@AustinKelsay
Copy link
Copy Markdown
Member

@AustinKelsay AustinKelsay commented Jan 5, 2026

Summary by CodeRabbit

  • New Features

    • Added QR code display functionality for credentials with keyboard toggle support.
    • Introduced animated ASCII art icon to the intro screen.
  • Documentation

    • Updated CLI command structure and namespace documentation.
    • Replaced npm references with bun-based build and development commands.
    • Added comprehensive testing architecture guide.
  • Tests

    • Added 97 new tests with full coverage across crypto, storage, and CLI parsing.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 5, 2026

📝 Walkthrough

Walkthrough

This PR introduces QR code support to the igloo-cli with new UI components, refactors CLI argument parsing into a reusable module, adds comprehensive test coverage across six new test files totaling 97 tests, updates documentation to reflect bun-based workflows and restructured command namespaces, and enhances the visual experience with animated ASCII icons.

Changes

Cohort / File(s) Summary
Documentation Updates
AGENTS.md, CLAUDE.md, llm/context/testing/test-architecture.md, llm/implementation/test-coverage-implementation.md
Replaces npm commands with bun equivalents in build/test/dev workflows. CLAUDE.md comprehensively reorganizes CLI structure with Share/Keyset/Keys namespaces, updated component architecture, and new environment variables. Test documentation outlines framework (node:test), test organization, helpers (makeTmp, runCli), and best practices.
CLI Core Refactoring
src/cli.tsx, src/lib/parseArgv.ts
Extracts argument parsing logic (Flags, ParsedArgs types, parseArgv, toBool) from cli.tsx into new src/lib/parseArgv.ts module. Adds flag alias normalization (t→threshold, T→total, E→debug-echo) and comprehensive edge-case handling for long/short flags, boolean detection, and special cases (--help, --version).
UI Visual Enhancements
src/components/Help.tsx, src/components/Intro.tsx
Help.tsx adds FROSTR_ICON ASCII art display in cyan. Intro.tsx adds ICON_FRAMES constant with 8 animation frames and useEffect hook cycling frameIndex every 200ms for animated icon effect.
QR Code Feature
src/components/ui/QRCodeDisplay.tsx, src/components/ui/CredentialDisplay.tsx, src/components/keyset/KeysetCreate.tsx, src/components/keyset/KeysetLoad.tsx, src/components/keyset/ShareSaver.tsx
Adds QRCodeDisplay component for terminal QR rendering with async generation via qrcode.toString. Adds CredentialDisplay component for labeled credential display with optional QR. Propagates showQR prop through KeysetCreate, KeysetLoad, and ShareSaver; KeysetLoad/ShareSaver support keyboard toggle (Q key) for QR visibility in raw mode with useInput/useStdin.
Dependencies
package.json
Adds qrcode (runtime) and @types/qrcode (dev) dependencies for QR code generation.
Test Suite
tests/cli.basic.test.ts, tests/cli.parsing.test.ts, tests/crypto.test.ts, tests/naming.test.ts, tests/paths.test.ts, tests/policy.test.ts, tests/storage.test.ts
Updates cli.basic.test.ts with successPattern for animated intro. Adds cli.parsing.test.ts with extensive parseArgv/toBool unit tests. Adds crypto.test.ts validating encryption/decryption roundtrips and legacy format support. Adds naming.test.ts (slug/path construction), paths.test.ts (app data resolution), policy.test.ts (policy creation/normalization), and storage.test.ts (file I/O and record persistence) covering ~97 new tests across 6 new files.

Sequence Diagram

sequenceDiagram
    participant User as User (Raw Mode)
    participant KL as KeysetLoad Component
    participant Input as useInput/stdin
    participant KS as KeysetLoad State<br/>(qrVisible)
    participant CD as CredentialDisplay
    participant QR as QRCodeDisplay
    participant QRC as qrcode.toString()
    participant Term as Terminal

    User->>Input: Press 'Q' key
    Input->>KL: onInput handler triggered
    KL->>KS: Toggle qrVisible state
    KS->>CD: Re-render with qrVisible
    alt showQR === true and qrVisible === true
        CD->>QR: Render QRCodeDisplay
        QR->>QRC: Generate QR string (async)
        QRC-->>QR: QR string
        QR->>Term: Render label + QR code in terminal
    else showQR === false or qrVisible === false
        CD->>Term: Render credential text only
    end
    Term-->>User: Display toggles between text and QR
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 Hops with joy, parsing flags so clean,
QR codes shimmer in cyan sheen,
Icons dance in terminal light,
Arguments hop left and right,
Tests ensure all hops take flight! 🎉

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.08% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The PR title 'Staging' is vague and generic, providing no meaningful information about the actual changes (documentation updates, CLI refactoring, QR code features, test architecture additions, and new exports). Replace with a more descriptive title that captures the main scope, such as 'Add QR code support, refactor CLI argument parsing, and expand test coverage' or 'Implement QR features and testing infrastructure'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
tests/naming.test.ts (1)

68-89: Consider using beforeEach/afterEach for environment variable manipulation.

The inline try/finally pattern works but is inconsistent with the rest of the file. Lines 97-105 use beforeEach/afterEach for the same purpose, which is cleaner and more maintainable.

🔎 Proposed refactor to align with existing patterns
-test('buildShareFilePath builds full path with directory and .json', () => {
-  // Set up temp directory for consistent path testing
-  const originalAppdata = process.env.IGLOO_APPDATA;
-  process.env.IGLOO_APPDATA = '/tmp/test-appdata';
-
-  try {
-    const result = buildShareFilePath('test', 1);
-    const expectedDir = getShareDirectory();
-    const expectedId = buildShareId('test', 1);
-
-    assert.equal(result, path.join(expectedDir, `${expectedId}.json`));
-    assert.ok(result.endsWith('.json'));
-    assert.ok(result.includes('test_share_1'));
-  } finally {
-    // Restore original env
-    if (originalAppdata !== undefined) {
-      process.env.IGLOO_APPDATA = originalAppdata;
-    } else {
-      delete process.env.IGLOO_APPDATA;
-    }
-  }
-});
+test('buildShareFilePath builds full path with directory and .json', () => {
+  const originalAppdata = process.env.IGLOO_APPDATA;
+  process.env.IGLOO_APPDATA = '/tmp/test-appdata';
+
+  const result = buildShareFilePath('test', 1);
+  const expectedDir = getShareDirectory();
+  const expectedId = buildShareId('test', 1);
+
+  assert.equal(result, path.join(expectedDir, `${expectedId}.json`));
+  assert.ok(result.endsWith('.json'));
+  assert.ok(result.includes('test_share_1'));
+
+  // Restore original env
+  if (originalAppdata !== undefined) {
+    process.env.IGLOO_APPDATA = originalAppdata;
+  } else {
+    delete process.env.IGLOO_APPDATA;
+  }
+});

Alternatively, move this test below line 106 to share the existing beforeEach/afterEach setup and eliminate env manipulation entirely.

llm/context/testing/test-architecture.md (1)

17-35: Minor: Add language identifier to fenced code block.

The fenced code block at line 17 is missing a language specifier. Consider adding text or leaving it as is if the style is intentional for directory tree visualizations.

🔎 Proposed fix
-```
+```text
 tests/
 ├── helpers/
src/lib/parseArgv.ts (1)

68-82: Alias normalization logic is correct.

The normalization correctly maps short flags to their long-form equivalents while preserving long-form values if both are provided. The precedence behavior (long-form wins) is reasonable and user-friendly.

Optional: Add brief comment for clarity

Consider adding a comment above line 68 to document the purpose:

+  // Normalize short flag aliases to their long-form equivalents
   if (flags.t !== undefined && flags.threshold === undefined) {

This is purely optional as the code is self-explanatory.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3564c2e and 4241541.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (21)
  • AGENTS.md
  • CLAUDE.md
  • llm/context/testing/test-architecture.md
  • llm/implementation/test-coverage-implementation.md
  • package.json
  • src/cli.tsx
  • src/components/Help.tsx
  • src/components/Intro.tsx
  • src/components/keyset/KeysetCreate.tsx
  • src/components/keyset/KeysetLoad.tsx
  • src/components/keyset/ShareSaver.tsx
  • src/components/ui/CredentialDisplay.tsx
  • src/components/ui/QRCodeDisplay.tsx
  • src/lib/parseArgv.ts
  • tests/cli.basic.test.ts
  • tests/cli.parsing.test.ts
  • tests/crypto.test.ts
  • tests/naming.test.ts
  • tests/paths.test.ts
  • tests/policy.test.ts
  • tests/storage.test.ts
🧰 Additional context used
📓 Path-based instructions (10)
src/**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Use Ink components (, , etc.) for terminal UI and do not use HTML elements

Files:

  • src/components/keyset/KeysetCreate.tsx
  • src/components/Help.tsx
  • src/components/keyset/ShareSaver.tsx
  • src/components/ui/QRCodeDisplay.tsx
  • src/components/Intro.tsx
  • src/cli.tsx
  • src/components/ui/CredentialDisplay.tsx
  • src/components/keyset/KeysetLoad.tsx
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

All import specifiers must include .js extensions (TypeScript ESM requirement) even though source files are .ts/.tsx

Files:

  • src/components/keyset/KeysetCreate.tsx
  • src/components/Help.tsx
  • src/components/keyset/ShareSaver.tsx
  • src/components/ui/QRCodeDisplay.tsx
  • src/lib/parseArgv.ts
  • src/components/Intro.tsx
  • src/cli.tsx
  • src/components/ui/CredentialDisplay.tsx
  • src/components/keyset/KeysetLoad.tsx
src/components/**

📄 CodeRabbit inference engine (CLAUDE.md)

All UI components should live under src/components/

Files:

  • src/components/keyset/KeysetCreate.tsx
  • src/components/Help.tsx
  • src/components/keyset/ShareSaver.tsx
  • src/components/ui/QRCodeDisplay.tsx
  • src/components/Intro.tsx
  • src/components/ui/CredentialDisplay.tsx
  • src/components/keyset/KeysetLoad.tsx
src/components/**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

When adding a new command, implement it as a component under src/components/

Store reusable UI components under src/components/

Files:

  • src/components/keyset/KeysetCreate.tsx
  • src/components/Help.tsx
  • src/components/keyset/ShareSaver.tsx
  • src/components/ui/QRCodeDisplay.tsx
  • src/components/Intro.tsx
  • src/components/ui/CredentialDisplay.tsx
  • src/components/keyset/KeysetLoad.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use TypeScript with ESM, 2-space indentation, single quotes, and trailing commas
Order imports from shallow-to-deep
Use camelCase for utility function and variable names
Use SCREAMING_SNAKE_CASE for constants

Files:

  • src/components/keyset/KeysetCreate.tsx
  • tests/policy.test.ts
  • src/components/Help.tsx
  • src/components/keyset/ShareSaver.tsx
  • src/components/ui/QRCodeDisplay.tsx
  • src/lib/parseArgv.ts
  • tests/storage.test.ts
  • src/components/Intro.tsx
  • tests/paths.test.ts
  • tests/crypto.test.ts
  • src/cli.tsx
  • tests/naming.test.ts
  • src/components/ui/CredentialDisplay.tsx
  • src/components/keyset/KeysetLoad.tsx
  • tests/cli.parsing.test.ts
  • tests/cli.basic.test.ts
src/components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Name React components using PascalCase

Files:

  • src/components/keyset/KeysetCreate.tsx
  • src/components/Help.tsx
  • src/components/keyset/ShareSaver.tsx
  • src/components/ui/QRCodeDisplay.tsx
  • src/components/Intro.tsx
  • src/components/ui/CredentialDisplay.tsx
  • src/components/keyset/KeysetLoad.tsx
**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

**/*.test.ts: Allow colocated test files named feature.test.ts beside implementations
Test files should exercise both happy paths and failure modes

Files:

  • tests/policy.test.ts
  • tests/storage.test.ts
  • tests/paths.test.ts
  • tests/crypto.test.ts
  • tests/naming.test.ts
  • tests/cli.parsing.test.ts
  • tests/cli.basic.test.ts
llm/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep protocol prompts and agent scripts in llm/ and update them when UX flows change

Files:

  • llm/context/testing/test-architecture.md
  • llm/implementation/test-coverage-implementation.md
src/components/Intro.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

When adding a new command, update command examples in Intro.tsx if applicable

Files:

  • src/components/Intro.tsx
src/cli.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

src/cli.tsx: Argument parsing is handled manually in cli.tsx via parseArgv() and must support --flag value, --flag=value, and -f value forms
When adding command flags, extend parseArgv() in cli.tsx for any custom parsing logic

src/cli.tsx: Keep the CLI entrypoint in src/cli.tsx and use it to bootstrap Ink rendering
Keep CLI flags lower-case (e.g., --verbose)

Files:

  • src/cli.tsx
🧠 Learnings (19)
📚 Learning: 2025-10-03T23:45:30.161Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-cli PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-03T23:45:30.161Z
Learning: Applies to src/App.tsx : Extract flags from props in App.tsx and pass them to command components; add validation/defaults as needed

Applied to files:

  • src/components/keyset/KeysetCreate.tsx
  • src/lib/parseArgv.ts
  • src/cli.tsx
  • CLAUDE.md
  • src/components/keyset/KeysetLoad.tsx
📚 Learning: 2025-10-08T16:24:14.475Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-cli PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-08T16:24:14.475Z
Learning: Applies to src/keyset/**/*.ts : Document non-obvious flows with concise comments, especially around key lifecycle management

Applied to files:

  • src/components/keyset/KeysetCreate.tsx
  • tests/policy.test.ts
  • AGENTS.md
  • tests/storage.test.ts
  • tests/crypto.test.ts
  • src/components/keyset/KeysetLoad.tsx
📚 Learning: 2025-10-08T16:24:14.475Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-cli PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-08T16:24:14.475Z
Learning: Applies to src/keyset/**/*.ts : Keep key exchange and credential helpers under src/keyset/

Applied to files:

  • src/components/keyset/KeysetCreate.tsx
  • tests/policy.test.ts
  • tests/crypto.test.ts
  • src/components/keyset/KeysetLoad.tsx
📚 Learning: 2025-10-08T16:24:14.475Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-cli PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-08T16:24:14.475Z
Learning: Applies to src/__tests__/**/*.ts : Tests under src/__tests__/ should exercise both happy paths and failure modes

Applied to files:

  • tests/policy.test.ts
  • llm/context/testing/test-architecture.md
  • tests/storage.test.ts
  • tests/paths.test.ts
  • tests/crypto.test.ts
  • tests/naming.test.ts
  • tests/cli.parsing.test.ts
📚 Learning: 2025-10-08T16:24:14.475Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-cli PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-08T16:24:14.475Z
Learning: Applies to **/*.test.ts : Test files should exercise both happy paths and failure modes

Applied to files:

  • tests/policy.test.ts
  • llm/context/testing/test-architecture.md
  • tests/storage.test.ts
  • tests/paths.test.ts
  • tests/cli.parsing.test.ts
📚 Learning: 2025-10-03T23:45:30.161Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-cli PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-03T23:45:30.161Z
Learning: Applies to src/**/*.tsx : Use Ink components (<Box>, <Text>, etc.) for terminal UI and do not use HTML elements

Applied to files:

  • src/components/Help.tsx
  • src/components/keyset/ShareSaver.tsx
  • src/components/ui/QRCodeDisplay.tsx
  • AGENTS.md
  • src/components/Intro.tsx
  • src/components/ui/CredentialDisplay.tsx
  • src/components/keyset/KeysetLoad.tsx
📚 Learning: 2025-10-08T16:24:14.475Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-cli PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-08T16:24:14.475Z
Learning: Run the full test suite (npm test) before opening a PR and record any manual validation steps in the PR description

Applied to files:

  • llm/context/testing/test-architecture.md
  • AGENTS.md
📚 Learning: 2025-10-08T16:24:14.475Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-cli PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-08T16:24:14.475Z
Learning: Favor type coverage first; add node:test or vitest specs when logic branches or data transforms appear

Applied to files:

  • llm/context/testing/test-architecture.md
📚 Learning: 2025-10-08T16:24:14.475Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-cli PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-08T16:24:14.475Z
Learning: Applies to **/*.test.ts : Allow colocated test files named feature.test.ts beside implementations

Applied to files:

  • llm/context/testing/test-architecture.md
  • tests/paths.test.ts
  • tests/naming.test.ts
📚 Learning: 2025-10-08T16:24:14.475Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-cli PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-08T16:24:14.475Z
Learning: Applies to src/__tests__/**/*.ts : Allow tests under src/__tests__/

Applied to files:

  • llm/context/testing/test-architecture.md
  • tests/paths.test.ts
📚 Learning: 2025-10-08T16:24:14.475Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-cli PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-08T16:24:14.475Z
Learning: Applies to src/cli.tsx : Keep the CLI entrypoint in src/cli.tsx and use it to bootstrap Ink rendering

Applied to files:

  • src/components/ui/QRCodeDisplay.tsx
  • AGENTS.md
  • package.json
  • src/components/Intro.tsx
  • src/cli.tsx
  • CLAUDE.md
  • src/components/keyset/KeysetLoad.tsx
  • tests/cli.basic.test.ts
📚 Learning: 2025-10-03T23:45:30.161Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-cli PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-03T23:45:30.161Z
Learning: Applies to tsup.config.ts : tsup entry must be src/cli.tsx

Applied to files:

  • AGENTS.md
  • src/cli.tsx
📚 Learning: 2025-10-03T23:45:30.161Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-cli PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-03T23:45:30.161Z
Learning: Applies to tsup.config.ts : Build output should be dist/cli.js and include a shebang (#!/usr/bin/env node)

Applied to files:

  • AGENTS.md
📚 Learning: 2025-10-03T23:45:30.161Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-cli PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-03T23:45:30.161Z
Learning: Applies to src/components/Intro.tsx : When adding a new command, update command examples in Intro.tsx if applicable

Applied to files:

  • AGENTS.md
  • src/components/Intro.tsx
  • src/cli.tsx
  • CLAUDE.md
  • tests/cli.basic.test.ts
📚 Learning: 2025-10-03T23:45:30.161Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-cli PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-03T23:45:30.161Z
Learning: Applies to src/components/**/*.tsx : When adding a new command, implement it as a component under src/components/

Applied to files:

  • AGENTS.md
  • CLAUDE.md
📚 Learning: 2025-10-03T23:45:30.161Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-cli PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-03T23:45:30.161Z
Learning: Applies to src/cli.tsx : When adding command flags, extend parseArgv() in cli.tsx for any custom parsing logic

Applied to files:

  • src/lib/parseArgv.ts
  • src/cli.tsx
  • CLAUDE.md
  • tests/cli.parsing.test.ts
📚 Learning: 2025-10-03T23:45:30.161Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-cli PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-03T23:45:30.161Z
Learning: Applies to src/cli.tsx : Argument parsing is handled manually in cli.tsx via parseArgv() and must support --flag value, --flag=value, and -f value forms

Applied to files:

  • src/lib/parseArgv.ts
  • src/cli.tsx
  • CLAUDE.md
  • tests/cli.parsing.test.ts
📚 Learning: 2025-10-08T16:24:14.475Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-cli PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-08T16:24:14.475Z
Learning: Applies to src/cli.tsx : Keep CLI flags lower-case (e.g., --verbose)

Applied to files:

  • src/lib/parseArgv.ts
  • src/cli.tsx
  • CLAUDE.md
  • tests/cli.parsing.test.ts
📚 Learning: 2025-10-03T23:45:30.161Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-cli PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-03T23:45:30.161Z
Learning: Applies to src/App.tsx : When adding a new command, import the new component in App.tsx and add a corresponding case to the switch

Applied to files:

  • src/cli.tsx
🧬 Code graph analysis (10)
tests/policy.test.ts (2)
src/keyset/types.ts (1)
  • ShareFileRecord (16-28)
src/keyset/policy.ts (8)
  • DEFAULT_POLICY_DEFAULTS (9-12)
  • createDefaultPolicy (14-20)
  • ensurePolicy (97-100)
  • setPolicyDefaults (109-131)
  • upsertPeerPolicy (133-171)
  • removePeerPolicy (173-190)
  • updatePolicyTimestamp (102-107)
  • pruneEmptyPeers (192-199)
src/components/keyset/ShareSaver.tsx (1)
src/components/ui/CredentialDisplay.tsx (1)
  • CredentialDisplay (13-31)
tests/storage.test.ts (5)
src/keyset/types.ts (1)
  • ShareFileRecord (16-28)
tests/helpers/tmp.ts (1)
  • makeTmp (5-8)
src/keyset/storage.ts (4)
  • ensureShareDirectory (8-12)
  • readShareFiles (14-46)
  • saveShareRecord (48-63)
  • loadShareRecord (65-103)
src/keyset/paths.ts (1)
  • getShareDirectory (22-24)
src/keyset/crypto.ts (1)
  • SHARE_FILE_VERSION (7-7)
tests/paths.test.ts (1)
src/keyset/paths.ts (2)
  • getAppDataPath (4-20)
  • getShareDirectory (22-24)
tests/crypto.test.ts (1)
src/keyset/crypto.ts (16)
  • SHARE_FILE_VERSION (7-7)
  • SHARE_FILE_PBKDF2_ITERATIONS (8-8)
  • SHARE_FILE_PBKDF2_PREVIOUS_ITERATIONS (9-9)
  • SHARE_FILE_PBKDF2_LEGACY_ITERATIONS (10-10)
  • SHARE_FILE_PASSWORD_ENCODING (11-11)
  • SHARE_FILE_SALT_LENGTH_BYTES (12-12)
  • SHARE_FILE_SALT_PBKDF2_EXPANDED_BYTES (13-13)
  • SHARE_FILE_IV_LENGTH_BYTES (14-14)
  • SHARE_FILE_IV_LEGACY_LENGTH_BYTES (15-15)
  • getIterationsForShareVersion (51-57)
  • deriveSecret (79-90)
  • encryptPayload (92-111)
  • decryptPayload (113-128)
  • randomSaltHex (130-132)
  • assertShareCredentialFormat (134-138)
  • decryptShareCredential (232-284)
tests/naming.test.ts (2)
src/keyset/paths.ts (1)
  • getShareDirectory (22-24)
tests/helpers/tmp.ts (1)
  • makeTmp (5-8)
src/components/ui/CredentialDisplay.tsx (1)
src/components/ui/QRCodeDisplay.tsx (1)
  • QRCodeDisplay (12-78)
src/components/keyset/KeysetLoad.tsx (1)
src/components/ui/CredentialDisplay.tsx (1)
  • CredentialDisplay (13-31)
tests/cli.parsing.test.ts (1)
src/lib/parseArgv.ts (2)
  • parseArgv (11-91)
  • toBool (93-101)
tests/cli.basic.test.ts (1)
tests/helpers/runCli.ts (1)
  • runCli (21-82)
🪛 markdownlint-cli2 (0.18.1)
llm/context/testing/test-architecture.md

17-17: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🔇 Additional comments (41)
AGENTS.md (2)

7-7: LGTM! Documentation correctly reflects bun-based workflow.

The updated commands align with the bun scripts defined in package.json and provide clear guidance for developers using the bun runtime.


13-13: LGTM! Test command documentation updated appropriately.

The change from npm-based to bun-based test execution is consistent with the project's tooling direction.

src/components/Intro.tsx (3)

1-1: LGTM! React 19 compatible import pattern.

Using named imports for useState and useEffect is the standard approach and works correctly with React 19.1.1.


4-86: LGTM! Well-structured animation frames.

The ASCII art frames create a smooth rotation effect with clear comments indicating the rotation angle. The 8-frame sequence provides good visual continuity.


94-102: LGTM! Animation logic is correct and properly cleaned up.

The animation implementation:

  • Correctly cycles through frames using modulo arithmetic
  • Properly cleans up the interval on unmount
  • Uses an appropriate 200ms delay for smooth animation

Also applies to: 107-107

tests/paths.test.ts (6)

1-5: LGTM! Correct imports with .js extension.

The imports correctly use the .js extension for the TypeScript ESM requirement, as specified in the coding guidelines.


11-24: LGTM! Proper environment variable isolation.

The test correctly:

  • Saves the original environment variable
  • Sets a test value
  • Verifies the override behavior
  • Properly restores or deletes the variable in the finally block

This follows the environment-variable testing patterns documented in the test architecture.


26-41: LGTM! Edge case properly tested.

The test correctly verifies that an empty string in IGLOO_APPDATA falls through to platform-specific logic rather than being used as-is. The assertions confirm non-empty fallback behavior.


43-81: LGTM! Comprehensive platform-specific testing.

The test validates platform-appropriate paths for:

  • macOS: ~/Library/Application Support
  • Windows: AppData or appdata
  • Linux: XDG_CONFIG_HOME or ~/.config

This approach tests actual platform behavior while maintaining environment isolation.


83-96: LGTM! Absolute path requirements verified.

Both tests correctly assert that returned paths are absolute and meet structural expectations (e.g., ending with igloo/shares). The cleanup logic is consistent across all tests.

Also applies to: 117-131


102-115: LGTM! Path construction properly validated.

The test verifies that getShareDirectory correctly appends igloo/shares to the app data path, using environment variable override for isolation.

package.json (1)

37-37: No action required. The qrcode package is already at the latest version (1.5.4) with no known security vulnerabilities. The @types/qrcode dependency (^1.5.6) is also current and secure.

tests/naming.test.ts (1)

1-143: LGTM! Comprehensive test coverage for naming utilities.

The test suite thoroughly covers all naming functions with both happy paths and edge cases:

  • Slugification logic (casing, special chars, trimming, empty inputs)
  • Share ID construction with slugification
  • File path building
  • Name existence checking with filesystem interactions

Test organization is clear with section markers, and proper cleanup is used throughout.

tests/storage.test.ts (1)

1-355: LGTM! Excellent test coverage for storage functionality.

The test suite is comprehensive and well-organized:

  • ensureShareDirectory: Tests creation, idempotence, overrides, and path correctness
  • readShareFiles: Tests empty directories, valid/invalid JSON, non-JSON files, malformed data, filepath attachment, and policy normalization
  • saveShareRecord: Tests file creation, version/timestamp injection, policy pruning, and directory overrides
  • loadShareRecord: Tests loading by ID/filepath, missing files, and policy normalization
  • Integration: Validates full roundtrip consistency

Test structure follows best practices with proper setup/teardown, helper functions, and clear section organization.

Based on learnings, the test suite appropriately exercises both happy paths and failure modes for the keyset storage functionality.

tests/policy.test.ts (1)

1-535: LGTM! Exceptional test coverage for policy functionality.

The test suite is extremely thorough and well-crafted:

  • Constants & Defaults: Validates exported constants and default policy creation
  • Boolean Coercion: Extensive testing of string-to-boolean conversion (true/false, 1/0, yes/no, on/off, case insensitivity, invalid values)
  • Policy Management: Tests normalization, peer pubkey handling, empty string filtering, timestamp fallbacks
  • CRUD Operations: Comprehensive coverage of setPolicyDefaults, upsertPeerPolicy, removePeerPolicy with edge cases
  • Data Integrity: Excellent immutability test verifying all functions return new objects without mutating inputs

The test organization with clear section markers and helper functions makes the suite highly maintainable.

Based on learnings, the test suite appropriately exercises both happy paths and failure modes for the policy module.

tests/crypto.test.ts (1)

1-471: LGTM! Comprehensive crypto test coverage with excellent edge case handling.

The test suite thoroughly validates the crypto module:

  • Constants: Type and value validation for all exported constants
  • Key Derivation: Tests determinism, sensitivity to inputs (password/salt/iterations/encoding)
  • Encryption: Validates output format, base64url encoding, determinism with explicit IVs, and randomness
  • Decryption: Tests successful roundtrips, wrong keys, corrupted/truncated data, and legacy 12-byte IV compatibility
  • Share Credentials: Tests v1 and legacy formats, wrong passwords (with appropriate timeout), metadata-driven parameters
  • Integration: Full roundtrip validation ensuring consistency

The manual construction of legacy-format encrypted payloads (lines 202-223, 325-357) demonstrates thorough testing of backward compatibility.

Based on learnings, the test suite appropriately exercises both happy paths and failure modes for the crypto module.

CLAUDE.md (1)

1-147: LGTM! Excellent documentation updates reflecting the new architecture.

The documentation comprehensively captures the PR changes:

  • Workflow Updates: Clear migration from npm to bun-based commands
  • Command Structure: Well-organized namespace hierarchy (share, keyset, keys) with clear examples
  • Architecture: Detailed component organization showing the new structure
  • Core Library: Documents the non-UI utilities under src/keyset/
  • Dependencies: Updated to reflect @frostr/bifrost, @frostr/igloo-core, and other key packages
  • Environment Variables: New debug and test options documented

The guidance is clear and actionable for developers working with the codebase.

src/components/keyset/KeysetCreate.tsx (2)

133-133: LGTM: QR flag derivation is clean and handles both naming conventions.

The logic correctly checks both flags.qr and flags['show-qr'] with explicit boolean comparison, and the bracket notation is appropriate for the hyphenated flag name.


499-499: LGTM: QR flag properly forwarded to ShareSaver.

The showQR prop is cleanly passed through to the ShareSaver component, enabling QR code display functionality.

src/cli.tsx (1)

8-9: LGTM: Clean refactoring to centralized argument parsing.

Moving parseArgv, toBool, and related types to a dedicated module improves code organization and testability. The comment on line 47 helpfully documents the change.

Also applies to: 47-47

src/components/Help.tsx (1)

4-14: LGTM: Nice visual enhancement with proper constant naming.

The ASCII art icon adds visual polish to the help screen. The constant follows the SCREAMING_SNAKE_CASE convention and is rendered correctly using Ink's Text component.

Also applies to: 24-26

src/components/ui/CredentialDisplay.tsx (1)

1-31: LGTM: Well-designed component with clear single responsibility.

This new component provides a clean abstraction for displaying credentials with optional QR codes. The implementation correctly uses Ink primitives, follows TypeScript conventions, and includes sensible defaults for colors. The conditional QR rendering integrates well with the QRCodeDisplay component.

src/components/keyset/KeysetLoad.tsx (4)

2-2: LGTM: Clean integration of QR visibility support.

The imports, flag derivation, and state initialization are well-structured. The optional chaining on flags is correct given that flags is optional in the component props.

Also applies to: 6-6, 30-32


147-151: LGTM: Keyboard handler properly guarded.

The Q key toggle is appropriately limited to raw mode and the result phase via the isActive condition, preventing interference with interactive prompts.


289-305: LGTM: CredentialDisplay integration enhances UX.

Replacing plain text credentials with the CredentialDisplay component provides a consistent presentation and seamless QR code support. The toggle hint is appropriately conditional on raw mode availability.


336-352: LGTM: Finish prompt complements the interactive flow.

The finish prompt in raw mode provides a clean exit mechanism. The auto-exit logic for non-interactive environments (lines 119-134) ensures the component doesn't hang in test scenarios.

tests/cli.basic.test.ts (1)

21-30: LGTM! Pattern-based completion detection is the right approach.

The use of successPattern to detect when the intro screen content renders is appropriate for testing continuously running animated UI. The comment clearly explains the rationale, and the timedOut assertion ensures the test doesn't hang indefinitely.

llm/context/testing/test-architecture.md (1)

1-309: Excellent test architecture documentation.

This comprehensive documentation clearly describes the test framework, organization, patterns, helpers, and best practices. It will be valuable for maintainers and contributors to understand the testing strategy and conventions.

src/components/keyset/ShareSaver.tsx (4)

1-32: LGTM! Clean integration of QR display prop.

The addition of the showQR prop with a default value of false is well-designed, making QR code display opt-in. The imports follow the project's ESM conventions with .js extensions.


59-100: LGTM! Well-implemented QR toggle with good UX.

The keyboard interaction is properly scoped via isActive: shouldPrompt, ensuring the Q key toggle only works when user input is expected. The hint message clearly indicates the current state and available action.


102-131: LGTM! Good refactoring to use CredentialDisplay component.

Migrating from inline Box/Text blocks to the CredentialDisplay component reduces duplication and centralizes credential rendering logic. The QR visibility is correctly controlled via the qrVisible state.


391-453: LGTM! Consistent QR hint placement across render phases.

The QR hint is appropriately shown only when shouldPrompt is true, ensuring users see the toggle instruction in interactive modes while keeping automated/non-interactive runs clean.

tests/cli.parsing.test.ts (3)

1-40: LGTM! Well-structured basic positional tests.

The tests correctly validate default command behavior, positional parsing, and help/version flag detection. The import paths follow the project's ESM conventions with .js extensions.


42-142: LGTM! Comprehensive flag parsing coverage.

The tests thoroughly exercise flag parsing including inline formats (--flag=value), empty values, aliases, and boolean detection. The alias tests correctly verify that original short flags are deleted after mapping, preventing duplicate entries.


144-181: LGTM! Thorough toBool function coverage.

The tests validate all expected string values, case-insensitivity, boolean passthrough, and fallback behavior for undefined and invalid inputs. This provides excellent coverage of the boolean coercion utility.

src/components/ui/QRCodeDisplay.tsx (3)

1-19: LGTM! Clean component setup with good defaults.

The props are well-typed with sensible defaults (small = true for compact terminal output, labelColor = 'cyan' for consistency). The state structure appropriately separates QR string content from error messages.


21-52: LGTM! Proper async handling with cancellation support.

The cancellation pattern correctly prevents state updates after component unmount, avoiding memory leaks and React warnings. The QR generation uses appropriate parameters for terminal display (type: 'terminal', errorCorrectionLevel: 'M').


54-78: LGTM! Clear three-state rendering with good UX.

The rendering logic appropriately handles error, loading, and success states with clear visual feedback. The component correctly uses Ink's Box and Text components for terminal UI, adhering to the project's coding guidelines.

src/lib/parseArgv.ts (3)

1-9: LGTM! Clean type definitions.

The type definitions are well-structured and appropriately capture the parsing result. The Flags type correctly allows both string and boolean values, matching the parsing logic below.


11-66: Excellent implementation of CLI argument parsing.

The parsing logic correctly handles all required forms per the learnings:

  • --flag=value (including empty string for --flag=)
  • --flag value (space-separated)
  • -f value (short form with value)

Boolean flags are appropriately defaulted when no value follows, and the edge case of standalone - is correctly handled at line 53. Based on learnings, this aligns with the manual parsing requirements.


93-101: Well-implemented boolean conversion utility.

The toBool function handles common boolean string representations correctly with sensible normalization (trim + lowercase). The default to false for undefined or unrecognized values is a safe and reasonable choice.

@AustinKelsay AustinKelsay merged commit a32d538 into master Jan 6, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant