sync

package
v0.6.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 31, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNotOwner       = fmt.Errorf("sync: owner role required")
	ErrMemberNotFound = fmt.Errorf("sync: not a member of this repo")
	ErrLastOwner      = fmt.Errorf("sync: cannot remove the last owner")
)

Sentinel errors for RemoveMember so the CLI can map the known refusal cases to friendly messages without string-matching status codes.

View Source
var ErrPageNotFound = fmt.Errorf("sync: page not found")

ErrPageNotFound is returned by ReadPage when the path doesn't exist on the server. Callers use it to distinguish "new page" from real errors.

Functions

func SaveState

func SaveState(hubDir string, s *State) error

SaveState writes the sidecar, creating parent dirs as needed.

func StatePath

func StatePath(hubDir string) string

StatePath returns the sidecar file location under the hub dir.

Types

type ActivityDetail

type ActivityDetail struct {
	Paths  []string `json:"paths,omitempty"`
	Client string   `json:"client,omitempty"`
}

ActivityDetail carries the extra context for an event: the pages a push touched, or the client/agent that pulled. Both fields are optional.

type ActivityEvent

type ActivityEvent struct {
	UserID    string          `json:"user_id"`
	Email     string          `json:"email"`
	Action    string          `json:"action"`
	Detail    *ActivityDetail `json:"detail,omitempty"`
	CreatedAt int64           `json:"created_at"`
}

ActivityEvent is one entry in /v1/repos/:id/activity responses. Mirrors handler.activityBody on the wire. CreatedAt is Unix seconds.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client speaks HTTP to the Contexo server.

func NewClient

func NewClient(baseURL, apiKey string) *Client

NewClient creates a sync client.

func (*Client) CreateRepo

func (c *Client) CreateRepo(repoID string) error

CreateRepo idempotently creates a repo on the server.

func (*Client) DeleteInviteKey

func (c *Client) DeleteInviteKey(repoID, keyID string) error

DeleteInviteKey revokes the invite key with id keyID on repoID.

func (*Client) JoinRepo

func (c *Client) JoinRepo(key string) (string, string, error)

JoinRepo consumes a repo invite key, adding the authenticated user as a member of the target repo. Returns the repo id the key was for.

func (*Client) ListActivity

func (c *Client) ListActivity(repoID string, limit, offset int) ([]ActivityEvent, int, error)

ListActivity returns a page of the repo's push/pull events (newest first) plus the total event count for pagination. limit <= 0 lets the server pick its default; offset <= 0 starts at the newest.

func (*Client) ListInviteKeys

func (c *Client) ListInviteKeys(repoID string) ([]InviteKey, error)

ListInviteKeys returns the active invite keys for repoID (no raw tokens).

func (*Client) ListMembers

func (c *Client) ListMembers(repoID string) ([]Member, error)

ListMembers returns every member of repoID with their email and role. Any member of the repo may call this.

func (*Client) ListRepos

func (c *Client) ListRepos() ([]RepoOption, error)

ListRepos returns the repos the authenticated user can see. Used by the CLI's interactive picker so the user doesn't have to type a repo_id.

func (*Client) MintInviteKey

func (c *Client) MintInviteKey(repoID, label string) (*InviteKey, string, error)

MintInviteKey creates an invite key on repoID with the given label. Returns the persisted key metadata plus the raw token (only returned once).

func (*Client) PageDiff

func (c *Client) PageDiff(repoID, filePath, from, to string, blame bool) (*diff.SectionDiff, error)

PageDiff returns a structured diff of filePath between two commits. Empty from/to defer to the server's defaults (to = HEAD-for-this-path, from = parent of to). When blame is true, each section in the result carries an IntroducedBy field pointing at the commit where its heading first appeared.

func (*Client) PageEvolution

func (c *Client) PageEvolution(repoID, filePath string, limit int, blame bool) ([]EvolutionEntry, error)

PageEvolution returns the full evolution for filePath: up to `limit` recent commits touching the path, each paired with the section-aware diff against its immediate prior commit. One round-trip replaces (history + N diffs) when the caller wants the whole trajectory. blame populates each diff's section IntroducedBy field (best-effort, may add latency on long histories).

func (*Client) PageHistory

func (c *Client) PageHistory(repoID, filePath string, limit int) ([]Commit, error)

PageHistory returns the commits that touched filePath, newest first. limit <= 0 lets the server pick a default.

func (*Client) PullPages

func (c *Client) PullPages(repoID, since string) (*PullResponse, error)

PullPages fetches files changed since the given sha (empty = all).

func (*Client) PushPages

func (c *Client) PushPages(repoID string, req *PushRequest) (*PushResponse, error)

PushPages uploads a batch of files to the server. Returns PushResponse even on 409 so the caller can inspect conflicts.

func (*Client) ReadPage

func (c *Client) ReadPage(repoID, filePath string) ([]byte, string, error)

ReadPage fetches the current content of a single page from the server. Returns ErrPageNotFound if the path isn't tracked yet. The page's last-touch sha is returned via the X-Page-SHA response header.

func (*Client) RemoveMember

func (c *Client) RemoveMember(repoID, userID string) error

RemoveMember removes userID from repoID. Only an owner may do this. It returns ErrNotOwner (403), ErrMemberNotFound (404), or ErrLastOwner (409) for the known refusal cases.

