import { type RootMatchInput, type RootMatchResult, type WorkspaceFilter } from "../db/workspaces.js"; import { type ProjectResolverOptions } from "../lib/project-resolver.js"; import { type CreateProjectDataModelInput, type CreateProjectDataRecordInput, type LinkProjectLoopInput, type ProjectDataModel, type ProjectDataRecord, type ProjectLoopLink, type ProjectLoopSummary, type ProjectStoreSummary } from "../db/project-store.js"; import { type CreateProjectBudgetInput, type ProjectBudget, type ProjectBudgetContext, type ProjectBudgetSpend, type ProjectBudgetStatus, type ProjectSpendInput } from "../lib/budget.js"; import { type ProjectChannelEnsureResult, type StoreEnsureChannelOptions } from "../lib/project-channel.js"; import { type ProductionProjectRegistrationAuthorityOptions } from "../lib/production-project-registration-authorities.js"; import type { Agent, AgentRun, CreateAgentInput, CreateRecipeInput, CreateRootInput, CreateWorkspaceInput, EventSource, GuardedProjectMutationReceiptLookupInput, GuardedProjectMutationReceiptLookupResult, GuardedProjectReadRequest, GuardedProjectReadResult, GuardedProjectMutationRequest, GuardedProjectMutationResult, GuardedProjectMutationRollbackRequest, JsonObject, ProjectQuarantineRequest, ProjectQuarantineReadRequest, ProjectQuarantineReadResult, ProjectQuarantineResult, ProjectQuarantineRollbackRequest, ProjectResourceLinkMutationRequest, ProjectResourceLinkMutationResult, ProjectResourceLinkMigrationAdvanceRequest, ProjectResourceLinkMigrationPlanRequest, ProjectResourceLinkMigrationReadRequest, ProjectResourceLinkMigrationResult, ProjectResourceLinkMigrationRollbackRequest, ProjectResourceLinkReadRequest, ProjectResourceLinkReadResult, ProjectResourceLinkRollbackRequest, CreateTmuxProfileInput, CreateTmuxProfileWindowInput, Recipe, Root, TmuxProfile, TmuxProfileWindow, UpdateRootInput, UpdateWorkspaceInput, Workspace, WorkspaceAgentAssignment, WorkspaceEvent, WorkspaceLocation, WorkspaceLock, Machine } from "../types/workspace.js"; /** Process-environment shape accepted by the shared @hasna/contracts seam. */ type Env = Record; export type ProjectStoreTransport = "local" | "http"; /** Mutation provenance carried on every write (agent + audit trail). */ export interface MutationContext { agentId?: string; source?: EventSource; command?: string; prompt?: string; reason?: string; } export interface DeleteProjectResult { /** The deleted project row when the transport can return it (always local). */ workspace: Workspace | null; hard: boolean; /** Stable identifier for the deleted project (id or slug). */ id: string; } export interface DeleteRootResult { root: Root; detached_workspaces: number; } /** Explicit audit-event write (routes through the Store, never raw sqlite). */ export interface RecordEventInput { event_type: string; source: EventSource; agentId?: string; prompt?: string; command?: string; before?: JsonObject | null; after?: JsonObject | null; metadata?: JsonObject; } /** Filter for the prompt-agent run ledger read (on-box sub-resource). */ export interface AgentRunFilter { workspace_id?: string; agent_id?: string; status?: AgentRun["status"]; limit?: number; } /** Assign a registered agent to a project role (on-box sub-resource). */ export interface AssignAgentInput { /** Already-resolved agent id. */ agentId: string; role?: string; assignedBy?: string; metadata?: JsonObject; source?: EventSource; command?: string; } /** Register another on-disk location for a project (on-box sub-resource). */ export interface AddLocationInput { path: string; machineId?: string; label?: string; kind?: string; isPrimary?: boolean; metadata?: JsonObject; agentId?: string; source?: EventSource; command?: string; } export interface AddLocationResult { project: Workspace; location: WorkspaceLocation; } /** Acquire a project mutation lock (machine-local coordination primitive). */ export interface AcquireLockInput { key: string; workspaceId?: string; agentId?: string; reason?: string; ttlSeconds?: number; } /** * A project list plus the metadata a caller needs to know whether it is the * whole set. `projects list --json` used to emit a bare array that was capped * server-side, so a truncated read and a complete one looked identical; every * bounded read now carries `total`/`has_more`/`complete`. */ export interface ProjectListPage { readonly projects: Workspace[]; /** Rows returned in this page. */ readonly count: number; /** Rows matching the filter, ignoring limit/offset. */ readonly total: number; /** Offset this page started at. */ readonly offset: number; /** Caller-requested bound, or null when the caller asked for everything. */ readonly limit: number | null; /** More rows exist past this page. */ readonly has_more: boolean; /** Every matching row is present (i.e. `offset === 0 && !has_more`). */ readonly complete: boolean; } export interface CompleteProjectPopulation { readonly projects: Workspace[]; readonly total: number; readonly pages: number; readonly complete: true; } export interface ProjectStore { readonly transport: ProjectStoreTransport; /** Base `/v1` for the hosted transport; null for local. Never contains the key. */ readonly baseUrl: string | null; /** * List projects. With no `limit` this returns EVERY matching row — the store * walks the server's pages itself rather than handing back one capped page. */ listProjects(filter?: WorkspaceFilter): Promise; /** Full population read with a stable producer total and terminal invariant. */ listProjectsComplete(filter?: Omit): Promise; /** As `listProjects`, plus the totals that make a bounded read detectable. */ listProjectsPage(filter?: WorkspaceFilter): Promise; getProject(idOrSlug: string): Promise; /** * Resolve a caller-supplied target to a single project, throwing if none * matches. Local resolves by id/slug/name and — as a machine-local * convenience — by on-disk path/marker. Api resolves by id/slug server-side. */ resolveTarget(target: string | undefined, options?: ProjectResolverOptions): Promise; createProject(input: CreateWorkspaceInput): Promise; updateProject(id: string, patch: UpdateWorkspaceInput): Promise; guardedReadProject(input: GuardedProjectReadRequest): Promise; readProjectResourceLinks(input: ProjectResourceLinkReadRequest): Promise; mutateProjectResourceLinks(input: ProjectResourceLinkMutationRequest): Promise; rollbackProjectResourceLinks(input: ProjectResourceLinkRollbackRequest): Promise; readDuplicateProjectQuarantinePreimage(input: ProjectQuarantineReadRequest): Promise; quarantineDuplicateProject(input: ProjectQuarantineRequest): Promise; rollbackDuplicateProjectQuarantine(input: ProjectQuarantineRollbackRequest): Promise; planProjectResourceLinkMigration(input: ProjectResourceLinkMigrationPlanRequest): Promise; readProjectResourceLinkMigration(input: ProjectResourceLinkMigrationReadRequest): Promise; advanceProjectResourceLinkMigration(input: ProjectResourceLinkMigrationAdvanceRequest): Promise; rollbackProjectResourceLinkMigration(input: ProjectResourceLinkMigrationRollbackRequest): Promise; guardedUpdateProject(input: GuardedProjectMutationRequest): Promise; lookupGuardedProjectMutationReceipt(input: GuardedProjectMutationReceiptLookupInput): Promise; rollbackGuardedProjectMutation(input: GuardedProjectMutationRollbackRequest): Promise; archiveProject(id: string, ctx?: MutationContext): Promise; unarchiveProject(id: string, ctx?: MutationContext): Promise; deleteProject(id: string, opts: { hard?: boolean; }, ctx?: MutationContext): Promise; listEvents(idOrSlug: string, limit?: number): Promise; /** Record an explicit audit event. Local writes sqlite; api POSTs to /projects/:id/events. */ recordEvent(idOrSlug: string, input: RecordEventInput): Promise; /** * Per-project agent assignments. This is an on-box sub-resource; the api * transport does not model it server-side and returns an empty list. */ getProjectAgents(id: string): Promise; /** Assign a registered agent to a project role. Local-only (throws in the hosted transport). */ assignAgent(idOrSlug: string, input: AssignAgentInput): Promise; /** Per-project registered locations. Readable from both registry transports. */ getProjectLocations(id: string): Promise; /** Registry of canonical machines (roles: mirror-hub | assignable | avoid). */ listMachines(): Promise; /** Register another on-disk location for a project. Local-only (throws in the hosted transport). */ addLocation(idOrSlug: string, input: AddLocationInput): Promise; listLocks(): Promise; acquireLock(input: AcquireLockInput): Promise; releaseLock(key: string, lockId: string): Promise; forceReleaseLock(key: string): Promise; listRoots(): Promise; getRoot(idOrSlug: string): Promise; createRoot(input: CreateRootInput): Promise; updateRoot(idOrSlug: string, patch: UpdateRootInput): Promise; deleteRoot(idOrSlug: string, opts?: { detachProjects?: boolean; }): Promise; /** Score registered roots by path/kind/tags/github_org (behaves identically in both transports). */ matchRoots(input: RootMatchInput): Promise; listAgents(): Promise; getAgent(idOrSlug: string): Promise; createAgent(input: CreateAgentInput): Promise; listRecipes(): Promise; getRecipe(idOrSlug: string): Promise; createRecipe(input: CreateRecipeInput): Promise; listAgentRuns(filter?: AgentRunFilter): Promise; listDataModels(project: Workspace): Promise; createDataModel(project: Workspace, input: CreateProjectDataModelInput, ctx?: MutationContext): Promise; listDataRecords(project: Workspace, modelId: string): Promise; createDataRecord(project: Workspace, input: CreateProjectDataRecordInput, ctx?: MutationContext): Promise; listLoopLinks(project: Workspace): Promise; linkLoop(project: Workspace, input: LinkProjectLoopInput, ctx?: MutationContext): Promise; listLoopSummaries(project: Workspace, options?: { includeRuns?: boolean; runLimit?: number; }): Promise; inspectAppStore(project: Workspace): Promise; inspectAppStoreWithLoops(project: Workspace, options?: { includeRuns?: boolean; }): Promise; createBudget(input: CreateProjectBudgetInput): Promise; listBudgets(context?: ProjectBudgetContext): Promise; getBudgetStatuses(context?: ProjectBudgetContext): Promise; resetBudget(id: string): Promise; recordSpend(input: ProjectSpendInput): Promise; listTmuxProfiles(): Promise; getTmuxProfile(idOrSlug: string): Promise; createTmuxProfile(input: CreateTmuxProfileInput): Promise; addTmuxProfileWindow(input: CreateTmuxProfileWindowInput & { profile_id: string; }): Promise; listTmuxProfileWindows(profileId: string): Promise; ensureChannel(project: Workspace, options?: StoreEnsureChannelOptions): Promise; } export interface ResolveProjectStoreOptions { producerAuthorityOptions?: ProductionProjectRegistrationAuthorityOptions; producerVerifierNow?: () => string; } /** * Resolve the active projects Store from the environment. Returns an * ApiProjectStore when the API URL and key pairing is present, else a * LocalProjectStore. Throws if the hosted pairing is incomplete (so callers * never silently read the wrong dataset). */ export declare function resolveProjectStore(env?: Env, fetchImpl?: (input: string, init?: RequestInit) => Promise, options?: ResolveProjectStoreOptions): ProjectStore; /** Test/di seam: clear the process-env cached store. */ export declare function __resetProjectStore(): void; export {}; //# sourceMappingURL=project-store.d.ts.map