import type { PermissionCategory } from '../permissions/index.js'; import type { PermissionPromptRequest, PermissionPromptDecision } from '../permissions/index.js'; type AskCallback = (request: PermissionPromptRequest) => Promise; /** * Wrap the permission machinery's final ask callback with the workspace trust * gate. This runs inside PermissionManager's own layer chain (it IS the ask * layer), so it composes with, and cannot drift from, the real machinery. * * - Trusted workspace: every category passes through to `ask` unchanged. * - Restricted workspace with an EXPLICIT prior decision: non-read categories * are denied outright, same as before, that IS what "restricted" means * once the user has actually chosen it. * - Undecided workspace (no decision yet, ever): the first non-read request * raises `requestTrustDecision()`, one modal, persisted via `setLevel`, * and, if the answer is 'trusted', the ORIGINAL request is forwarded to * `ask` so the very thing the user just approved actually happens instead * of failing anyway. Concurrent requests that arrive before the first * decision resolves await the same in-flight prompt rather than opening a * second one. */ export declare function trustGatedAsk(manager: Pick, ask: AskCallback, requestTrustDecision: () => Promise): AskCallback; export type WorkspaceTrustLevel = 'trusted' | 'restricted'; /** * detectPriorWorkspaceState, true if /.goodvibes already * holds GoodVibes RUNTIME state from a prior session. Deliberately keyed on * generated state (sessions/checkpoints/state/memory/onboarding marker), not on * committed scaffolding like .goodvibes/agents or GOODVIBES.md, so a checked-out * template does not read as "previously used". MUST be sampled before any * service initializes the workspace this session (bootstrap-core samples it * before createRuntimeServices), or this-run scaffolding would look like prior * use. */ export declare function detectPriorWorkspaceState(workingDirectory: string, surfaceRoot: string): boolean; export interface WorkspaceTrustPaths { readonly projectGoodVibesRoot: string; resolveProjectPath(...segments: string[]): string; } /** Read-only view of the persisted trust decision, for status/doctor reporting. */ export interface PersistedWorkspaceTrustView { /** 'trusted' | 'restricted' when a decision exists; 'undecided' when none is persisted yet. */ readonly level: WorkspaceTrustLevel | 'undecided'; readonly grandfathered: boolean; } /** * readPersistedWorkspaceTrust, read /.goodvibes//trust.json WITHOUT the * side effects of WorkspaceTrustManager.load() (which grandfathers and persists). * Reporting surfaces (`status`/`doctor`) must never mutate trust state, so they * use this pure reader instead of constructing a manager. */ export declare function readPersistedWorkspaceTrust(paths: WorkspaceTrustPaths, surfaceRoot: string): PersistedWorkspaceTrustView; export interface WorkspaceTrustManagerOptions { readonly shellPaths: WorkspaceTrustPaths; /** The owning product's storage scope, the `` segment trust.json sits under. */ readonly surfaceRoot: string; } export declare class WorkspaceTrustManager { private level; private grandfathered; private loaded; private readonly store; constructor(options: WorkspaceTrustManagerOptions); /** * Load the persisted decision, if one exists. No grandfathering: a * workspace with no persisted decision stays undecided (the gate treats it * as restricted, and the first non-read tool request raises the trust * question via `trustGatedAsk`'s `requestTrustDecision` callback), even * one that already carries prior GoodVibes runtime state. `grandfathered` * on an already-persisted decision is read-only history from before this * fix (status/doctor still report it honestly); nothing new is ever * grandfathered. */ load(): Promise; isDecided(): boolean; /** Undecided workspaces read as 'restricted', the safe default before a choice. */ getLevel(): WorkspaceTrustLevel; isTrusted(): boolean; wasGrandfathered(): boolean; setLevel(level: WorkspaceTrustLevel): Promise; /** * The restriction rule the permission machinery consults. Read tools always * run (read-only exploration is the whole point of "restricted"); every other * category (write / execute / delegate) is denied until the workspace is * trusted. */ isCategoryAllowed(category: PermissionCategory): boolean; private persist; } export {}; //# sourceMappingURL=workspace-trust.d.ts.map