/** * RenaissShipFlow API client for CLI and MCP server usage. */ import { SHIPFLOW_CONTRACT } from "./shipflow-contract-data.js"; export declare class ApiError extends Error { status: number; body: string; constructor(status: number, body: string); } /** An active exclusive issue claim held by an agent. */ export interface AgentClaim { repo: string; issueNumber: number; actor: string; agent?: string; claimedAt: string; expiresAt: string; } /** A capability the agent cannot grant itself (issue #211). Mirrors the * server's domain.CapabilityRequest wire form. */ export type CapabilityClass = "capability" | "access" | "secret" | "policy"; export type CapabilityStatus = "open" | "granted" | "declined"; export interface CapabilityRequest { id: string; repo?: string; class: CapabilityClass; title: string; why: string; requestedBy?: string; issueNumber?: number; status: CapabilityStatus; resolution?: string; createdAt: string; resolvedAt?: string; } /** Reporter-thread delivery outcome (issue #460). * * `threadNotified: false` meant two opposite things: a GitHub-filed issue has * no reporter thread to notify (normal), or the thread upload FAILED and the * error was swallowed. Only `failed` is a failure. */ export type EvidenceThreadStatus = "delivered" | "no-reporter-thread" | "failed"; /** Where uploaded test evidence landed. */ export interface EvidenceResult { threadImageUrls?: string[]; githubCommented: boolean; prCommented?: boolean; threadNotified: boolean; /** Optional: servers older than 0.30 don't send it — fall back to * `threadNotified`, which is kept for exactly that wire compatibility. */ threadStatus?: EvidenceThreadStatus; /** The upload failure, verbatim, when `threadStatus` is `failed`. */ threadError?: string; } /** Thrown when claiming an issue another agent already holds. */ export declare class ClaimConflictError extends Error { holder?: AgentClaim | undefined; constructor(holder?: AgentClaim | undefined); } export interface ClientOptions { baseUrl: string; apiKey?: string; } /** New tokens from a successful refresh, with the access-token expiry. */ export interface RefreshedTokens { token: string; refreshToken: string; expiresAt: number; } export interface AuthOptions { jwt?: string; refreshToken?: string; onRefreshed?: (t: RefreshedTokens) => void; } export declare class ShipFlowClient { private baseUrl; private apiKey?; private refreshToken?; private onRefreshed?; private fetchImpl; private sleep; constructor(opts: ClientOptions & AuthOptions & { fetch?: typeof fetch; sleep?: (ms: number) => Promise; }); private static readonly REQUEST_TIMEOUT_MS; private static readonly UPLOAD_TIMEOUT_MS; private authedFetch; /** Fetch a raw URL through the injected fetch, attaching the bearer token and * doing one transparent 401 refresh-retry — for non-JSON bodies (multipart * evidence) that can't go through request(). The Authorization header is * (re)applied on each attempt so the refreshed token is used. */ private fetchWithRefresh; private toResult; private request; /** Exchange the stored refresh token for new tokens and persist them. Returns * false (leaving the refresh token cleared) if the refresh can't succeed — * e.g. it has itself expired, in which case the caller should re-login. */ private tryRefresh; listRepos(org: string): Promise; getRepo(org: string, repo: string): Promise; updateWorkflow(org: string, repo: string, workflowType: string, body: { enabled?: boolean; settings?: Record; notificationChannelIds?: string[]; }): Promise; listActivity(org: string, params?: { cursor?: string; limit?: number; }): Promise>; getStats(org: string): Promise; /** Per-model and per-stage AI token usage over the last `days` days (default 30), * sourced from ai_logs. Distinct from getStats (execution counts). */ getTokenStats(org: string, days?: number): Promise; getOrg(org: string): Promise; listChannels(org: string): Promise; addChannel(org: string, body: { channelType: string; channelIdentifier: string; label: string; config?: Record; }): Promise; exchangeGhToken(ghToken: string): Promise; refreshJWT(refreshToken: string): Promise<{ token: string; refreshToken: string; }>; getRepoByFullName(org: string, owner: string, repo: string): Promise<{ projects: { id: string; name: string; }[]; }>; getTriage(org: string, projectId: string, repo: string, issueNumber: number): Promise; /** Escalate pre-flight: look up a reusable precedent for one ask. The server * normalizes + fingerprints the raw reason (single source of truth); the CLI * never computes a fingerprint. Precedent lookup is best-effort — the caller * falls back to escalating on any error. */ matchPrecedent(org: string, projectId: string, body: { category: string; reason: string; repo?: string; issue?: number; }): Promise; signal(org: string, projectId: string, refKind: "issues" | "prs", number: number, action: "claim" | "release-claim" | "opened" | "merged", body: Record): Promise; /** Upload testing evidence for an issue (multipart). `before`/`after` are the * labeled screenshots showing the fix's effect; `images` is supplementary * media (a screen recording, extra shots). */ attachEvidence(org: string, projectId: string, number: number, opts: { repo: string; pr?: number; previewUrl?: string; caption?: string; before?: { filename: string; data: Uint8Array; }[]; after?: { filename: string; data: Uint8Array; }[]; /** Defect capture: the broken state of a bug with no fix yet, so there is * nothing to pair it with. Mutually exclusive with before/after (#417). */ actual?: { filename: string; data: Uint8Array; }[]; /** Per-pair surface names, by position: labels[i] names before[i] ↔ after[i]. */ labels?: string[]; /** Per-image captions, by position within each file group: beforeCaptions[i] * describes before[i], and likewise for after/images. A per-shot caption * keeps a blanket summary from over-claiming what one image shows (#301). */ beforeCaptions?: string[]; afterCaptions?: string[]; actualCaptions?: string[]; imageCaptions?: string[]; /** Touched feature names — gallery gap cards render for unproven ones. */ touched?: string[]; images?: { filename: string; data: Uint8Array; }[]; }): Promise; /** Host media files (screenshots, recordings) at public URLs (issue #457). * Used by `issue create --screenshot` to embed images in the body of an * issue that does not exist yet, so the per-issue evidence endpoint cannot * serve it. Returns URLs index-aligned with the files; the server fails the * whole request if any upload fails. */ uploadMedia(org: string, projectId: string, files: { filename: string; data: Uint8Array; }[]): Promise<{ urls: string[]; }>; /** Exclusively claim an issue. Throws ClaimConflictError when held by another agent. */ claimIssue(org: string, projectId: string, number: number, body: { repo: string; agent?: string; ttlMinutes?: number; }): Promise; /** Active claims in the project — who is working on what right now. */ listClaims(org: string, projectId: string): Promise; /** File a standing ask for a capability/access/secret/policy the agent can't * grant itself, so an operator can work it through the queue. */ createCapabilityRequest(org: string, projectId: string, body: { class: string; title: string; why: string; repo?: string; issueNumber?: number; }): Promise; /** The project's capability requests, newest-first, optionally filtered by status. */ listCapabilityRequests(org: string, projectId: string, status?: string): Promise; triggerRelease(org: string, projectId: string, body: { repo: string; tag: string; baseTag?: string; env?: string; }): Promise<{ releaseRunId: string; workflowRunIds: string[]; }>; triggerWorkflow(org: string, projectId: string, workflowType: string, inputs: Record): Promise; getExecutionResult(org: string, execId: string): Promise; getProjectStatus(org: string, projectId: string): Promise; getFeatureMapping(org: string, projectId: string): Promise; } /** 202 response from POST .../workflows/{type}/trigger. */ export interface WorkflowTriggerResult { executionId: string; status: string; } /** Per-run gate status from GET .../executions/{id}/result * (domain.WorkflowResult → BuildWorkflowResult). Terminal: success | failure | * skipped. Renamed from `ExecutionStatus` (issue #185): that name collided with * the server's execution-LIST statuses (domain.ExecutionStatus: * queued/dispatched/… — the contract's executionStatuses list, which the * dashboard union derives from), and the two are different server enums. */ export type GateStatus = "pending" | "in_progress" | "success" | "failure" | "skipped"; /** @deprecated Renamed to {@link GateStatus} (issue #185) — this alias keeps * existing imports compiling and will be removed when the CLI gains a * contract-derived union for the server's execution-list statuses, which owns * the `ExecutionStatus` name everywhere else (Go domain + dashboard). */ export type ExecutionStatus = GateStatus; /** Notification delivery methods (domain.ChannelType), single-sourced from the * shared ShipFlow contract (issue #185) — the Go constants and the dashboard * union are pinned to the same list by parity tests. */ export type ChannelType = (typeof SHIPFLOW_CONTRACT.channelTypes.values)[number]; /** Subscription tiers (domain.PlanType), single-sourced from the shared * ShipFlow contract (issue #185) — same parity guarantees as ChannelType. */ export type PlanType = (typeof SHIPFLOW_CONTRACT.planTypes.values)[number]; /** A workflow run's structured result. Mirrors the server's domain.WorkflowResult. * The gating status lives at `result.status`; test_runner runs also populate * total/passed/failed/skipped counts under `result`. */ export interface WorkflowExecutionResult { executionId: string; workflowType: string; repo: string; trigger?: { event?: string; issueNumber?: number; prNumber?: number; tag?: string; ref?: string; timestamp?: string; }; result: { status: GateStatus; errorMessage?: string; test_suite?: string; environment?: string; total_tests?: number; passed_tests?: number; failed_tests?: number; skipped_tests?: number; duration?: number; [key: string]: unknown; }; progress?: unknown; durationMs?: number; } export interface RepoListItem { id: string; name: string; fullName: string; defaultBranch: string; isActive: boolean; projectId?: string; projectName?: string; workflowCount: number; enabledWorkflowCount: number; lastActivityAt?: string; } export interface WorkflowConfig { workflowType: string; enabled: boolean; settings: Record; notificationChannelIds?: string[]; lastRunAt?: string; lastRunStatus?: string; } export interface Repository { id: string; name: string; fullName: string; description?: string; htmlUrl: string; isActive: boolean; workflowConfigs: WorkflowConfig[]; lastActivityAt?: string; createdAt: string; } export interface ActivityEvent { id: string; workflowType: string; repoName: string; repoFullName: string; triggerEvent: string; status: string; startedAt: string; completedAt?: string; durationMs?: number; details?: { triggerActor?: string; errorMessage?: string; inputs?: Record; outputs?: Record; }; } export interface PaginatedResponse { data: T[]; pagination: { cursor?: string; hasMore: boolean; total?: number; }; } export interface Channel { id: string; channelType: ChannelType; channelIdentifier: string; label: string; createdAt: string; } export interface OrgSettings { name: string; plan: PlanType; usage: { workflowRuns: number; workflowRunsLimit: number; repos: number; reposLimit: number; }; github?: { connected: boolean; org: string; installationId?: number; appSlug: string; }; } export interface OrgStats { totalExecutions: number; successCount: number; failureCount: number; activeRepos: number; workflowBreakdown: Record; } /** Per-model or per-stage AI usage bucket (from ai_logs). */ export interface AIUsageBucket { requests: number; tokensIn: number; tokensOut: number; /** Prompt-cache write tokens (input written to cache). Optional for older servers. */ cacheCreationTokens?: number; /** Prompt-cache read tokens — the cache "hits" (input served from cache). Optional for older servers. */ cacheReadTokens?: number; costUsd: number; } /** Aggregated AI token usage returned by GET /orgs/{org}/stats/tokens. */ export interface AIUsageStats { totalRequests: number; totalTokensIn: number; totalTokensOut: number; /** Prompt-cache write tokens summed across the window. Optional for older servers. */ totalCacheCreationTokens?: number; /** Prompt-cache read tokens (cache hits) summed across the window. Optional for older servers. */ totalCacheReadTokens?: number; totalCostUsd: number; byModel?: Record; byStage?: Record; } export interface TokenExchangeResult { token: string; refreshToken: string; tenants: { token: string; refreshToken: string; tenant: { id: string; githubOrg: string; displayName: string; }; }[]; tenant: { id: string; githubOrg: string; displayName: string; }; } export interface TriageView { priority?: string; suggestedLabels?: string[]; relatedFeatures?: string[]; relatedFiles?: string[]; relatedIssues?: number[]; relatedCommits?: string[]; } export interface ProjectStatus { recentWorkflows?: unknown[]; latestSummaries?: Record; [key: string]: unknown; } /** The stored precedent surfaced by a match, when one exists. */ export interface PrecedentInfo { id: string; answer: string; sourceIssue: number; sourceUrl: string; author: string; answeredAt: string; reuseCount: number; expiresAt: string; } /** The escalate pre-flight verdict for one ask (issue #210). * - `none`: no precedent — escalate as today. * - `suggest` / `reconfirm`: escalate with the stored answer prefilled. * - `apply`: auto-resolve (only when the server's default-off flag is on). */ export interface PrecedentMatch { outcome: "none" | "suggest" | "reconfirm" | "apply"; category: string; repo: string; fingerprint: string; classDemoted: boolean; note?: string; precedent?: PrecedentInfo; } /** One feature in ShipFlow's per-project feature map. */ export interface Feature { name: string; description?: string; category?: string; layer?: string; paths?: string[]; test_priority?: string; [key: string]: unknown; } /** ShipFlow's per-project feature map (features → file paths/test info). */ export interface FeatureMapping { features: Record; excludePatterns?: string[]; cicdPatterns?: string[]; lastUpdated?: string; } //# sourceMappingURL=client.d.ts.map