copilotadapter

package
v0.1.3 Latest Latest
Warning

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

Go to latest
Published: Oct 1, 2026 License: Apache-2.0 Imports: 40 Imported by: 0

README

copilot-adapter

A REST surface over one host's GitHub Copilot CLI, so a browser UI can start sessions, prompt or steer them, watch the transcript stream, and answer the requests the CLI blocks on. It is the Copilot Pair feature list expressed as a typed HTTP contract instead of an extension.

The service is a library package (house rule CS-10): its entry point is NewCopilotAdapter(options ...Option) (*CopilotAdapter, error), it reads no environment, parses no flags, installs no signal handler and requires no container. There is no cmd/ and no Dockerfile here: those are one-to-one with a binary and live in app/.

Contract first

Nothing here is hand-written twice. Two files own the design, in this order:

File What it owns
application.yaml Structured intent: resources, fields, invariants, capabilities. No routes, no SQL, no wire format. The document you argue about.
openapi.yaml The wire contract: OpenAPI 3.0.3, one operation per capability, one shared Error schema on every 4xx/5xx, UUID ids, RFC 3339 UTC timestamps, enums for every status and kind, limit+cursor pagination.

openapi.yaml is the generator input; gen/api/api.gen.go (models, client, gin server, strict server, embedded spec) and the UI's TypeScript client types are projections of it. Never hand-edit a projection: change the spec and regenerate.

Register installs the shared httpserver.ValidateOpenAPIRequests adapter on the generated routes. It uses kin-openapi's legacy schema router and openapi3filter; Gin still owns HTTP routing. Validation failures use the contract's Error response, and unrelated routes on the same engine remain unaffected. Authentication remains a caller-owned policy: this adapter's current loopback composition uses no-op schema authentication.

Resources: Session (id, displayName, model, workingDirectory, status of starting|idle|running|ended|failed, permissions, ordered tool and shell allowlists, failureCode, failureReason?, createdAt, updatedAt, lastTurnAt?, turnCount), Turn, TranscriptItem (sequence-numbered, assistant deltas collapsed), SessionRequest (exact-identity tool permission) and the read-only Model list the CLI reports.

Handler and service boundary

apiHandlers decodes HTTP input, calls typed in-process service operations, and encodes responses. Handlers and middleware never own database handles, SQLC queries, or transactions. Service operations own durable reads and writes, including session creation, permission policies, and event replay. This adds no IPC between the HTTP and business layers. A request still awaits its service result; PostgreSQL I/O remains synchronous and context-cancellable.

Configuration belongs to config: it loads the declared defaults, invokes the generated protobuf validator, and converts tunables to Go durations and limits. These conversions are not methods on CopilotAdapter. WithConfig retains its validation and copy of the caller's configuration.

Stable failure identities

failureCode is the immutable numeric classification; failureReason is human-readable diagnostic detail. Codes are append-only and never renumbered or reused. The OpenAPI schema owns the identifiers and generated client types.

Code Meaning
0 No failure
1 Provider shutdown
2 Session creation failed
3 Provider session missing during restoration
4 Worktree unavailable
Session permission policies

POST /v1/sessions accepts permissions as ask, approveAll, or allowlist. Omitting it defaults to ask; session responses always read back that mode and both allowlist fields as arrays. Policies and their ordered lists are immutable parts of the creation receipt, so reusing an idempotency key with a different policy is a conflict.

allowlist compares trusted SDK identities only. MCP tools, custom tools, and hooks must have an exact, case-sensitive ToolName; native read and write requests have no trusted name and remain pending. Shell entries are Go path.Match patterns matched against the entire FullCommandText, never a command prefix or argument segment. The match is slash-sensitive: * does not cross /, so go test * does not match go test ./...; use a pattern that describes the complete command. Invalid patterns are rejected when the session is created.

approveAll delegates to the provider's auto-approval handler. Provider and managed-approval restrictions still leave a request pending, as do any policy decision the provider cannot safely auto-approve.

Streaming transports

