import type { JsonRecord } from './route-helpers.js'; import type { AutomationSurfaceKind } from './runtime-route-types.js'; export type { AutomationSurfaceKind }; export type DaemonApiClientKind = 'web' | 'slack' | 'discord' | 'ntfy' | 'webhook' | 'telegram' | 'google-chat' | 'signal' | 'whatsapp' | 'imessage' | 'msteams' | 'bluebubbles' | 'mattermost' | 'matrix' | 'daemon'; export type AutomationRouteBindingKind = string; export type AutomationSessionPolicy = string; export type AutomationThreadPolicy = string; export type AutomationDeliveryGuarantee = string; export type WatcherKind = string; export interface ConfigManagerLike { get(key: string): unknown; getAll(): Record; setDynamic(key: string, value: unknown): void; /** * Absolute path of the settings file this manager writes to. * * Reported back on every config write. A caller and the host it is talking to * routinely own DIFFERENT surface-scoped stores (`~/.goodvibes/agent/` versus * `~/.goodvibes/tui/`), so "the setting was saved" is ambiguous until the file * is named: a value written to the connected host is invisible to the caller's * own store and vice versa, and reading it back locally shows the old value. */ getConfigPath?(): string; /** * Which store the key resolves from and whether the DAEMON owns it. * * Ownership, not the caller's identity, decides where a value belongs: a * daemon-owned key (chat surfaces, control-plane binding, watchers, device * grants, retention) has exactly one home regardless of which client asked. * Reported on every write so a caller never has to infer it from a path. */ describeConfigKeySource?(key: string): { readonly tier: string; readonly daemonOwned: boolean; readonly daemonTierPath: string | null; }; } export interface IntegrationApprovalSnapshotSourceLike { getApprovalSnapshot(): unknown; } export interface PlatformServiceManagerLike { status(): Record; install(): unknown; start(): unknown; stop(): unknown; restart(): unknown; uninstall(): unknown; } export interface RouteBindingRecordInput { readonly id?: string | undefined; readonly kind: AutomationRouteBindingKind; readonly surfaceKind: AutomationSurfaceKind; readonly surfaceId: string; readonly externalId: string; readonly sessionPolicy?: AutomationSessionPolicy | undefined; readonly threadPolicy?: AutomationThreadPolicy | undefined; readonly deliveryGuarantee?: AutomationDeliveryGuarantee | undefined; readonly threadId?: string | undefined; readonly channelId?: string | undefined; readonly sessionId?: string | null | undefined; readonly jobId?: string | null | undefined; readonly runId?: string | null | undefined; readonly title?: string | undefined; readonly metadata: Record; } export interface RouteBindingPatchInput { readonly sessionPolicy?: AutomationSessionPolicy | undefined; readonly threadPolicy?: AutomationThreadPolicy | undefined; readonly deliveryGuarantee?: AutomationDeliveryGuarantee | undefined; readonly threadId?: string | undefined; readonly channelId?: string | undefined; readonly sessionId?: string | null | undefined; readonly jobId?: string | null | undefined; readonly runId?: string | null | undefined; readonly title?: string | undefined; readonly metadata?: Record | undefined; } export interface RouteBindingManagerLike { listBindings(): readonly unknown[]; upsertBinding(input: RouteBindingRecordInput): Promise; patchBinding(bindingId: string, input: RouteBindingPatchInput): Promise; removeBinding(bindingId: string): Promise; } export interface WatcherSourceRecord { readonly id: string; readonly kind: string; readonly label: string; readonly enabled: boolean; readonly createdAt: number; readonly updatedAt: number; readonly metadata: Record; } export interface WatcherRecord { readonly id: string; readonly label: string; readonly kind: WatcherKind; readonly source: WatcherSourceRecord; readonly intervalMs?: number | undefined; readonly metadata: Record; } export interface WatcherRegistryLike { list(): readonly unknown[]; removeWatcher(watcherId: string): boolean; registerWatcher(input: { readonly id: string; readonly label: string; readonly kind: WatcherKind; readonly source: WatcherSourceRecord; readonly intervalMs: number; readonly metadata: Record; readonly run?: (() => string) | undefined; }): WatcherRecord; getWatcher(watcherId: string): WatcherRecord | null; startWatcher(watcherId: string): WatcherRecord | null; stopWatcher(watcherId: string, reason: string): WatcherRecord | null; runWatcherNow(watcherId: string): Promise; } /** * How far an approval decision reaches. Mirrors the broker's remember-tier * union (a generalizing tier persists a durable rule and sweeps queued asks * it covers; 'session' is the classic in-memory cache). Kept in sync with * the operator contract's rememberTier enum. */ export type ApprovalRememberTier = 'session' | 'exact' | 'command-class' | 'path' | 'tool'; export declare const APPROVAL_REMEMBER_TIERS: readonly ApprovalRememberTier[]; export interface ApprovalBrokerLike { claimApproval(approvalId: string, actor: string, actorSurface: string, note?: string): Promise; cancelApproval(approvalId: string, actor: string, actorSurface: string, note?: string): Promise; resolveApproval(approvalId: string, input: { readonly approved: boolean; readonly remember: boolean; readonly actor: string; readonly actorSurface: string; readonly note?: string | undefined; /** * Optional per-hunk selection (edit-tool approvals only). The broker * filters the approval's own edit list to these indices server-side. An * out-of-range index or a non-edit approval throws a 400-tagged error the * route layer converts to an HTTP 400. */ readonly selectedHunks?: readonly number[] | undefined; /** How far this decision reaches; a generalizing tier persists a durable rule. */ readonly rememberTier?: ApprovalRememberTier | undefined; /** User free-text; on deny it rides the structured declined result. */ readonly reason?: string | undefined; /** * Argument-modifying approval payload (e.g. the typed answer to a * command's terminal prompt). selectedHunks, when present, supersedes it. */ readonly modifiedArgs?: Record | undefined; }): Promise; } export interface WorkspaceSwapManagerLike { getCurrentWorkingDir(): string; requestSwap(newWorkingDir: string): Promise<{ ok: true; previous: string; current: string; } | { ok: false; code: 'WORKSPACE_BUSY'; reason: string; retryAfter: number; } | { ok: false; code: 'INVALID_PATH'; reason: string; }>; } /** * Secret-free status metadata for a single credential held in the daemon's * shared store (or overridden by an environment variable). This is the ONLY * shape the credential-read wire method (`credentials.get`) ever returns, the * plaintext secret value never crosses the wire. `usable` reflects a real * in-process resolution attempt, so a configured-but-unresolvable reference * (e.g. a broken `op://` ref) reports `configured: true, usable: false`. */ export interface CredentialStatusRecord { readonly key: string; /** A value exists in the shared store (or, for a named probe, in env). */ readonly configured: boolean; /** The value/reference resolved to non-empty plaintext in-process. */ readonly usable: boolean; /** Where the value was found: 'env' | 'daemon-secure' | 'user-secure' | … */ readonly source: string; /** 'daemon' | 'user' | 'project' | 'env'. */ readonly scope: string; /** Backed by an encrypted store (vs plaintext). */ readonly secure: boolean; /** A same-named environment variable overrides the stored value. */ readonly overriddenByEnv: boolean; /** External-reference provider, when the stored value is a secret ref. */ readonly refSource?: string | undefined; } /** * Reads credential STATUS (never plaintext) from the daemon's shared secret * store. Enumeration (`list`) is over stored keys only, never `process.env`, * so it cannot leak the names of unrelated environment variables. A named probe * (`get`) may consult env for that one caller-named key. */ export interface CredentialStatusProviderLike { list(): Promise; get(key: string): Promise; } export interface DaemonSystemRouteContext { readonly approvalBroker: ApprovalBrokerLike; readonly configManager: ConfigManagerLike; /** * Secret-free credential-status source for `credentials.get`. Null when the * daemon host wires no shared secret store, the handler then reports an * honest 503 rather than a false "no credentials". */ readonly credentialStatus: CredentialStatusProviderLike | null; readonly integrationHelpers: IntegrationApprovalSnapshotSourceLike | null; readonly inspectInboundTls: (surface: 'controlPlane' | 'httpListener') => unknown; readonly inspectOutboundTls: () => unknown; readonly isValidConfigKey: (key: string) => boolean; readonly parseJsonBody: (req: Request) => Promise; readonly parseOptionalJsonBody: (req: Request) => Promise; readonly platformServiceManager: PlatformServiceManagerLike; readonly recordApiResponse: (req: Request, path: string, response: Response, clientKind?: DaemonApiClientKind) => Response; readonly requireAdmin: (req: Request) => Response | null; readonly requireAuthenticatedSession: (req: Request) => { username: string; roles: readonly string[]; } | null; readonly routeBindings: RouteBindingManagerLike; /** Manages runtime.workingDir swaps. Null when workspace swapping is not available. */ readonly swapManager: WorkspaceSwapManagerLike | null; readonly watcherRegistry: WatcherRegistryLike; } //# sourceMappingURL=system-route-types.d.ts.map