From 8e72ed871420271f7ec49d7cb0092cc36bea4fdc Mon Sep 17 00:00:00 2001 From: adlee-was-taken Date: Mon, 27 Apr 2026 18:12:04 -0400 Subject: [PATCH] feat(ext/setup): vault-presence probe helper Co-Authored-By: Claude Sonnet 4.6 --- extension/src/setup/__tests__/probe.test.ts | 49 +++++++++++++++++++++ extension/src/setup/probe.ts | 23 ++++++++++ 2 files changed, 72 insertions(+) create mode 100644 extension/src/setup/__tests__/probe.test.ts create mode 100644 extension/src/setup/probe.ts diff --git a/extension/src/setup/__tests__/probe.test.ts b/extension/src/setup/__tests__/probe.test.ts new file mode 100644 index 0000000..2901cd8 --- /dev/null +++ b/extension/src/setup/__tests__/probe.test.ts @@ -0,0 +1,49 @@ +import { describe, expect, it, vi } from 'vitest'; +import { probeVault } from '../probe'; +import type { GitHost } from '../../service-worker/git-host'; + +function fakeHost(opts: { + relicarioFiles?: string[]; + rootFiles?: string[]; + commit?: { sha: string; author: string; date: string } | null; +} = {}): GitHost { + return { + listDir: vi.fn().mockImplementation(async (p: string) => { + if (p === '.relicario') return opts.relicarioFiles ?? []; + if (p === '') return opts.rootFiles ?? []; + return []; + }), + lastCommit: vi.fn().mockResolvedValue(opts.commit ?? null), + readFile: vi.fn(), writeFile: vi.fn(), writeFileCreateOnly: vi.fn(), + deleteFile: vi.fn(), putBlob: vi.fn(), getBlob: vi.fn(), deleteBlob: vi.fn(), + }; +} + +describe('probeVault', () => { + it('reports exists=false when repo is empty', async () => { + const host = fakeHost(); + expect(await probeVault(host)).toEqual({ exists: false }); + }); + + it('reports exists=true when manifest.enc is present', async () => { + const host = fakeHost({ + rootFiles: ['manifest.enc', 'README.md'], + commit: { sha: 'abc1234', author: 'Alice', date: '2026-04-20T12:00:00Z' }, + }); + const result = await probeVault(host); + expect(result.exists).toBe(true); + expect(result.lastCommit?.author).toBe('Alice'); + }); + + it('reports exists=true when only .relicario/salt is present (partial init)', async () => { + const host = fakeHost({ relicarioFiles: ['salt'] }); + expect((await probeVault(host)).exists).toBe(true); + }); + + it('omits lastCommit field when API returns null', async () => { + const host = fakeHost({ rootFiles: ['manifest.enc'], commit: null }); + const result = await probeVault(host); + expect(result.exists).toBe(true); + expect(result.lastCommit).toBeUndefined(); + }); +}); diff --git a/extension/src/setup/probe.ts b/extension/src/setup/probe.ts new file mode 100644 index 0000000..6f13928 --- /dev/null +++ b/extension/src/setup/probe.ts @@ -0,0 +1,23 @@ +import type { GitHost } from '../service-worker/git-host'; + +export interface VaultProbe { + exists: boolean; + lastCommit?: { sha: string; author: string; date: string }; +} + +/// Detect whether the configured remote already contains a relicario vault. +/// Considered present if any of: .relicario/salt, .relicario/params.json, +/// manifest.enc exists. Best-effort metadata fetch via lastCommit(). +export async function probeVault(host: GitHost): Promise { + const [relicarioFiles, rootFiles] = await Promise.all([ + host.listDir('.relicario'), + host.listDir(''), + ]); + const exists = + relicarioFiles.includes('salt') || + relicarioFiles.includes('params.json') || + rootFiles.includes('manifest.enc'); + if (!exists) return { exists: false }; + const lastCommit = await host.lastCommit('manifest.enc'); + return lastCommit ? { exists, lastCommit } : { exists }; +}