Documentation
¶
Index ¶
- Constants
- Variables
- func CheckVersionResponse(resp *http.Response) bool
- func DeriveSlug(name string) string
- func HandleRedirect(projectRoot string, info *RedirectInfo) error
- func PrintDeprecationWarning(message string)
- func PrintUpgradeRequired(minVersion string)
- func RenameRepoMarker(projectRoot, oldID, newID string) error
- type DistillObservation
- type DistillRequest
- type DistillResponse
- type DoctorIssue
- type DoctorResponse
- type ImportNotification
- type LedgerStatusResponse
- type MergeRepoRequest
- type MergeRepoResponse
- type QueryLatency
- type QueryRequest
- type QueryResponse
- type QueryResult
- type RedirectConfig
- type RedirectInfo
- type RedirectMapping
- type RepoClient
- func (c *RepoClient) DistillMemory(teamID string, req *DistillRequest) (*DistillResponse, error)
- func (c *RepoClient) Endpoint() string
- func (c *RepoClient) GetDoctorIssues(repoID string) (*DoctorResponse, error)
- func (c *RepoClient) GetLedgerStatus(repoID string) (*LedgerStatusResponse, error)
- func (c *RepoClient) GetRepoDetail(repoID string) (*RepoDetailResponse, error)
- func (c *RepoClient) GetRepos() (*ReposResponse, error)
- func (c *RepoClient) GetTeamInfo(teamID string) (*TeamInfoResponse, error)
- func (c *RepoClient) MergeRepo(repoID string, markers map[string]json.RawMessage) (*MergeRepoResponse, *RedirectInfo, error)
- func (c *RepoClient) NotifyImport(teamID string, metadata any) error
- func (c *RepoClient) NotifyUninstall(repoID, repoSalt string) error
- func (c *RepoClient) Query(req *QueryRequest) (*QueryResponse, error)
- func (c *RepoClient) RegisterRepo(req *RepoInitRequest) (*RepoInitResponse, error)
- func (c *RepoClient) WithAuthToken(token string) *RepoClient
- type RepoDetailLedger
- type RepoDetailResponse
- type RepoDetailTeamContext
- type RepoFingerprint
- type RepoInfo
- type RepoInitRequest
- type RepoInitResponse
- type RepoMarkerData
- type RepoUninstallRequest
- type ReposResponse
- type TeamInfoResponse
- type TeamMembership
Constants ¶
const ( // HeaderMinVersion is returned by the server to indicate the minimum CLI version required HeaderMinVersion = "X-SageOx-Min-Version" // HeaderDeprecated is returned by the server to warn of upcoming deprecation HeaderDeprecated = "X-SageOx-Deprecated" )
const RedirectHeader = "X-SageOx-Merge"
RedirectHeader is the HTTP header name for merge/redirect information
Variables ¶
var ErrForbidden = errors.New("access denied: you are not a member of this team — request an invite URL from a team admin")
ErrForbidden is returned when the API returns 403 Forbidden
var ErrLedgerNotFound = errors.New("ledger not found")
ErrLedgerNotFound is returned when the ledger doesn't exist for the given repo.
var ErrReadOnly = errors.New("read-only access: you are a viewer on this public repo")
ErrReadOnly is returned when the user has viewer (read-only) access to a public repo
ErrUnauthorized is returned when the API returns 401 Unauthorized
var ErrVersionUnsupported = errors.New("CLI version no longer supported by server")
ErrVersionUnsupported is returned when the server indicates the CLI version is no longer supported
Functions ¶
func CheckVersionResponse ¶
CheckVersionResponse inspects HTTP response for version deprecation signals. Returns true if the CLI should abort due to unsupported version (HTTP 426). For successful responses, checks for soft deprecation warning header.
func DeriveSlug ¶ added in v0.3.0
DeriveSlug generates a kebab-case slug from a display name. Used as fallback when the server doesn't provide a slug.
func HandleRedirect ¶
func HandleRedirect(projectRoot string, info *RedirectInfo) error
HandleRedirect processes redirect info and updates local config/markers This is best-effort: returns nil on success or if nothing to do, and logs but does not fail on non-critical errors
func PrintDeprecationWarning ¶
func PrintDeprecationWarning(message string)
PrintDeprecationWarning displays a warning that the CLI version is deprecated Uses yellow color semantically indicating a non-blocking warning
func PrintUpgradeRequired ¶
func PrintUpgradeRequired(minVersion string)
PrintUpgradeRequired displays a message indicating the CLI version is no longer supported Uses red color semantically indicating a blocking error
func RenameRepoMarker ¶ added in v0.3.0
RenameRepoMarker renames the .repo_* marker file from old ID to new ID using VCS and updates the repo_id value inside the marker file
Types ¶
type DistillObservation ¶ added in v0.3.0
type DistillObservation struct {
Content string `json:"content"`
RecordedAt string `json:"recorded_at"` // RFC3339
}
DistillObservation is a single observation in a distill request.
type DistillRequest ¶ added in v0.3.0
type DistillRequest struct {
Observations []DistillObservation `json:"observations"`
DateRange [2]string `json:"date_range"` // [start, end] RFC3339
}
DistillRequest is the request body for POST /api/v1/teams/<teamID>/memory/distill.
type DistillResponse ¶ added in v0.3.0
type DistillResponse struct {
Summary string `json:"summary"`
UpdatedAt string `json:"updated_at"`
}
DistillResponse is the response from POST /api/v1/teams/<teamID>/memory/distill.
type DoctorIssue ¶
type DoctorIssue struct {
Type string `json:"type"` // e.g., "merge_pending", "team_invite_pending"
Severity string `json:"severity"` // "error", "warning", "info"
Title string `json:"title"` // short display title
Description string `json:"description"` // detailed explanation, supports Markdown
ActionURL string `json:"action_url,omitempty"` // URL to resolve the issue
ActionLabel string `json:"action_label,omitempty"` // button text, e.g., "Resolve merge"
}
DoctorIssue represents a single diagnostic issue from the cloud Cloud doctor detects things the local CLI cannot: - Pending merge conflicts (same repo registered twice) - requires cross-repo knowledge - Team invites pending acceptance - lives in cloud DB - Guidance updates available - version comparison server-side - Billing/quota warnings - enterprise only - Team-wide health (X repos need updates) - aggregate view
type DoctorResponse ¶
type DoctorResponse struct {
Issues []DoctorIssue `json:"issues"`
CheckedAt string `json:"checked_at"` // RFC3339 timestamp
}
DoctorResponse represents the GET /api/v1/repo/{repo_id}/doctor response
type ImportNotification ¶ added in v0.3.0
type ImportNotification struct {
TeamID string `json:"team_id"`
Metadata json.RawMessage `json:"metadata"`
}
ImportNotification is the POST /api/v1/teams/{team_id}/context/import request body. Imports target a team context (not a project repo), so team_id is the primary identifier. The Metadata field is passed as-is (json.RawMessage) to avoid coupling the API package to the docMeta struct in cmd/ox.
type LedgerStatusResponse ¶
type LedgerStatusResponse struct {
Status string `json:"status"` // "ready", "pending", "error"
RepoURL string `json:"repo_url"` // git clone URL (empty if not ready)
RepoID int `json:"repo_id"` // GitLab project ID (internal use)
CreatedAt string `json:"created_at"` // RFC3339 timestamp
Message string `json:"message,omitempty"` // optional status message
Visibility string `json:"visibility,omitempty"` // "public" or "private" (new field, may be empty on older servers)
AccessLevel string `json:"access_level,omitempty"` // "member" or "viewer" (new field, may be empty on older servers)
}
LedgerStatusResponse represents the GET /api/v1/repos/{repo_id}/ledger-status response.
func (*LedgerStatusResponse) IsReadOnly ¶
func (r *LedgerStatusResponse) IsReadOnly() bool
IsReadOnly returns true if the user has viewer (read-only) access.
type MergeRepoRequest ¶ added in v0.3.0
type MergeRepoRequest struct {
RepoMarkers map[string]json.RawMessage `json:"repo_markers"` // filename -> marker JSON
}
MergeRepoRequest represents POST /api/v1/repo/{repo_id}/merge
type MergeRepoResponse ¶ added in v0.3.0
type MergeRepoResponse struct {
Canonical string `json:"canonical_repo_id"` // the winning repo_id
Merged []string `json:"merged_repo_ids"` // repo_ids that were marked as merged
Redirect *RedirectInfo `json:"redirect,omitempty"` // redirect info (also in header)
}
MergeRepoResponse represents the merge API response
type QueryLatency ¶ added in v0.3.0
type QueryLatency struct {
Embed int64 `json:"embed"`
Search int64 `json:"search"`
Total int64 `json:"total"`
}
QueryLatency tracks latency of sub-operations.
type QueryRequest ¶ added in v0.3.0
type QueryRequest struct {
Query string `json:"query"`
Mode string `json:"mode,omitempty"` // "hybrid", "knn", "bm25" (default: hybrid)
K int `json:"k,omitempty"` // number of results (default: 10, max: 100)
Teams []string `json:"teams"` // team IDs to search team-context indexes
Repos []string `json:"repos"` // repo IDs to search ledger indexes
AgentID string `json:"agent_id,omitempty"` // querying agent instance (e.g. "Oxa7b3")
AgentType string `json:"agent_type,omitempty"` // querying agent type (e.g. "claude-code")
}
QueryRequest represents the POST /api/v1/query request body.
type QueryResponse ¶ added in v0.3.0
type QueryResponse struct {
Results []QueryResult `json:"results"`
LatencyMs QueryLatency `json:"latency_ms"`
}
QueryResponse represents the POST /api/v1/query response.
type QueryResult ¶ added in v0.3.0
type QueryResult struct {
Score float64 `json:"score"`
Text string `json:"text"`
DocType string `json:"doc_type"`
FilePath string `json:"file_path"`
SourceType string `json:"source_type"`
SourceID string `json:"source_id"`
CreatedAt string `json:"created_at,omitempty"`
}
QueryResult is a single search result.
type RedirectConfig ¶
type RedirectConfig struct {
RepoID string `json:"repo_id,omitempty"`
TeamID string `json:"team_id,omitempty"`
}
RedirectConfig contains the new config values to apply
type RedirectInfo ¶
type RedirectInfo struct {
Repo *RedirectMapping `json:"repo,omitempty"`
Team *RedirectMapping `json:"team,omitempty"`
Config *RedirectConfig `json:"config,omitempty"`
}
RedirectInfo contains redirect information from the server when repos or teams have been merged
func ParseRedirectHeader ¶
func ParseRedirectHeader(header http.Header) *RedirectInfo
ParseRedirectHeader parses X-Sageox-Redirect header if present Returns nil if header is not present or cannot be parsed
type RedirectMapping ¶
RedirectMapping represents a from -> to ID mapping
type RepoClient ¶
type RepoClient struct {
// contains filtered or unexported fields
}
RepoClient handles API communication with the SageOx repo endpoints
func NewRepoClient ¶
func NewRepoClient() *RepoClient
NewRepoClient creates a new repo API client using the global default endpoint.
CAUTION: This should RARELY be used. It uses endpoint.Get() which ignores project config, so it will use the wrong endpoint for repos configured with non-default endpoints (e.g., enterprise or test environments).
Use NewRepoClientForProject(gitRoot) instead for operations within a repo context. Use NewRepoClientWithEndpoint(endpoint) when you have the endpoint explicitly.
func NewRepoClientForProject ¶
func NewRepoClientForProject(gitRoot string) *RepoClient
NewRepoClientForProject creates a new repo API client using the endpoint from project config. This is the recommended way to create a client for repo-bound operations. It checks: SAGEOX_ENDPOINT env var > project config > default endpoint.
func NewRepoClientWithEndpoint ¶
func NewRepoClientWithEndpoint(baseURL string) *RepoClient
NewRepoClientWithEndpoint creates a new repo API client with a specific endpoint. Use this when you already have the endpoint URL (e.g., from auth flow or config).
func (*RepoClient) DistillMemory ¶ added in v0.3.0
func (c *RepoClient) DistillMemory(teamID string, req *DistillRequest) (*DistillResponse, error)
DistillMemory calls POST /api/v1/teams/<teamID>/memory/distill to run server-side LLM distillation of accumulated observations.
func (*RepoClient) Endpoint ¶
func (c *RepoClient) Endpoint() string
Endpoint returns the base URL this client is configured for
func (*RepoClient) GetDoctorIssues ¶
func (c *RepoClient) GetDoctorIssues(repoID string) (*DoctorResponse, error)
GetDoctorIssues calls GET /api/v1/repo/{repo_id}/doctor for cloud diagnostics Returns nil, nil if API unavailable (graceful degradation for offline mode)
func (*RepoClient) GetLedgerStatus ¶
func (c *RepoClient) GetLedgerStatus(repoID string) (*LedgerStatusResponse, error)
GetLedgerStatus fetches ledger provisioning status from the cloud API.
Response status values:
- "ready": Ledger is provisioned and RepoURL is available for cloning
- "pending": Ledger is being provisioned, caller should retry later
- "error": Provisioning failed, check Message for details
The repoID parameter is the SageOx repo identifier (UUID) from project config. The returned RepoID is the GitLab project ID (used internally by server).
Returns ErrLedgerNotFound if no ledger exists for this repo. Returns ErrUnauthorized if authentication fails.
func (*RepoClient) GetRepoDetail ¶
func (c *RepoClient) GetRepoDetail(repoID string) (*RepoDetailResponse, error)
GetRepoDetail calls GET /api/v1/cli/repos/{repo_id} to fetch repo detail. Returns visibility, access level, ledger status, and accessible team contexts. Works for both members (full access) and non-members on public repos (viewer access).
Returns ErrForbidden if the user is not a member and the repo is private. Returns ErrUnauthorized if authentication fails. Returns nil, nil if the endpoint returns 404 (server hasn't implemented this endpoint yet).
func (*RepoClient) GetRepos ¶
func (c *RepoClient) GetRepos() (*ReposResponse, error)
GetRepos calls GET /api/v1/cli/repos to fetch user's team context repos. This is user-scoped and returns all team contexts the user has access to. For ledger URLs, use GetLedgerStatus() which is project-scoped. Requires authentication. Returns PAT, repo URLs, and token expiration.
func (*RepoClient) GetTeamInfo ¶
func (c *RepoClient) GetTeamInfo(teamID string) (*TeamInfoResponse, error)
GetTeamInfo calls GET /api/v1/teams/{id} to fetch team information including the team context repo URL and credentials. Requires authentication. Returns nil, nil if team not found (404).
func (*RepoClient) MergeRepo ¶ added in v0.3.0
func (c *RepoClient) MergeRepo(repoID string, markers map[string]json.RawMessage) (*MergeRepoResponse, *RedirectInfo, error)
MergeRepo calls POST /api/v1/repo/{repo_id}/merge to notify the server about duplicate registration resolution. This is best-effort for server-side visibility and bookkeeping — the local cleanup is authoritative. Gracefully handles 404 (endpoint not yet deployed) by returning nil, nil, nil.
func (*RepoClient) NotifyImport ¶ added in v0.3.0
func (c *RepoClient) NotifyImport(teamID string, metadata any) error
NotifyImport sends a fire-and-forget notification about a new document import. Imports target a team context, so teamID identifies where the document lives. The metadata argument should be JSON-marshalable (typically the docMeta struct). Returns nil on network error, 404, or any non-2xx — never fails the caller's operation.
func (*RepoClient) NotifyUninstall ¶
func (c *RepoClient) NotifyUninstall(repoID, repoSalt string) error
NotifyUninstall calls POST /api/v1/repo/{repo_id}/uninstall to notify server of local uninstall. Requires authentication - the server validates the user is a team member with permission to trigger uninstallation workflows. Returns errors so callers can provide user feedback. The repo_salt (first commit hash) provides additional verification.
func (*RepoClient) Query ¶ added in v0.3.0
func (c *RepoClient) Query(req *QueryRequest) (*QueryResponse, error)
Query calls POST /api/v1/query to perform semantic search over team context and ledger data. Requires authentication. Returns search results with relevance scores.
func (*RepoClient) RegisterRepo ¶
func (c *RepoClient) RegisterRepo(req *RepoInitRequest) (*RepoInitResponse, error)
RegisterRepo calls POST /api/v1/repo/init Returns (response, error) - error is nil if call succeeds (even for 4xx/5xx) Gracefully handles 404 (endpoint not yet deployed) by returning nil, nil
func (*RepoClient) WithAuthToken ¶
func (c *RepoClient) WithAuthToken(token string) *RepoClient
WithAuthToken sets the auth token for authenticated requests
type RepoDetailLedger ¶
type RepoDetailLedger struct {
Status string `json:"status"` // "ready", "pending", "error"
RepoURL string `json:"repo_url"` // git clone URL (empty if not ready)
Message string `json:"message,omitempty"` // status message for pending/error
}
RepoDetailLedger is the ledger section of the repo detail response.
type RepoDetailResponse ¶
type RepoDetailResponse struct {
Visibility string `json:"visibility"` // "public" or "private"
AccessLevel string `json:"access_level"` // "member" or "viewer"
Ledger *RepoDetailLedger `json:"ledger"` // null if not provisioned
TeamContexts []RepoDetailTeamContext `json:"team_contexts"` // empty if none accessible
}
RepoDetailResponse represents GET /api/v1/cli/repos/{repo_id}. Returns repo visibility, user access level, ledger status, and accessible team contexts. Works for both members and non-members on public repos.
func (*RepoDetailResponse) IsReadOnly ¶
func (r *RepoDetailResponse) IsReadOnly() bool
IsReadOnly returns true if the user has viewer (read-only) access.
type RepoDetailTeamContext ¶
type RepoDetailTeamContext struct {
TeamID string `json:"team_id"` // team_xxx
Name string `json:"name"` // display name
Slug string `json:"slug,omitempty"` // kebab-case team slug
Visibility string `json:"visibility"` // "public" or "private"
AccessLevel string `json:"access_level"` // "member" or "viewer"
RepoURL string `json:"repo_url"` // git clone URL
}
RepoDetailTeamContext is a team context in the repo detail response.
func (RepoDetailTeamContext) StableID ¶
func (r RepoDetailTeamContext) StableID() string
StableID returns the stable team identifier (team_xxx) for path construction and lookups.
type RepoFingerprint ¶
type RepoFingerprint struct {
// FirstCommit is the hash of the initial commit (same as repo_salt).
FirstCommit string `json:"first_commit"`
// MonthlyCheckpoints maps "YYYY-MM" to the first commit hash of that month.
MonthlyCheckpoints map[string]string `json:"monthly_checkpoints"`
// AncestrySamples contains commit hashes at power-of-2 intervals.
AncestrySamples []string `json:"ancestry_samples"`
// RemoteHashes contains salted SHA256 hashes of normalized remote URLs.
RemoteHashes []string `json:"remote_hashes,omitempty"`
}
RepoFingerprint holds repository identity fingerprint data for detecting identical or related repositories across teams. Enables the API to suggest team merges when multiple teams are working on the same codebase.
type RepoInfo ¶
type RepoInfo struct {
Name string `json:"name"` // e.g., "acme-corp-team-context"
URL string `json:"url"` // git clone URL
Type string `json:"type"` // "team-context" (ledgers use separate API)
TeamID string `json:"team_id,omitempty"` // team_xxx (present for team-context repos)
Slug string `json:"slug,omitempty"` // kebab-case team slug (server-provided)
}
RepoInfo represents a single git repository from the server. NOTE: This API only returns team context repos, not ledgers. Use GetLedgerStatus() for ledger URLs (project-scoped).
type RepoInitRequest ¶
type RepoInitRequest struct {
RepoID string `json:"repo_id"` // Required: prefixed UUIDv7
Type string `json:"type"` // Required: "git" or "svn"
InitAt string `json:"init_at"` // Required: RFC3339 timestamp
Name string `json:"name,omitempty"` // Optional: display name (e.g. "sageox/ox")
Teams []string `json:"teams,omitempty"` // Optional: team IDs to associate repo with
RepoSalt string `json:"repo_salt,omitempty"` // Optional: initial commit hash
RepoRemoteHashes []string `json:"repo_remote_hashes,omitempty"` // Optional: salted hashes
Fingerprint *RepoFingerprint `json:"fingerprint,omitempty"` // Optional: repo identity fingerprint
Identities any `json:"identities,omitempty"` // Optional: resolved user identities (identity.ResolvedIdentities)
IsPublic bool `json:"is_public,omitempty"` // Optional: prevents fork merging
CreatedByEmail string `json:"created_by_email,omitempty"` // Optional: git user email (backward compat)
CreatedByName string `json:"created_by_name,omitempty"` // Optional: git user name (backward compat)
}
RepoInitRequest represents the POST /api/v1/repo/init request
type RepoInitResponse ¶
type RepoInitResponse struct {
RepoID string `json:"repo_id"`
TeamID string `json:"team_id"`
WebBaseURL string `json:"web_base_url,omitempty"` // web dashboard base URL (for enterprise endpoints)
ExistingRepoID string `json:"existing_repo_id,omitempty"` // set when dedup matched a different repo_id
DuplicateWarning string `json:"duplicate_warning,omitempty"` // human-readable warning for CLI display
}
RepoInitResponse represents the POST /api/v1/repo/init response
type RepoMarkerData ¶
type RepoMarkerData struct {
RepoID string `json:"repo_id"`
RepoSalt string `json:"repo_salt"`
Endpoint string `json:"endpoint"`
// TODO: Remove after 2026-01-31 - legacy field support
APIEndpoint string `json:"api_endpoint"` // deprecated: use Endpoint
}
RepoMarkerData holds parsed data from a .repo_* marker file
func ReadFirstRepoMarker ¶
func ReadFirstRepoMarker(sageoxDir string) (*RepoMarkerData, error)
ReadFirstRepoMarker reads the first .repo_* marker file found in the sageox directory. Returns the parsed marker data or nil if no marker found. This is useful for getting repo_id and repo_salt before uninstall.
func (*RepoMarkerData) GetEndpoint ¶
func (m *RepoMarkerData) GetEndpoint() string
GetEndpoint returns the endpoint, preferring new field over legacy
type RepoUninstallRequest ¶
type RepoUninstallRequest struct {
RepoSalt string `json:"repo_salt"` // first commit hash for authentication
}
RepoUninstallRequest represents the POST /api/v1/repo/{repo_id}/uninstall request
type ReposResponse ¶
type ReposResponse struct {
Token string `json:"token"` // PAT for git operations
ServerURL string `json:"server_url"` // GitLab server URL
Username string `json:"username"` // GitLab username
ExpiresAt time.Time `json:"expires_at"` // Token expiration
Repos map[string]RepoInfo `json:"repos"` // Repos indexed by name
Teams []TeamMembership `json:"teams"` // User's team memberships
}
ReposResponse represents the GET /api/v1/cli/repos response. This API returns team context repos only (user-scoped). Ledger URLs are fetched separately via GET /api/v1/repos/{repo_id}/ledger-status (project-scoped).
func (*ReposResponse) TeamMembershipsFromRepos ¶
func (r *ReposResponse) TeamMembershipsFromRepos() []TeamMembership
TeamMembershipsFromRepos derives team memberships from the repos map. Each repo with type "team-context" represents a team the user belongs to. Falls back to the Teams array if populated.
type TeamInfoResponse ¶
type TeamInfoResponse struct {
ID string `json:"id"` // team ID (team_xxx)
Name string `json:"name"` // display name
Slug string `json:"slug,omitempty"` // URL-friendly name
RepoURL string `json:"repo_url,omitempty"` // team context git repo URL
GitToken string `json:"git_token,omitempty"` // token for git operations
}
TeamInfoResponse represents the GET /api/v1/teams/{id} response