GET /v1/sessions/{sessionId}/events is Server-Sent Events. The generated strict server cannot produce a streaming body, so its transport handler is written by hand — against the SessionEvent schema declared in the same spec, so its envelope {seq, sessionId, kind, occurredAt, payload} is still generated into Go and TypeScript. Clients resume with Last-Event-ID. Redocly reports SessionEvent as an unused component for exactly this reason; that warning is expected and correct.

The live Kanban uses gotth-live's WebSocket handler at /v1/kanban/live and server-rendered markup at /v1/kanban/view. Both mount on the existing host router. Cards are keyed widget instances; committed adapter writes notify them in memory, without a polling timer. Task columns come from continuity checkpoints, independently of whether the associated agent session is idle.

The widget integration guide explains task associations, checkpoint requirements and explicit refresh of external issue changes. Given an existing adapter and router, mounting and shutdown look like:

board, err := kanban.NewBoard(adapter, []string{"https://workbench.example.invalid"}, logger)
if err != nil {
    return err
}
board.Register(router)
// At host shutdown, after stopping new requests:
return board.Close(shutdownContext)

Regenerate

# From this directory; both commands use pinned generator containers.
bash generate.sh write
bash generate.sh check

The shared generator image pins oapi-codegen v2.8.0 on Go 1.26.5. check regenerates into a temporary directory and compares the output without changing the checked-in bindings.

Validate the spec before regenerating:

docker run --rm --user "$(id -u):$(id -g)" -e HOME=/tmp \
  -e npm_config_cache=/tmp/npm -v "$PWD:/spec" -w /spec node:22-bookworm \
  bash -c 'npx --yes @redocly/cli@1.34.3 lint openapi.yaml'

Run it as a plain binary

The adapter has no cmd/ or flags of its own. The checked-in app/csf/cmd/main.go is the complete, compile-checked composition: it owns configuration, applies the adapter and cron migrations, constructs every required bridge, store, worktree, terminal and schedule dependency, mounts the adapter into Gin, and owns the listener and signal lifecycle.

Use Go 1.26.5, Node 22, an available PostgreSQL database, an authenticated Copilot CLI, and a Git checkout for sessions. Keep a database configuration file outside the checkout with this shape, replacing the example credentials:

{"url":"postgres://user:password@127.0.0.1:5432/copilot_adapter?sslmode=disable"}

From the public module root containing go.mod, replace the absolute paths and run:

(cd services/copilot-adapter/ui && npm ci && VITE_CSF_DASHBOARD_URL=/ npm run build)
go run ./app/csf/cmd serve \
  --workbench-database-config /absolute/path/to/workbench-database.json \
  --workbench-repository /absolute/path/to/repository \
  --workbench-ui ./services/copilot-adapter/ui/dist

Open http://127.0.0.1:14111/ui/; /healthz is the health endpoint. The composition mounts the live board. Its --listen and --origin defaults are 127.0.0.1:14111 and http://127.0.0.1:14111; when changing the address or using a proxy, set --origin to the actual browser origin. An optional --workbench-token-file supplies a token to the Copilot bridge and the HTTP GitHub task source. A consumer embedding the Workbench supplies its own workbench.WithTaskContinuity(...) for checkpoint-backed moves.

A container is one deployment option for that binary, never the definition of the service.

Implementation and tests

Backend

Generated first, in this order, each with a check mode that regenerates into a temp dir and diffs: generate.sh (oapi-codegen v2.8.0 → gen/api/api.gen.go: models, Gin router, strict server, client, embedded spec), store/generate.sh (sqlc 1.31.1 over store/migrations + store/queries.sql → storedb, database/sql flavour so pkg/pgmem can back it in tests), the mockgen //go:generate sites for the two seams in seams.go, and goverter (views.go → views_gen.go: the projection from sqlc's rows to the contract's models, so the mapping between two generated types is generated too).

