/** * secrets-store-paths.ts, where a secret physically lives, per scope. * * Three tiers, and the difference between them is a real directory rather than * a label: * * project, `/.goodvibes//secrets.enc`, walked up the ancestor * chain nearest-first. A credential that belongs to one checkout. * * user , `/.goodvibes//secrets.enc`. This operator's own * credential, on this machine, for this surface. * * daemon , `/secrets.enc`, defaulting to * `~/.goodvibes/daemon/secrets.enc`: the same directory that already * holds `settings.json`, `operator-tokens.json` and the rest of the * daemon's own state (see daemon-config-tier.ts). Deliberately NOT * surface-scoped, the daemon is one process whichever product * launched it, so a credential it executes with has exactly one * home, and the TUI, the agent and the web UI all read that one. * * Read order puts the daemon tier FIRST among the file stores, which is the * secret-store form of the rule daemon-config-tier.ts already states for * settings: a stale copy left behind in a surface silo must never beat the * daemon's own. The tier is opt-in and empty until something writes to it * explicitly, so this changes nothing for a store that has no daemon secrets. * The environment still wins over all three. */ /** Which tier owns a stored secret. */ export type SecretScope = 'project' | 'user' | 'daemon'; /** Whether a store is encrypted at rest. */ export type SecretStorageMedium = 'secure' | 'plaintext'; /** Where a resolved secret was read from. */ export type SecretSource = 'env' | 'project-secure' | 'project-plaintext' | 'user-secure' | 'user-plaintext' | 'daemon-secure' | 'daemon-plaintext'; /** One store file, with the tier and medium it represents. */ export interface SecretStorePath { readonly source: Exclude; readonly path: string; readonly secure: boolean; readonly scope: SecretScope; } /** The roots and explicit overrides the path builders need. */ export interface SecretStoreLayout { readonly projectRoot: string; readonly globalHome: string; readonly daemonHome: string; readonly surfaceRoot: string; readonly secureProjectFilePath?: string | undefined; readonly secureUserFilePath?: string | undefined; readonly secureDaemonFilePath?: string | undefined; readonly plaintextProjectFilePath?: string | undefined; readonly plaintextUserFilePath?: string | undefined; readonly plaintextDaemonFilePath?: string | undefined; } /** The daemon's state root under a user home: `/.goodvibes/daemon`. */ export declare function defaultDaemonSecretHome(globalHome: string): string; /** * Every OTHER surface's user-tier store under this home. * * `secretReadOrder` walks one surface root, this manager's own, which is * right for resolution: the agent has no business resolving a credential out of * the TUI's silo at read time, and a daemon that did would be reading a value * nobody asked it to. * * Migration is the exception, and the owner's machine is why. Their Telegram * token sat in `~/.goodvibes/agent/secrets.enc` while the daemon booted rooted * at `daemon` and enumerated only its own store. The credential was one * directory away, readable, and invisible to the only code that could have * lifted it, so it was never lifted by anything, ever. * * Discovered by listing `/.goodvibes/` rather than from a list of known * surface names: a product the SDK has never heard of still leaves its store * there, and a hand-maintained list is the thing that goes stale. Entries * holding no store are skipped, so every path returned exists. */ export declare function siblingSurfaceSecretStores(layout: SecretStoreLayout, listDirectory: (path: string) => readonly string[], fileExists: (path: string) => boolean): SecretStorePath[]; /** * The stores a lookup consults, in the order it consults them. First match * wins, so the daemon tier leads: see the header for why. */ export declare function secretReadOrder(layout: SecretStoreLayout, includePlaintext: boolean): SecretStorePath[]; /** Every store this manager could touch, policy aside. Used by delete/inspect. */ export declare function allSecretStores(layout: SecretStoreLayout): SecretStorePath[]; /** The single store a write of `scope`/`medium` lands in. */ export declare function secretWriteTarget(layout: SecretStoreLayout, scope: SecretScope, medium: SecretStorageMedium): SecretStorePath; //# sourceMappingURL=secrets-store-paths.d.ts.map