func (*Client) ServerDistill

func (c *Client) ServerDistill(repoID string, req *DistillRequest) (*DistillResponse, error)

ServerDistill posts a buffer to the server's distillation endpoint. Today this always returns an error because the server stub returns 501. The function exists so the CLI's --fallback-server wiring is real and we can swap in the live implementation in Phase 4 without re-plumbing.

func (*Client) SetClientName

func (c *Client) SetClientName(name string)

SetClientName sets the X-Contexo-Client identifier sent on pulls so the server can attribute who/what pulled (e.g. "ctx-cli", "claude-code").

func (*Client) Timeline

func (c *Client) Timeline(repoID string, limit int) ([]Commit, error)

Timeline returns recent commits across the repo.

type Commit

type Commit struct {
	SHA     string    `json:"sha"`
	Author  string    `json:"author"`
	Email   string    `json:"email"`
	Time    time.Time `json:"time"`
	Message string    `json:"message"`
}

Commit mirrors gitstore.CommitMeta on the wire.

type Conflict

type Conflict struct {
	Path              string `json:"path"`
	CurrentSHA        string `json:"current_sha"`
	CurrentContent    []byte `json:"current_content"`
	ExpectedParentSHA string `json:"expected_parent_sha"`
	AncestorContent   []byte `json:"ancestor_content,omitempty"`
}

Conflict mirrors gitstore.Conflict on the wire. AncestorContent is optional; it's populated when the server can locate the ExpectedParentSHA's content, enabling three-way merge by the MCP agent (Layer 4).

type DistillRequest

type DistillRequest struct {
	SessionID string   `json:"session_id"`
	Buffer    []byte   `json:"buffer"`
	PageSlugs []string `json:"page_slugs"`
}

DistillRequest is the body of POST /v1/repos/:id/sync/distill. Phase 4 will define this fully. Today the server returns 501 regardless.

type DistillResponse

type DistillResponse struct {
	SourcePath string `json:"source_path,omitempty"`
	Body       string `json:"body,omitempty"`
	Error      string `json:"error,omitempty"`
}

DistillResponse will carry the server-produced source page (Phase 4). Only the error path matters for v1.

type EvolutionEntry

type EvolutionEntry struct {
	Commit Commit           `json:"commit"`
	Diff   diff.SectionDiff `json:"diff"`
}

EvolutionEntry pairs one commit with its diff against the prior commit for the same path. Mirrors handler.EvolutionEntry on the wire.

type InviteKey

type InviteKey struct {
	ID        string `json:"id"`
	Label     string `json:"label"`
	CreatedAt int64  `json:"created_at"`
	ExpiresAt int64  `json:"expires_at"`
}

InviteKey is one entry in /v1/repos/:id/invite-keys responses (mint + list). Mirrors handler.inviteKeyBody on the wire. CreatedAt and ExpiresAt are Unix seconds.

type Member

type Member struct {
	UserID  string `json:"user_id"`
	Email   string `json:"email"`
	Role    string `json:"role"`
	AddedAt int64  `json:"added_at"`
}

Member is one entry in /v1/repos/:id/members responses. Mirrors handler.memberBody on the wire. AddedAt is Unix seconds.

type PullFile

type PullFile struct {
	Path    string `json:"path"`
	Content string `json:"content"`
	SHA     string `json:"sha"`
}

PullFile is one file in a PullResponse.

type PullResponse

type PullResponse struct {
	NewHead string     `json:"new_head"`
	Files   []PullFile `json:"files"`
}

PullResponse is the response from GET /v1/repos/:id/sync/pull.

type PushFile

type PushFile struct {
	Path      string `json:"path"`
	Content   string `json:"content"`
	ParentSHA string `json:"parent_sha,omitempty"`
}

PushFile is one file in a push request.

type PushRequest

type PushRequest struct {
	AuthorName  string     `json:"author_name"`
	AuthorEmail string     `json:"author_email"`
	Message     string     `json:"message"`
	Files       []PushFile `json:"files"`
}

PushRequest is sent to POST /v1/repos/:id/sync/push.

type PushResponse

type PushResponse struct {
	NewHead   string       `json:"new_head"`
	Pushed    []PushedFile `json:"pushed,omitempty"`
	Conflicts []Conflict   `json:"conflicts,omitempty"`
}

PushResponse is what the server returns for a push.

type PushedFile

type PushedFile struct {
	Path string `json:"path"`
	SHA  string `json:"sha"`
}

PushedFile carries a path and the sha of the commit that created/updated it.

type RepoOption

type RepoOption struct {
	ID   string `json:"id"`
	Role string `json:"role,omitempty"`
}

RepoOption is one entry in the response from GET /v1/repos as the CLI cares about it. Other server-side fields (page_count, last_commit) are ignored when the CLI just needs to enumerate memberships.

type State

type State struct {
	LastPullSHA string            `json:"last_pull_sha,omitempty"`
	PageSHAs    map[string]string `json:"page_shas,omitempty"`
}

State tracks per-page sync metadata so the client knows which parent_sha to send on each push. Lives at .contexo/.sync/state.json.

func LoadState

func LoadState(hubDir string) (*State, error)

LoadState reads the sidecar; returns a zero-value State if the file is absent.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL