import type { CreateLoopInput, CreateWorkflowInput, Loop, LoopRun, LoopStatus, PublicWorkflowEvent, RunReceipt, RunStatus, WorkflowInvocation, WorkflowRun, WorkflowSpec, WorkflowStepRun, WorkflowWorkItem, WorkflowWorkItemStatus, WriteRunReceiptInput } from "../../types.js"; import { type PublicLoopMutationResult, LoopMutationEnvelope, LoopMutationLookupCaps } from "../operation-contract.js"; import type { Goal, GoalPlanNode, GoalRun, GoalStatus } from "../goal/types.js"; import type { HasnaStorageClient } from "@hasna/contracts/client/storage"; type Env = Record; import { Store } from "../store.js"; import type { PruneHistoryOptions, PruneHistorySummary } from "../store.js"; /** Which transport backs a resolved store (for banners/diagnostics only). */ export type StoreTransport = "file" | "api"; export interface StuckRunCandidate { runId: string; loopId: string; snapshotId: string; } export interface StuckRunCandidateReport { state: "clear" | "stuck"; expiredBefore: string; candidates: StuckRunCandidate[]; truncated: boolean; } export interface StuckRunReconciliationOutcome { runId: string; outcome: "recovered" | "already_recovered" | "conflict" | "operation_reconciliation_required"; reason?: string; } export interface StuckRunReconciliationReport { outcomes: StuckRunReconciliationOutcome[]; } /** * Thrown when a command routed through the API store hits an operation that * the control-plane `/v1` API does not yet expose. Failing loudly here is * deliberate: the alternative (silently reading/writing the on-box sqlite * island while the machine is connected to a control plane) is exactly the * split-brain bug we are removing. */ export declare class CloudUnsupportedError extends Error { constructor(operation: string); } /** * The single data interface for the Loops client. Both {@link LocalStore} * and {@link ApiStore} implement it; callers hold a `LoopStore` and never know * (or branch on) which one. Every method is async so the two transports share * one surface. */ export interface LoopStore { readonly transport: StoreTransport; close(): Promise; createLoop(input: CreateLoopInput, from?: Date): Promise; getLoop(id: string): Promise; findLoopByName(name: string): Promise; requireLoop(idOrName: string): Promise; requireUniqueLoop(idOrName: string): Promise; listLoops(opts?: { status?: LoopStatus; labels?: string[]; limit?: number; offset?: number; archived?: boolean; includeArchived?: boolean; name?: string; }): Promise; countLoops(status?: LoopStatus, opts?: { archived?: boolean; includeArchived?: boolean; }): Promise; updateLoop(id: string, patch: Partial>): Promise; mutateLoop(envelope: LoopMutationEnvelope): Promise; getLoopMutationResult(operationId: string, stepId: string, caps: LoopMutationLookupCaps): Promise; renameLoop(id: string, name: string): Promise; archiveLoop(idOrName: string): Promise; unarchiveLoop(idOrName: string): Promise; deleteLoop(idOrName: string): Promise; createWorkflow(input: CreateWorkflowInput): Promise; getWorkflow(id: string): Promise; findWorkflowByName(name: string): Promise; requireWorkflow(idOrName: string): Promise; listWorkflows(opts?: { status?: WorkflowSpec["status"]; limit?: number; offset?: number; }): Promise; countWorkflows(opts?: { status?: WorkflowSpec["status"]; }): Promise; archiveWorkflow(idOrName: string): Promise; getWorkflowRun(id: string): Promise; requireWorkflowRun(id: string): Promise; listWorkflowRuns(opts?: { workflowId?: string; loopRunId?: string; limit?: number; }): Promise; listWorkflowStepRuns(workflowRunId: string): Promise; listWorkflowEvents(workflowRunId: string, limit?: number): Promise; recoverWorkflowRun(workflowRunId: string, reason?: string): Promise<{ run: WorkflowRun; recoveredSteps: WorkflowStepRun[]; }>; cancelWorkflowRun(workflowRunId: string, reason?: string): Promise; listWorkflowWorkItems(opts?: { status?: WorkflowWorkItemStatus; routeKey?: string; limit?: number; }): Promise; getWorkflowWorkItem(id: string): Promise; requeueWorkflowWorkItem(id: string, patch?: { reason?: string; resetAttempts?: boolean; }): Promise; listWorkflowInvocations(opts?: { limit?: number; }): Promise; getWorkflowInvocation(id: string): Promise; getGoal(id: string): Promise; findGoalByLoop(idOrName: string): Promise; findGoalByRunId(id: string): Promise; listGoals(opts?: { status?: GoalStatus; limit?: number; }): Promise; listGoalPlanNodes(goalIdOrPlanId: string): Promise; listGoalRuns(opts?: { goalId?: string; runId?: string; limit?: number; }): Promise; listRuns(opts?: { loopId?: string; status?: RunStatus; labels?: string[]; limit?: number; offset?: number; }): Promise; countRuns(opts?: { loopId?: string; status?: RunStatus; labels?: string[]; }): Promise; getRun(id: string): Promise; writeRunReceipt(input: WriteRunReceiptInput): Promise; getRunReceipt(runId: string): Promise; listRunReceipts(opts?: { loopId?: string; repo?: string; taskId?: string; knowledgeId?: string; status?: string; limit?: number; }): Promise; listStuckRunCandidates(opts?: { expiredBefore?: string; limit?: number; }): Promise; reconcileStuckRunCandidates(candidates: StuckRunCandidate[]): Promise; pruneHistory(opts: PruneHistoryOptions): Promise; } /** * On-box SQLite transport. Wraps a single {@link Store} and awaits its * synchronous methods so callers see the async {@link LoopStore} surface. */ export declare class LocalStore implements LoopStore { readonly transport: "file"; private readonly store; constructor(store?: Store); /** * The underlying on-box sqlite {@link Store}. Exposed ONLY for genuinely * local-runtime operations that cannot route over HTTP — the scheduler * (tick/run-now inline execution), migration import/export, and local * diagnostics (doctor/health/daemon status). Callers must gate on * `transport === "file"` first; the hosted ApiStore has no `raw` store, so * these operations fail loudly on the API connection instead of touching an * island. */ get raw(): Store; close(): Promise; createLoop(input: CreateLoopInput, from?: Date): Promise; getLoop(id: string): Promise; findLoopByName(name: string): Promise; requireLoop(idOrName: string): Promise; requireUniqueLoop(idOrName: string): Promise; listLoops(opts?: Parameters[0]): Promise; countLoops(status?: LoopStatus, opts?: { archived?: boolean; includeArchived?: boolean; }): Promise; updateLoop(id: string, patch: Partial>): Promise; mutateLoop(envelope: LoopMutationEnvelope): Promise; getLoopMutationResult(operationId: string, stepId: string, caps: LoopMutationLookupCaps): Promise; renameLoop(id: string, name: string): Promise; archiveLoop(idOrName: string): Promise; unarchiveLoop(idOrName: string): Promise; deleteLoop(idOrName: string): Promise; createWorkflow(input: CreateWorkflowInput): Promise; getWorkflow(id: string): Promise; findWorkflowByName(name: string): Promise; requireWorkflow(idOrName: string): Promise; listWorkflows(opts?: Parameters[0]): Promise; countWorkflows(opts?: { status?: WorkflowSpec["status"]; }): Promise; archiveWorkflow(idOrName: string): Promise; getWorkflowRun(id: string): Promise; requireWorkflowRun(id: string): Promise; listWorkflowRuns(opts?: Parameters[0]): Promise; listWorkflowStepRuns(workflowRunId: string): Promise; listWorkflowEvents(workflowRunId: string, limit?: number): Promise; recoverWorkflowRun(workflowRunId: string, reason?: string): Promise<{ run: WorkflowRun; recoveredSteps: WorkflowStepRun[]; }>; cancelWorkflowRun(workflowRunId: string, reason?: string): Promise; listWorkflowWorkItems(opts?: Parameters[0]): Promise; getWorkflowWorkItem(id: string): Promise; requeueWorkflowWorkItem(id: string, patch?: { reason?: string; resetAttempts?: boolean; }): Promise; listWorkflowInvocations(opts?: Parameters[0]): Promise; getWorkflowInvocation(id: string): Promise; getGoal(id: string): Promise; findGoalByLoop(idOrName: string): Promise; findGoalByRunId(id: string): Promise; listGoals(opts?: Parameters[0]): Promise; listGoalPlanNodes(goalIdOrPlanId: string): Promise; listGoalRuns(opts?: Parameters[0]): Promise; listRuns(opts?: Parameters[0]): Promise; countRuns(opts?: Parameters[0]): Promise; getRun(id: string): Promise; writeRunReceipt(input: WriteRunReceiptInput): Promise; getRunReceipt(runId: string): Promise; listRunReceipts(opts?: Parameters[0]): Promise; listStuckRunCandidates(opts?: { expiredBefore?: string; limit?: number; }): Promise; reconcileStuckRunCandidates(candidates: StuckRunCandidate[]): Promise; pruneHistory(opts: PruneHistoryOptions): Promise; } export declare class HostedResponseShapeError extends Error { constructor(key: string); } /** * API transport: routes every read+write through the hosted `/v1` API. Loop/name * resolution (requireLoop/requireUniqueLoop/find*) is done client-side by * listing and matching, mirroring the local Store behaviour, so a server that * ignores a name filter can never return the wrong row. */ export declare class ApiStore implements LoopStore { private readonly client; readonly baseUrl: string; readonly transport: "api"; constructor(client: HasnaStorageClient, baseUrl: string); private get t(); close(): Promise; createLoop(input: CreateLoopInput): Promise; getLoop(id: string): Promise; findLoopByName(name: string): Promise; requireLoop(idOrName: string): Promise; requireUniqueLoop(idOrName: string): Promise; private resolveLoop; listLoops(opts?: Parameters[0]): Promise; countLoops(status?: LoopStatus, opts?: { archived?: boolean; includeArchived?: boolean; }): Promise; updateLoop(id: string, patch: Partial>): Promise; mutateLoop(envelope: LoopMutationEnvelope): Promise; getLoopMutationResult(operationId: string, stepId: string, caps: LoopMutationLookupCaps): Promise; renameLoop(id: string, name: string): Promise; archiveLoop(idOrName: string): Promise; unarchiveLoop(idOrName: string): Promise; private mutateArchiveState; deleteLoop(idOrName: string): Promise; createWorkflow(input: CreateWorkflowInput): Promise; getWorkflow(id: string): Promise; findWorkflowByName(name: string): Promise; requireWorkflow(idOrName: string): Promise; listWorkflows(opts?: Parameters[0]): Promise; countWorkflows(opts?: { status?: WorkflowSpec["status"]; }): Promise; archiveWorkflow(idOrName: string): Promise; getWorkflowRun(id: string): Promise; requireWorkflowRun(id: string): Promise; listWorkflowRuns(opts?: Parameters[0]): Promise; listWorkflowStepRuns(workflowRunId: string): Promise; listWorkflowEvents(workflowRunId: string, limit?: number): Promise; recoverWorkflowRun(workflowRunId: string, reason?: string): Promise<{ run: WorkflowRun; recoveredSteps: WorkflowStepRun[]; }>; cancelWorkflowRun(_workflowRunId: string, _reason?: string): Promise; listWorkflowWorkItems(opts?: Parameters[0]): Promise; getWorkflowWorkItem(id: string): Promise; requeueWorkflowWorkItem(_id: string, _patch?: { reason?: string; resetAttempts?: boolean; }): Promise; listWorkflowInvocations(opts?: Parameters[0]): Promise; getWorkflowInvocation(id: string): Promise; getGoal(id: string): Promise; findGoalByLoop(idOrName: string): Promise; findGoalByRunId(id: string): Promise; listGoals(opts?: Parameters[0]): Promise; listGoalPlanNodes(goalIdOrPlanId: string): Promise; listGoalRuns(opts?: Parameters[0]): Promise; listRuns(opts?: Parameters[0]): Promise; countRuns(opts?: Parameters[0]): Promise; getRun(id: string): Promise; writeRunReceipt(input: WriteRunReceiptInput): Promise; getRunReceipt(runId: string): Promise; listRunReceipts(opts?: Parameters[0]): Promise; listStuckRunCandidates(opts?: { expiredBefore?: string; limit?: number; }): Promise; reconcileStuckRunCandidates(candidates: StuckRunCandidate[]): Promise; pruneHistory(opts: PruneHistoryOptions): Promise; } /** * Resolve the client store for the current environment: an {@link ApiStore} when * the connection contract resolves to the HTTP transport (API URL + API key * set), else a {@link LocalStore}. Callers hold a {@link LoopStore} and never * branch on connection. */ export declare function getStore(env?: Env): LoopStore; /** True when the resolved store is the control-plane HTTP transport. */ export declare function isCloudStore(env?: Env): boolean; export {};