Handwritten, and only policy (every row→model mapping is generated; every error answer goes through one typed failure and one strict middleware; nullable columns are guregu/null values by sqlc override, so no Null* helper exists): service.go/options.go (the CS-10 library: NewCopilotAdapter(options...) and Register(gin.IRouter), its only mount point), handlers.go and the other transport files (the strict interface through apiHandlers), *_operations.go (typed service operations and their persistence), sessions.go (one owning goroutine for live CLI handles and one per session projecting bridge events into session_events, transcript_items, pending_requests and turn state), sse.go (the event stream over gin's own Stream loop and gin-contrib/sse framing; the generated text/event-stream visitor cannot flush per frame), copilotbridge (the SDK seam; needs a Copilot CLI on the host), and store/migrate.go (the embedded migrations, the only schema source, applied by pkg/sqlmigrate). The IStore seam is sqlc's generated Querier, so it cannot drift from the queries.

Mount it into a binary's existing engine — a service never opens a listener, never has a cmd/, and never ships a Dockerfile; those are one-to-one with a binary and live in app/:

app/csf/cmd/main.go is the maintained reference composition. It supplies every required option and is compiled in CI, so consumers should follow that source instead of copying a partial constructor example that can drift out of date.

Migrations: store.ApplyMigrations(ctx, db) (the shared pkg/sqlmigrate over the embedded .sql files) before Register.

Tests: go test -race ./services/copilot-adapter/... — unit specs in-package over gomock seams through the generated client; integration specs under integration/ on pgmem with the real migrations and a mocked CLI.

The browser front end is ui/: Vite 6 + React 18 + Mantine 8 + TypeScript strict. It is a static bundle with no container of its own — npm run dev serves it and proxies /v1 and /healthz at this host on http://127.0.0.1:8090; npm run build emits dist/, which workbench.MountUI serves from the host's origin.

ui/src/api/schema.d.ts is generated from openapi.yaml by openapi-typescript 7.4.4 (npm run gen), checked for drift by npm run gen:check, and consumed through one openapi-fetch client in ui/src/api/client.ts. The SSE stream is folded by the pure reducer in ui/src/transcript.ts, which collapses assistant deltas into one growing message and a toolCall/toolResult pair into one card, and carries the Last-Event-ID resume point.

Documentation

Overview

Package copilotadapter is the HTTP adapter that fronts a Copilot CLI session with the contract in openapi.yaml. It is a library (CS-10): the binary in cmd/ reads flags and environment, this package never does.

Index

Constants

This section is empty.

Variables

View Source
var ErrAbortPending = errors.New("copilot adapter: an earlier abort is still pending")

ErrAbortPending means an earlier abort RPC still awaits its terminal SDK event. A second abort must not replace that event's exact target.

View Source
var ErrAbortTargetMismatch = errors.New("copilot adapter: active turn does not match the abort target")

ErrAbortTargetMismatch means the caller's durable expected turn is no longer the CLI's foreground turn. The bridge must not guess and abort a successor.

View Source
var ErrBridgeSessionMissing = errors.New("copilot adapter: bridge session missing")

ErrBridgeSessionMissing means the Copilot SDK has proved that a persisted adapter session no longer exists in its durable session store. Only this class may terminalize that session during restart; resume dependency errors must leave it retryable.

View Source
var ErrInvalidWorktree = errors.New("copilot adapter: invalid worktree")

ErrInvalidWorktree means a persisted path definitively falls outside the configured repository boundary. Callers may quarantine only this class; git, filesystem and cancellation failures leave persisted state untouched.

View Source
var ErrNoActiveTurn = errors.New("copilot adapter: no active turn")

ErrNoActiveTurn means an abort cannot select a turn without guessing.

Functions

func DefaultAdapterConfig

func DefaultAdapterConfig() *copilotv1.AdapterConfig

DefaultAdapterConfig preserves the service's public entry point while the configuration package owns defaults and their typed projections.

Types

type BridgeEvent

type BridgeEvent struct {
	// ID is the source event's stable identifier. The concrete SDK supplies its
	// event UUID; callback-originated events use the callback request UUID.
	ID         string
	Kind       BridgeEventKind
	OccurredAt time.Time
	TurnID     *uuid.UUID
	Text       string
	// FailureCode classifies terminal failures independently of diagnostic text.
	FailureCode api.FailureCode
	ToolName    ToolName
	// ToolCallID is the CLI's own identifier for one tool invocation. It
	// pairs a toolResult with the toolCall that produced it even when two
	// calls to the same tool overlap.
	ToolCallID  ToolCallID
	Author      string
	RequestID   *uuid.UUID
	RequestKind BridgeRequestKind
	// ResolutionDecision is approve or deny on RequestCompleted.
	ResolutionDecision string
	AgentID            string
	DisplayName        string
	SessionBusy        bool
	Usage              *api.UsageObservation
	UsagePayload       json.RawMessage
}

BridgeEvent is one thing the CLI told the adapter. It is data, not behaviour, so it is a struct rather than an interface (CS-8's data-shaped test).

type BridgeEventKind

type BridgeEventKind string

BridgeEventKind names what a BridgeEvent reports. It mirrors the contract's SessionEventKind without importing the generated HTTP types into the seam.

const (
	// BridgeEventUsage preserves provider measurements even after turn completion.
	BridgeEventUsage BridgeEventKind = "usage"
	// BridgeEventAssistantDelta is a token delta on the assistant's reply.
	BridgeEventAssistantDelta BridgeEventKind = "assistantDelta"
	// BridgeEventAssistantMessage is one completed assistant message.
	BridgeEventAssistantMessage BridgeEventKind = "assistantMessage"
	// BridgeEventToolCall is the CLI invoking a tool.
	BridgeEventToolCall BridgeEventKind = "toolCall"
	// BridgeEventToolResult is a tool's output coming back.
	BridgeEventToolResult BridgeEventKind = "toolResult"
	// BridgeEventTurnStarted marks the exact FIFO turn the CLI began.
	BridgeEventTurnStarted BridgeEventKind = "turnStarted"
	// BridgeEventTurnCompleted closes the turn in flight.
	BridgeEventTurnCompleted BridgeEventKind = "turnCompleted"
	// BridgeEventTurnAborted closes the exact foreground turn canceled by the CLI.
	BridgeEventTurnAborted BridgeEventKind = "turnAborted"
	// BridgeEventTurnFailed closes the exact foreground turn whose SDK request failed.
	BridgeEventTurnFailed BridgeEventKind = "turnFailed"
	// BridgeEventRequestOpened raises one exact-identity permission request.
	BridgeEventRequestOpened BridgeEventKind = "requestOpened"
	// BridgeEventRequestCompleted reports the exact permission result observed
	// from the SDK, including decisions made by another attached client.
	BridgeEventRequestCompleted BridgeEventKind = "requestCompleted"
	// BridgeEventSubagentStarted opens one actual SDK subagent lifecycle.
	BridgeEventSubagentStarted BridgeEventKind = "subagentStarted"
	// BridgeEventSubagentCompleted closes a successful SDK subagent lifecycle.
	BridgeEventSubagentCompleted BridgeEventKind = "subagentCompleted"
	// BridgeEventSubagentFailed closes a failed SDK subagent lifecycle.
	BridgeEventSubagentFailed BridgeEventKind = "subagentFailed"
	// BridgeEventSubagentMessage is one completed subagent progress message.
	BridgeEventSubagentMessage BridgeEventKind = "subagentMessage"
	// BridgeEventSubagentProgress is the SDK's live assistant.intent update for
	// one identified subagent.
	BridgeEventSubagentProgress BridgeEventKind = "subagentProgress"
	// BridgeEventSubagentToolCall is a tool invoked by a subagent.
	BridgeEventSubagentToolCall BridgeEventKind = "subagentToolCall"
	// BridgeEventSubagentToolResult is a subagent tool's output.
	BridgeEventSubagentToolResult BridgeEventKind = "subagentToolResult"
	// BridgeEventFailed is reserved for an unrecoverable CLI session failure.
	BridgeEventFailed BridgeEventKind = "failed"
)

type BridgeModel

type BridgeModel struct {
	ID           string
	DisplayName  string
	Capabilities []api.ModelCapability
}

BridgeModel is one model the CLI reports.

type BridgePrompt

type BridgePrompt struct {
	TurnID uuid.UUID
	Text   string
	Mode   string
	Author string
}

BridgePrompt is one durable adapter turn handed to the CLI. TurnID is queued before Send crosses the external boundary, then paired with the SDK's assistant.turn_start identifier by the concrete bridge.

type BridgePromptDelivery

type BridgePromptDelivery uint8

BridgePromptDelivery states what the bridge knows about one Send call after it returns. An error after crossing the SDK boundary is deliberately Unknown: the adapter keeps the durable turn in its distinct unknown state until a retry or later SDK event proves acceptance instead of guessing that delivery failed.

const (
	// BridgePromptDeliveryUnknown means the bridge cannot prove whether the SDK
	// accepted the prompt.
	BridgePromptDeliveryUnknown BridgePromptDelivery = iota
	// BridgePromptDeliveryAccepted means the SDK accepted the prompt.
	BridgePromptDeliveryAccepted
	// BridgePromptDeliveryRejected means the prompt definitely did not cross the
	// SDK boundary and may be failed or retried safely.
	BridgePromptDeliveryRejected
)

type BridgeRequestKind

type BridgeRequestKind string

BridgeRequestKind names the kind of decision the CLI is asking for.

const (
	// BridgeRequestPermission is the CLI asking to run a tool.
	BridgeRequestPermission BridgeRequestKind = "permission"
)

type BridgeResolution

type BridgeResolution struct {
	RequestID uuid.UUID
	Decision  string
}

BridgeResolution is a decision routed back into a pending CLI request.

type BridgeRestoredTurn

type BridgeRestoredTurn struct {
	ID              uuid.UUID
	Mode            api.PromptMode
	Status          api.TurnStatus
	DeliveryUnknown bool
}

BridgeRestoredTurn preserves the scheduling lane a durable turn occupied before the adapter process restarted.

type BridgeSession

type BridgeSession struct {
	Events                <-chan BridgeEvent
	UsageHistory          func(ctx context.Context) ([]BridgeEvent, error)
	Send                  func(ctx context.Context, prompt BridgePrompt) (BridgePromptDelivery, error)
	AcknowledgeDelivery   func(turnID uuid.UUID)
	ActiveTurn            func() (uuid.UUID, bool)
	Abort                 func(ctx context.Context, expectedTurnID uuid.UUID) (uuid.UUID, error)
	SetModel              func(ctx context.Context, model string) error
	Resolve               func(ctx context.Context, resolution BridgeResolution) error
	AcknowledgeResolution func(requestID uuid.UUID)
	AbandonResolution     func(requestID uuid.UUID)
	Close                 func(ctx context.Context) error
}

BridgeSession is the live handle on one CLI session. Every capability is a function value and the stream is a channel, so there is no behaviour left to abstract and no interface to exempt (CS-8's data-shaped test).

type BridgeSessionSpec

type BridgeSessionSpec struct {
	SessionID uuid.UUID
	// AgentID is a host-scoped durable identity. The adapter carries it without
	// interpreting permissions or service-specific configuration.
	AgentID            string
	Model              string
	WorkingDirectory   string
	SystemInstructions string
	PermissionPolicy   PermissionPolicy
	RestoredTurns      []BridgeRestoredTurn
}

BridgeSessionSpec is what the adapter asks the bridge to start.

type CopilotAdapter

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

CopilotAdapter is the adapter, mounted into a binary's existing Gin engine through Register. It owns no process concerns and never opens a listener: a service is an option slid into a pre-existing binary (CS-10).

func NewCopilotAdapter

func NewCopilotAdapter(options ...Option) (*CopilotAdapter, error)

NewCopilotAdapter validates the whole option set, then builds the adapter.

func (*CopilotAdapter) Close

func (adapter *CopilotAdapter) Close() error

Close ends every live CLI session and stops the registry. Run does not call it: the binary that owns the process decides when the sessions die.

func (*CopilotAdapter) InvalidateWorkspace

func (adapter *CopilotAdapter) InvalidateWorkspace()

InvalidateWorkspace invalidates snapshots after an external source is ingested. It does not itself fetch GitHub state or infer task completion.

func (*CopilotAdapter) LinkWorkspaceTask

func (adapter *CopilotAdapter) LinkWorkspaceTask(ctx context.Context, sessionID uuid.UUID, taskURL string, expectedGeneration int64) (api.WorkspaceTaskLink, error)

LinkWorkspaceTask retains only an explicit association. expectedGeneration belongs to that association, not to the checkpoint's Git revision.

func (*CopilotAdapter) MoveWorkspaceTask

func (adapter *CopilotAdapter) MoveWorkspaceTask(ctx context.Context, link api.WorkspaceTaskLink, expectedID string, status workv1.WorkStatus, nextAction, reason string) (*workv1.ResumeRecord, error)

MoveWorkspaceTask publishes a prepared checkpoint and verifies its retained receipt. The caller supplies the observed association and checkpoint tip. The existing session mutation owner serializes moves with relinking in this host. GitHub's stale/fork checks still apply; comments are not a remote CAS.

func (*CopilotAdapter) RefreshWorkspace

func (adapter *CopilotAdapter) RefreshWorkspace(ctx context.Context) error

RefreshWorkspace refreshes task observations and invalidates the shared view.

func (*CopilotAdapter) Register

func (adapter *CopilotAdapter) Register(router gin.IRouter) error

Register installs OpenAPI request validation and the generated strict handlers onto router. It is the service's only mount point.

func (*CopilotAdapter) RestoreSessions

func (adapter *CopilotAdapter) RestoreSessions(ctx context.Context) error

RestoreSessions reconnects every persisted nonterminal SDK session before HTTP or scheduled jobs can address it. Each stored working directory is revalidated through the configured worktree manager first, so restart does not turn legacy database paths into filesystem authority.

func (*CopilotAdapter) RunSchedules

func (adapter *CopilotAdapter) RunSchedules(ctx context.Context) error

RunSchedules owns the reloadable Candace cron runtime. The mounting binary runs it beside HTTP; each active product row becomes an actual cron job, so cron owns recurrence, catch-up, overlap, leases and occurrence completion.

func (*CopilotAdapter) SubscribeWorkspace

func (adapter *CopilotAdapter) SubscribeWorkspace() WorkspaceSubscription

SubscribeWorkspace observes committed adapter writes in this process. The caller owns the returned subscription and must close it on cancellation.

func (*CopilotAdapter) Telemetry

func (adapter *CopilotAdapter) Telemetry(ctx context.Context) (api.TelemetrySnapshot, error)

Telemetry reads the same retained facts used by the API, board and metrics. SQLC keyset pagination prevents silently truncating totals at one page.

func (*CopilotAdapter) Workspace

func (adapter *CopilotAdapter) Workspace(ctx context.Context) (api.WorkspaceSnapshot, error)

Workspace reads retained identities without filesystem inspection or provider calls. SubscribeWorkspace must be called before loading a live snapshot.

func (*CopilotAdapter) WorkspaceTask

func (adapter *CopilotAdapter) WorkspaceTask(ctx context.Context, taskURL string, force bool) *workv1.ResumeRecord

WorkspaceTask returns a cloned observation, never mutable shared state. force is used at explicit ingestion boundaries after external issue changes.

type ICopilotBridge

type ICopilotBridge interface {
	CreateSession(ctx context.Context, spec BridgeSessionSpec) (BridgeSession, error)
	ResumeSession(ctx context.Context, spec BridgeSessionSpec) (BridgeSession, error)
	ListModels(ctx context.Context) ([]BridgeModel, error)
}

ICopilotBridge is the seam over the Copilot CLI. Everything above it is testable with a generated mock; the concrete implementation needs a CLI on the host.

type IStore

type IStore interface {
	storedb.Querier
	Transact(ctx context.Context, transaction StoreTransaction) error
}

IStore is the persistence seam. Its method set is sqlc's own generated Querier (emit_interface in store/sqlc.yaml), plus the one transaction capability SQLC deliberately does not generate. The concrete store binds a callback to *sql.Tx so related domain facts and their event pointer commit together.

type ITerminalManager

type ITerminalManager interface {
	List(worktreeID uuid.UUID) []TerminalSnapshot
	Create(ctx context.Context, spec TerminalSpec) (TerminalSnapshot, error)
	Get(identifier uuid.UUID) (TerminalSnapshot, bool)
	Resize(identifier uuid.UUID, rows int32, columns int32) (TerminalSnapshot, error)
	Write(identifier uuid.UUID, data string) (TerminalSnapshot, error)
	Stop(identifier uuid.UUID) (TerminalSnapshot, error)
	EventsAfter(identifier uuid.UUID, afterSeq int64) (TerminalEventReplay, bool)
	Close() error
}

ITerminalManager owns PTYs and their bounded in-memory replay.

type IWorktreeManager

type IWorktreeManager interface {
	Repositories() []Repository
	Prepare(ctx context.Context, request WorktreeRequest) (PreparedWorktree, error)
	Reuse(ctx context.Context, repositoryID string, path string) (PreparedWorktree, error)
	Inspect(ctx context.Context, path string) (WorktreeSnapshot, error)
	Changes(ctx context.Context, path string) (WorktreeChanges, error)
	Release(ctx context.Context, worktree PreparedWorktree) error
}

IWorktreeManager owns the git/filesystem boundary for configured roots.

type Option

type Option func(configuration *configuration) error

Option configures a Service before New builds anything (CS-6, CS-10).

func WithBridge

func WithBridge(bridge ICopilotBridge) Option

WithBridge supplies the Copilot CLI seam. Required.

func WithConfig

func WithConfig(config *copilotv1.AdapterConfig) Option

WithConfig supplies the adapter's tunables. The message and its bounds are generated from proto/candace/copilot/v1/adapter.proto and the defaults come from config/defaults.json, so a caller overrides a DECLARED value rather than a constant in source. Optional; DefaultAdapterConfig is the fallback.

func WithLogger

func WithLogger(logger *slog.Logger) Option

WithLogger supplies the structured logger. Optional; the service falls back to slog.Default.

func WithScheduleStore

func WithScheduleStore(scheduleStore cron.IStore) Option

WithScheduleStore supplies candace/pkg/cron's occurrence and lease store.

func WithStore

func WithStore(store IStore) Option

WithStore supplies the persistence seam. Required.

func WithTaskContinuity

func WithTaskContinuity(source *workcontinuity.Continuity) Option

WithTaskContinuity supplies the issue authority used for shared planning. Without it, sessions still render, but task status is visibly unavailable.

func WithTerminalManager

func WithTerminalManager(terminals ITerminalManager) Option

WithTerminalManager supplies the process-owned PTY boundary.

func WithVersion

func WithVersion(version string) Option

WithVersion labels the build in the health response.

func WithWorktreeManager

func WithWorktreeManager(worktrees IWorktreeManager) Option

WithWorktreeManager supplies the configured repository/git boundary.

type PermissionPolicy

type PermissionPolicy struct {
	Mode           api.PermissionPolicyMode
	ToolAllowlist  []string
	ShellAllowlist []string
}

PermissionPolicy is the durable authority supplied to both new and restored bridge sessions. Empty slices are deliberate: only Mode can broaden access.

type PreparedWorktree

type PreparedWorktree struct {
	Repository Repository
	Path       string
	BaseRef    string
	Managed    bool
}

PreparedWorktree is a validated working directory ready for a CLI session.

type Repository

type Repository struct {
	ID          string
	DisplayName string
	Root        string
	DefaultRef  string
}

Repository describes one configured root the browser is allowed to select.

type StoreTransaction

type StoreTransaction func(queries storedb.Querier) error

StoreTransaction is one atomic mutation against a transaction-bound SQLC query set. The callback must not retain queries after it returns.

type TerminalEventReplay

type TerminalEventReplay struct {
	// Changed closes when newer output or a lifecycle event is published. It is
	// captured with Events so a subscriber cannot miss a write before waiting.
	Changed  <-chan struct{}
	Snapshot TerminalSnapshot
	Events   []TerminalOutput
}

TerminalEventReplay is one atomic view of a terminal's current lifecycle state and every retained event after a cursor. The snapshot and events must come from the same read so a stream cannot miss the terminal event while deciding that an exited process is already caught up.

type TerminalOutput

type TerminalOutput struct {
	Seq             int64
	TerminalID      uuid.UUID
	Kind            string
	Data            string
	ExitCode        *int32
	OccurredAt      time.Time
	ReplayTruncated bool
}

TerminalOutput is one bounded replay event.

type TerminalSnapshot

type TerminalSnapshot struct {
	ID         uuid.UUID
	WorktreeID uuid.UUID
	Rows       int32
	Columns    int32
	Shell      string
	Status     string
	ExitCode   *int32
	CreatedAt  time.Time
	UpdatedAt  time.Time
}

TerminalSnapshot is the lifecycle state returned by the terminal manager.

type TerminalSpec

type TerminalSpec struct {
	WorktreeID uuid.UUID
	Directory  string
	Rows       int32
	Columns    int32
}

TerminalSpec is a process-owned shell request in one persisted worktree.

type ToolCallID

type ToolCallID string

ToolCallID is the CLI's own identifier for one tool invocation; it pairs a result with the call that produced it.

type ToolName

type ToolName string

ToolName identifies a tool the CLI can invoke. The protocol leaves the set open (MCP servers and custom tools register names at run time) and the SDK exports no enumeration of the built-ins, so this is a typed identifier rather than an enum; the names the SDK does export are re-exported typed from copilotbridge.

type TraceExporter

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

TraceExporter is one caller-owned goroutine over the existing SQL outbox. The official OTLP client owns the wire protocol; SQL owns retry and fencing.

func NewTraceExporter

func NewTraceExporter(queries storedb.Querier, config *copilotv1.TraceExportConfig, options ...TraceOption) (*TraceExporter, error)

func (*TraceExporter) Close

func (exporter *TraceExporter) Close(ctx context.Context) error

func (*TraceExporter) DeliverNext

func (exporter *TraceExporter) DeliverNext(ctx context.Context) (bool, error)

DeliverNext acknowledges only after the official client confirms acceptance. A shutdown or lost acknowledgement leaves the lease recoverable; stable IDs make a replay refer to the same observation, not a new model invocation.

func (*TraceExporter) Start

func (exporter *TraceExporter) Start(ctx context.Context) error

Start is explicit: constructing a capability never starts background work.

type TraceOption

type TraceOption func(exporter *TraceExporter)

func WithTraceClient

func WithTraceClient(client otlptrace.Client) TraceOption

type WorkspaceSubscription

type WorkspaceSubscription struct {
	Changed <-chan struct{}
	Close   func()
}

WorkspaceSubscription coalesces committed changes into a request to reload current state. Subscribe before reading the initial snapshot so a commit during that read remains pending. Close releases the subscription; it starts no goroutine and is safe to call repeatedly.

type WorktreeChange

type WorktreeChange struct {
	Path          string
	PreviousPath  string
	IndexState    string
	WorktreeState string
}

WorktreeChange is one porcelain-v2 status entry.

type WorktreeChanges

type WorktreeChanges struct {
	HeadSHA   string
	Clean     bool
	Files     []WorktreeChange
	Patch     string
	Truncated bool
	Captured  time.Time
}

WorktreeChanges is the bounded current diff plus file states.

type WorktreeRequest

type WorktreeRequest struct {
	RepositoryID string
	Mode         string
	BaseRef      string
	SessionID    uuid.UUID
}

WorktreeRequest asks the concrete adapter to reuse a configured root or create an isolated git worktree. No browser-supplied path crosses the seam.

type WorktreeSnapshot

type WorktreeSnapshot struct {
	Branch  string
	HeadSHA string
	Clean   bool
	State   string
}

WorktreeSnapshot is current git state read from disk.

Directories

Path Synopsis
Package copilotbridge is the concrete ICopilotBridge over the Copilot Go SDK.
Package copilotbridge is the concrete ICopilotBridge over the Copilot Go SDK.
gen
api
Package api provides primitives to interact with the openapi HTTP API.
Package api provides primitives to interact with the openapi HTTP API.
Package kanban mounts shared task planning into an existing HTTP server.
Package kanban mounts shared task planning into an existing HTTP server.
card
Package card is the generated KanbanCard widget.
Package card is the generated KanbanCard widget.
proto
Package store carries the adapter's schema.
Package store carries the adapter's schema.
Package terminaladapter owns interactive PTYs for the Copilot workbench.
Package terminaladapter owns interactive PTYs for the Copilot workbench.
Package workbench composes the existing Copilot service for caller-owned hosts.
Package workbench composes the existing Copilot service for caller-owned hosts.
Package worktreeadapter implements configured git repository and worktree operations for the Copilot adapter.
Package worktreeadapter implements configured git repository and worktree operations for the Copilot adapter.

Jump to

Keyboard shortcuts

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