// Package backendrpc is the Go client for the local Rust Resource Backend. // // The package talks directly to bat.sock over newline-delimited JSON-RPC 2.0. // It is the default Go integration path for bat-api; do not shell out to the // bat binary for normal service calls. package backendrpc import ( "bufio" "context" "encoding/json" "errors" "fmt" "net" "sync/atomic" "time" ) const jsonRPCVersion = "2.0" // Client calls the local Rust daemon through a Unix domain socket. type Client struct { SocketPath string Timeout time.Duration // DialContext exists for tests and alternative local transports. DialContext func(ctx context.Context, network string, address string) (net.Conn, error) seq atomic.Uint64 } // New returns a client for the given bat.sock path. func New(socketPath string) *Client { return &Client{SocketPath: socketPath, Timeout: 30 * time.Second} } // APIError mirrors the Rust ApiError envelope payload. type APIError struct { Code string `json:"code"` Kind string `json:"kind"` Domain string `json:"domain"` Location string `json:"location"` Message string `json:"message"` Retryable bool `json:"retryable"` } func (e *APIError) Error() string { if e == nil { return "" } if e.Code == "" { return e.Message } return fmt.Sprintf("%s %s", e.Code, e.Message) } // JSONRPCError is a transport-level JSON-RPC error. type JSONRPCError struct { Code int `json:"code"` Message string `json:"message"` } func (e *JSONRPCError) Error() string { if e == nil { return "" } return fmt.Sprintf("json-rpc error %d: %s", e.Code, e.Message) } // Envelope is the application-level payload carried in JSON-RPC result. type Envelope struct { OK bool `json:"ok"` Status string `json:"status"` Data json.RawMessage `json:"data,omitempty"` Error *APIError `json:"error,omitempty"` RequestID string `json:"request_id"` } type rpcRequest struct { JSONRPC string `json:"jsonrpc"` ID uint64 `json:"id"` Method string `json:"method"` Params any `json:"params"` } type rpcResponse struct { JSONRPC string `json:"jsonrpc"` ID uint64 `json:"id"` Result json.RawMessage `json:"result,omitempty"` Error *JSONRPCError `json:"error,omitempty"` } // Call invokes method and decodes the envelope data into out when out is non-nil. func (c *Client) Call(ctx context.Context, method string, params any, out any) (*Envelope, error) { envelope, err := c.callEnvelope(ctx, method, params) if err != nil { return nil, err } if !envelope.OK { if envelope.Error != nil { return envelope, envelope.Error } return envelope, errors.New("backend rpc returned ok=false without error payload") } if out != nil && len(envelope.Data) > 0 && string(envelope.Data) != "null" { if err := json.Unmarshal(envelope.Data, out); err != nil { return envelope, fmt.Errorf("decode %s response data: %w", method, err) } } return envelope, nil } func (c *Client) callEnvelope(ctx context.Context, method string, params any) (*Envelope, error) { if c.SocketPath == "" { return nil, errors.New("backend rpc socket path is empty") } conn, err := c.dial(ctx) if err != nil { return nil, err } defer conn.Close() if deadline, ok := c.deadline(ctx); ok { _ = conn.SetDeadline(deadline) } req := rpcRequest{ JSONRPC: jsonRPCVersion, ID: c.seq.Add(1), Method: method, Params: params, } if err := json.NewEncoder(conn).Encode(&req); err != nil { return nil, fmt.Errorf("write backend rpc request %s: %w", method, err) } line, err := bufio.NewReader(conn).ReadBytes('\n') if err != nil { return nil, fmt.Errorf("read backend rpc response %s: %w", method, err) } var resp rpcResponse if err := json.Unmarshal(line, &resp); err != nil { return nil, fmt.Errorf("decode backend rpc response %s: %w", method, err) } if resp.Error != nil { return nil, resp.Error } if len(resp.Result) == 0 { return nil, fmt.Errorf("backend rpc %s response missing result", method) } var envelope Envelope if err := json.Unmarshal(resp.Result, &envelope); err != nil { return nil, fmt.Errorf("decode backend rpc envelope %s: %w", method, err) } return &envelope, nil } func (c *Client) dial(ctx context.Context) (net.Conn, error) { if c.DialContext != nil { return c.DialContext(ctx, "unix", c.SocketPath) } var dialer net.Dialer return dialer.DialContext(ctx, "unix", c.SocketPath) } func (c *Client) deadline(ctx context.Context) (time.Time, bool) { if deadline, ok := ctx.Deadline(); ok { return deadline, true } if c.Timeout > 0 { return time.Now().Add(c.Timeout), true } return time.Time{}, false } type boolParam struct { Force bool `json:"force"` } type pageParam struct { Offset int `json:"offset"` Limit int `json:"limit"` } type tailParam struct { Tail int `json:"tail"` } type taskIDParam struct { TaskID string `json:"task_id"` } type TextUnitQueryParams struct { Offset int `json:"offset,omitempty"` Limit int `json:"limit,omitempty"` Destination string `json:"destination,omitempty"` PathPattern string `json:"path_pattern,omitempty"` ArchiveEntry string `json:"archive_entry,omitempty"` PathID *int64 `json:"path_id,omitempty"` ClassID *int `json:"class_id,omitempty"` FieldPath string `json:"field_path,omitempty"` Format string `json:"format,omitempty"` } type UnityFSTextAssetPatchParams struct { BundlePath string `json:"bundle_path"` SerializedFilePath string `json:"serialized_file_path"` PathID int64 `json:"path_id"` ReplacementPath string `json:"replacement_path"` TargetPath string `json:"target_path"` ExpectedName *string `json:"expected_name,omitempty"` } type UnityFSStringFieldPatchParams struct { BundlePath string `json:"bundle_path"` SerializedFilePath string `json:"serialized_file_path"` PathID int64 `json:"path_id"` FieldPath string `json:"field_path"` ReplacementText *string `json:"replacement_text,omitempty"` ReplacementPath string `json:"replacement_path,omitempty"` TargetPath string `json:"target_path"` ExpectedValue *string `json:"expected_value,omitempty"` } type UnityFSFieldPatchParams struct { BundlePath string `json:"bundle_path"` SerializedFilePath string `json:"serialized_file_path"` PathID int64 `json:"path_id"` FieldPath string `json:"field_path"` Replacement json.RawMessage `json:"replacement"` TargetPath string `json:"target_path"` ExpectedValue json.RawMessage `json:"expected_value,omitempty"` } // ScheduleMutationParams is shared by schedule.add, schedule.update, and // schedule.remove. Omitted pointer fields preserve the existing schedule on // update; clear_* fields explicitly remove values. type ScheduleMutationParams struct { ID string `json:"id,omitempty"` Group string `json:"group,omitempty"` Action string `json:"action,omitempty"` Args []string `json:"args,omitempty"` NextRunUnixSeconds *uint64 `json:"next_run_unix_seconds,omitempty"` DelaySeconds *uint64 `json:"delay_seconds,omitempty"` EverySeconds *uint64 `json:"every_seconds,omitempty"` Count *uint64 `json:"count,omitempty"` ClearArgs bool `json:"clear_args,omitempty"` ClearEvery bool `json:"clear_every,omitempty"` Enabled *bool `json:"enabled,omitempty"` } // ScheduleListParams filters the Rust-owned schedule store. type ScheduleListParams struct { ID string `json:"id,omitempty"` Group string `json:"group,omitempty"` Enabled *bool `json:"enabled,omitempty"` } // ScheduleRunParams selects a schedule or runs every due enabled schedule. type ScheduleRunParams struct { ID string `json:"id,omitempty"` Group string `json:"group,omitempty"` Force bool `json:"force,omitempty"` MaxRuns *uint64 `json:"max_runs,omitempty"` } // TranslationTaskUnitResultParam is the dashboard/manual-review subset of one // TextUnit result accepted by Rust translation.task.update. type TranslationTaskUnitResultParam struct { UnitID string `json:"unit_id"` SourceText string `json:"source_text"` TranslatedText string `json:"translated_text"` GlossaryOverride *GlossaryOverride `json:"glossary_override,omitempty"` } // TranslationTaskUpdateParams is used by translation.task.update to persist // provider worker state and optional manual-review text for one task in the // current official release. type TranslationTaskUpdateParams struct { TaskID string `json:"task_id"` Status string `json:"status"` FailureReason string `json:"failure_reason,omitempty"` ProviderRunID string `json:"provider_run_id,omitempty"` Provider string `json:"provider,omitempty"` TranslationResults []TranslationTaskUnitResultParam `json:"translation_results,omitempty"` } // TranslationTaskListParams filters the Rust-owned translation task queue. // The result shape is intentionally left as Rust JSON so Go does not duplicate // the translation task schema. type TranslationTaskListParams struct { Offset *uint64 `json:"offset,omitempty"` Limit *uint64 `json:"limit,omitempty"` TaskID string `json:"task_id,omitempty"` ReleaseID string `json:"release_id,omitempty"` Destination string `json:"destination,omitempty"` PathPattern string `json:"path_pattern,omitempty"` ArchiveEntry string `json:"archive_entry,omitempty"` Status string `json:"status,omitempty"` WorkerStatus string `json:"worker_status,omitempty"` ParseStatus string `json:"parse_status,omitempty"` Format string `json:"format,omitempty"` HasReason *bool `json:"has_reason,omitempty"` HasFailureReason *bool `json:"has_failure_reason,omitempty"` } // TranslationWorkerRunParams starts one Rust-owned provider worker task. // Pointer numeric fields preserve explicit zeroes so Rust can reject invalid // dashboard input instead of receiving omitted defaults. type TranslationWorkerRunParams struct { Provider string `json:"provider,omitempty"` FixturePath string `json:"fixture_path,omitempty"` TranslationMemoryPath string `json:"translation_memory_path,omitempty"` GlossaryPath string `json:"glossary_path,omitempty"` Concurrency *uint64 `json:"concurrency,omitempty"` MaxAttempts *uint64 `json:"max_attempts,omitempty"` LeaseSeconds *uint64 `json:"lease_seconds,omitempty"` RetryBackoffSeconds *uint64 `json:"retry_backoff_seconds,omitempty"` MaxTasks *uint64 `json:"max_tasks,omitempty"` WorkerID string `json:"worker_id,omitempty"` } // TranslationWorkerConfig mirrors the accepted worker config returned by Rust. type TranslationWorkerConfig struct { Provider string `json:"provider"` FixturePath string `json:"fixture_path,omitempty"` TranslationMemoryPath string `json:"translation_memory_path,omitempty"` GlossaryPath string `json:"glossary_path,omitempty"` Concurrency uint64 `json:"concurrency"` MaxAttempts uint64 `json:"max_attempts"` LeaseSeconds uint64 `json:"lease_seconds"` RetryBackoffSeconds uint64 `json:"retry_backoff_seconds"` MaxTasks *uint64 `json:"max_tasks,omitempty"` WorkerID string `json:"worker_id"` } // TranslationWorkerRunResult is returned when translation.worker.run is queued. type TranslationWorkerRunResult struct { TaskID string `json:"task_id"` Kind string `json:"kind"` Worker TranslationWorkerConfig `json:"worker"` } // TranslationMemoryContext is the stable TextUnit context sent to Rust. type TranslationMemoryContext map[string]string // TranslationMemorySourceKind identifies who supplied the translation. type TranslationMemorySourceKind string const ( TranslationMemorySourceProvider TranslationMemorySourceKind = "provider" TranslationMemorySourceManual TranslationMemorySourceKind = "manual" TranslationMemorySourceImported TranslationMemorySourceKind = "imported" ) // TranslationMemoryTrustStatus is the Rust-owned review state. type TranslationMemoryTrustStatus string const ( TranslationMemoryStatusCandidate TranslationMemoryTrustStatus = "candidate" TranslationMemoryStatusTrusted TranslationMemoryTrustStatus = "trusted" TranslationMemoryStatusSuperseded TranslationMemoryTrustStatus = "superseded" TranslationMemoryStatusRejected TranslationMemoryTrustStatus = "rejected" ) // TranslationMemoryMatchKind describes why a record was returned. type TranslationMemoryMatchKind string const ( TranslationMemoryMatchStrongExact TranslationMemoryMatchKind = "strong_exact" TranslationMemoryMatchCandidateExact TranslationMemoryMatchKind = "candidate_exact" TranslationMemoryMatchSourceOnly TranslationMemoryMatchKind = "source_only" ) // TranslationMemorySummaryParams selects an optional Rust-owned TM database. type TranslationMemorySummaryParams struct { TranslationMemoryPath string `json:"translation_memory_path,omitempty"` } // TranslationMemoryQueryParams queries Rust-owned TM records by raw source and // optional complete TextUnit context. type TranslationMemoryQueryParams struct { TranslationMemoryPath string `json:"translation_memory_path,omitempty"` SourceText string `json:"source_text"` SourceContext TranslationMemoryContext `json:"source_context,omitempty"` Limit *uint64 `json:"limit,omitempty"` } // TranslationMemoryConfirmParams explicitly promotes one candidate record. type TranslationMemoryConfirmParams struct { TranslationMemoryPath string `json:"translation_memory_path,omitempty"` RecordID string `json:"record_id"` Reviewer string `json:"reviewer"` Reason string `json:"reason,omitempty"` } // TranslationMemorySummary mirrors translation.memory.summary data. type TranslationMemorySummary struct { SchemaVersion uint64 `json:"schema_version"` RecordCount uint64 `json:"record_count"` TrustedCount uint64 `json:"trusted_count"` CandidateCount uint64 `json:"candidate_count"` SupersededCount uint64 `json:"superseded_count"` RejectedCount uint64 `json:"rejected_count"` } // TranslationMemorySummaryReport distinguishes a missing database from an // available database with an empty summary. type TranslationMemorySummaryReport struct { Available bool `json:"available"` Path string `json:"path"` SchemaVersion *uint64 `json:"schema_version,omitempty"` Summary *TranslationMemorySummary `json:"summary,omitempty"` Reason string `json:"reason,omitempty"` } // TranslationMemorySourceTrace mirrors the Rust TextUnit/provider provenance. type TranslationMemorySourceTrace struct { OfficialReleaseID string `json:"official_release_id"` UnitID *string `json:"unit_id,omitempty"` TaskID *string `json:"task_id,omitempty"` Destination *string `json:"destination,omitempty"` ArchiveEntry *string `json:"archive_entry,omitempty"` SerializedFile *string `json:"serialized_file,omitempty"` PathID *int64 `json:"path_id,omitempty"` ClassID *int32 `json:"class_id,omitempty"` FieldPath *string `json:"field_path,omitempty"` Format *string `json:"format,omitempty"` AssetName *string `json:"asset_name,omitempty"` TextSourceKind *string `json:"text_source_kind,omitempty"` SourceURL *string `json:"source_url,omitempty"` } // TranslationMemoryEntry mirrors a persisted Rust TM record. type TranslationMemoryEntry struct { RecordID string `json:"record_id"` SourceText string `json:"source_text"` SourceHash string `json:"source_hash"` NormalizedSourceText string `json:"normalized_source_text"` SourceContext TranslationMemoryContext `json:"source_context,omitempty"` SourceContextHash string `json:"source_context_hash"` TranslatedText string `json:"translated_text"` TranslationSourceKind TranslationMemorySourceKind `json:"translation_source_kind"` TrustStatus TranslationMemoryTrustStatus `json:"trust_status"` OfficialReleaseID string `json:"official_release_id"` SourceTrace TranslationMemorySourceTrace `json:"source_trace"` Provider *string `json:"provider,omitempty"` ProviderRunID *string `json:"provider_run_id,omitempty"` CreatedUnixSeconds uint64 `json:"created_unix_seconds"` UpdatedUnixSeconds uint64 `json:"updated_unix_seconds"` TrustedUnixSeconds *uint64 `json:"trusted_unix_seconds,omitempty"` TrustedBy *string `json:"trusted_by,omitempty"` TrustedReason *string `json:"trusted_reason,omitempty"` SupersedesRecordID *string `json:"supersedes_record_id,omitempty"` SupersededByRecordID *string `json:"superseded_by_record_id,omitempty"` } // TranslationMemoryMatch is one Rust-selected match and its reuse decision. type TranslationMemoryMatch struct { Entry TranslationMemoryEntry `json:"entry"` MatchKind TranslationMemoryMatchKind `json:"match_kind"` CanAutoReuse bool `json:"can_auto_reuse"` } // TranslationMemoryQueryReport mirrors translation.memory.query data. type TranslationMemoryQueryReport struct { Available bool `json:"available"` Path string `json:"path"` SourceText string `json:"source_text"` SourceContext TranslationMemoryContext `json:"source_context,omitempty"` Matches []TranslationMemoryMatch `json:"matches"` Reason string `json:"reason,omitempty"` } // TranslationMemoryConfirmReport mirrors translation.memory.confirm data. type TranslationMemoryConfirmReport struct { Available bool `json:"available"` Path string `json:"path"` Entry TranslationMemoryEntry `json:"entry"` } // GlossaryReviewStatus is the Rust-owned term review state. type GlossaryReviewStatus string const ( GlossaryStatusDraft GlossaryReviewStatus = "draft" GlossaryStatusApproved GlossaryReviewStatus = "approved" GlossaryStatusDeprecated GlossaryReviewStatus = "deprecated" GlossaryStatusRejected GlossaryReviewStatus = "rejected" ) // GlossarySourceRecord identifies the source/provenance of a term. type GlossarySourceRecord struct { SourceKind string `json:"source_kind"` SourceRef *string `json:"source_ref,omitempty"` SourceAuthor *string `json:"source_author,omitempty"` SourceNote *string `json:"source_note,omitempty"` ObservedUnixSeconds uint64 `json:"observed_unix_seconds"` } // GlossaryTermSnapshot is the versioned definition shared by Rust and Go. type GlossaryTermSnapshot struct { SourceTerm string `json:"source_term"` Aliases []string `json:"aliases,omitempty"` RecommendedTranslation string `json:"recommended_translation"` AllowedTranslations []string `json:"allowed_translations,omitempty"` SourceLanguage *string `json:"source_language,omitempty"` TargetLanguage *string `json:"target_language,omitempty"` Category *string `json:"category,omitempty"` Priority int `json:"priority"` Scope map[string]string `json:"scope,omitempty"` } // GlossaryOverride records explicit human approval for a deviation. type GlossaryOverride struct { Reviewer string `json:"reviewer"` Reason string `json:"reason"` Provenance string `json:"provenance"` ConfirmedUnixSeconds uint64 `json:"confirmed_unix_seconds"` } // GlossaryTerm mirrors a persisted Rust term and its source history. type GlossaryTerm struct { TermID string `json:"term_id"` GlossaryTermSnapshot ReviewStatus GlossaryReviewStatus `json:"review_status"` Source GlossarySourceRecord `json:"source"` History []GlossaryHistoryRecord `json:"history,omitempty"` CreatedUnixSeconds uint64 `json:"created_unix_seconds"` UpdatedUnixSeconds uint64 `json:"updated_unix_seconds"` } // GlossaryHistoryRecord is one durable term mutation. type GlossaryHistoryRecord struct { HistoryID string `json:"history_id"` Action string `json:"action"` Reviewer *string `json:"reviewer,omitempty"` Reason *string `json:"reason,omitempty"` Source GlossarySourceRecord `json:"source"` ReviewStatus GlossaryReviewStatus `json:"review_status"` Snapshot GlossaryTermSnapshot `json:"snapshot"` ObservedUnixSeconds uint64 `json:"observed_unix_seconds"` } // GlossarySummary mirrors translation.glossary.summary. type GlossarySummary struct { SchemaVersion uint64 `json:"schema_version"` TermCount uint64 `json:"term_count"` ApprovedCount uint64 `json:"approved_count"` DraftCount uint64 `json:"draft_count"` DeprecatedCount uint64 `json:"deprecated_count"` RejectedCount uint64 `json:"rejected_count"` } type GlossarySummaryParams struct { GlossaryPath string `json:"glossary_path,omitempty"` } type GlossaryQueryParams struct { GlossaryPath string `json:"glossary_path,omitempty"` SourceText string `json:"source_text,omitempty"` Category string `json:"category,omitempty"` ReviewStatus string `json:"review_status,omitempty"` Limit *uint64 `json:"limit,omitempty"` } type GlossaryDiagnoseParams struct { GlossaryPath string `json:"glossary_path,omitempty"` SourceText string `json:"source_text"` Context map[string]string `json:"context,omitempty"` } type GlossaryTermMutationParams struct { GlossaryPath string `json:"glossary_path,omitempty"` TermID string `json:"term_id"` SourceTerm string `json:"source_term"` Aliases []string `json:"aliases,omitempty"` RecommendedTranslation string `json:"recommended_translation"` AllowedTranslations []string `json:"allowed_translations,omitempty"` SourceLanguage *string `json:"source_language,omitempty"` TargetLanguage *string `json:"target_language,omitempty"` Category *string `json:"category,omitempty"` Priority int `json:"priority"` Scope map[string]string `json:"scope,omitempty"` ReviewStatus string `json:"review_status"` Source GlossarySourceRecord `json:"source"` Reviewer string `json:"reviewer,omitempty"` Reason string `json:"reason,omitempty"` } type GlossaryReviewParams struct { GlossaryPath string `json:"glossary_path,omitempty"` TermID string `json:"term_id"` Reviewer string `json:"reviewer"` Reason string `json:"reason,omitempty"` } type GlossarySummaryReport struct { Available bool `json:"available"` Path string `json:"path"` SchemaVersion *uint64 `json:"schema_version,omitempty"` Summary *GlossarySummary `json:"summary,omitempty"` Reason string `json:"reason,omitempty"` } type GlossaryQueryReport struct { Available bool `json:"available"` Path string `json:"path"` SourceText string `json:"source_text"` Terms []GlossaryTerm `json:"terms"` Reason string `json:"reason,omitempty"` } type GlossaryMutationReport struct { Available bool `json:"available"` Path string `json:"path"` SchemaVersion *uint64 `json:"schema_version,omitempty"` Term GlossaryTerm `json:"term"` } type GlossaryDiagnoseReport struct { Available bool `json:"available"` Path string `json:"path"` SourceText string `json:"source_text"` Context map[string]string `json:"context,omitempty"` Evaluation json.RawMessage `json:"evaluation"` Reason string `json:"reason,omitempty"` } // LocalizedPublishParams selects the source of one localized release // publication. TranslationFile and FromWorker are mutually exclusive. type LocalizedPublishParams struct { TranslationFile string `json:"translation_file,omitempty"` FromWorker bool `json:"from_worker,omitempty"` LocalizedReleaseID string `json:"localized_release_id,omitempty"` Force bool `json:"force,omitempty"` } // LocalizedRollbackParams optionally restricts rollback to one current release. type LocalizedRollbackParams struct { LocalizedReleaseID string `json:"localized_release_id,omitempty"` } // TranslationProofread marks the current localized workflow as manual // proofreading. Rust owns the persisted localized state. func (c *Client) TranslationProofread(ctx context.Context) (json.RawMessage, error) { return c.rawData(ctx, "translation.proofread", nil) } // Ack is returned by accepted daemon control methods. type Ack struct { Command string `json:"command"` Status string `json:"status"` Message string `json:"message"` StateDir string `json:"state_dir"` SocketPath string `json:"socket_path"` ControllerPID *int `json:"controller_pid,omitempty"` Force *bool `json:"force,omitempty"` } // TaskAccepted is returned when an async backend task is queued. type TaskAccepted struct { TaskID string `json:"task_id"` Kind string `json:"kind"` } // TaskRecord is the pollable task state. type TaskRecord struct { ID string `json:"id"` Kind string `json:"kind"` Status string `json:"status"` Stage *string `json:"stage,omitempty"` Message *string `json:"message,omitempty"` CreatedAt uint64 `json:"created_at"` UpdatedAt uint64 `json:"updated_at"` StartedAt *uint64 `json:"started_at,omitempty"` FinishedAt *uint64 `json:"finished_at,omitempty"` Error *APIError `json:"error,omitempty"` Result json.RawMessage `json:"result,omitempty"` } type TaskList struct { Tasks []TaskRecord `json:"tasks"` } type TaskCancelResult struct { TaskID string `json:"task_id"` CancelRequested bool `json:"cancel_requested"` Note string `json:"note,omitempty"` } type TaskLogs struct { TaskID string `json:"task_id"` Lines []string `json:"lines"` } type DoctorCheck struct { Name string `json:"name"` OK bool `json:"ok"` Message string `json:"message"` } type DoctorReport struct { Command string `json:"command"` Status string `json:"status"` Message string `json:"message"` Healthy bool `json:"healthy"` Checks []DoctorCheck `json:"checks"` } type LogsReport struct { Command string `json:"command"` Status string `json:"status"` Message string `json:"message"` LogPath string `json:"log_path"` Exists bool `json:"exists"` Empty bool `json:"empty"` Bytes int `json:"bytes"` TotalLines int `json:"total_lines"` ReturnedLines int `json:"returned_lines"` Content string `json:"content"` } type DaemonStatusReport struct { Status string `json:"status"` StatusCode *string `json:"status_code,omitempty"` Message string `json:"message"` Running bool `json:"running"` PID *int `json:"pid,omitempty"` ResourceOutputRoot *string `json:"resource_output_root,omitempty"` StateDir string `json:"state_dir"` SocketPath string `json:"socket_path"` RPCAvailable bool `json:"rpc_available"` CurrentStage *string `json:"current_stage,omitempty"` CurrentMessage *string `json:"current_message,omitempty"` } type ResourceState struct { Status string `json:"status,omitempty"` StatusCode string `json:"status_code,omitempty"` StatusPhase string `json:"status_phase,omitempty"` StatusTerminal bool `json:"status_terminal,omitempty"` StatusRetryable bool `json:"status_retryable,omitempty"` ResourceOutputRoot *string `json:"resource_output_root,omitempty"` VersionState json.RawMessage `json:"version_state,omitempty"` LastUpdateStatus *string `json:"last_update_status,omitempty"` LastSuccessUnixSeconds *uint64 `json:"last_success_unix_seconds,omitempty"` } type ResourceManifestEntry struct { URL string `json:"url"` Destination string `json:"destination"` Bytes *uint64 `json:"bytes,omitempty"` BLAKE3 string `json:"blake3,omitempty"` } type ResourceManifestPage struct { Available bool `json:"available"` ResourceRoot string `json:"resource_root,omitempty"` ManifestVersion int `json:"manifest_version,omitempty"` TotalEntries int `json:"total_entries,omitempty"` Offset int `json:"offset,omitempty"` Limit int `json:"limit,omitempty"` Entries []ResourceManifestEntry `json:"entries,omitempty"` } func (c *Client) DaemonStatus(ctx context.Context) (*DaemonStatusReport, error) { var out DaemonStatusReport _, err := c.Call(ctx, "daemon.status", nil, &out) return &out, err } func (c *Client) DaemonLogs(ctx context.Context, tail int) (*LogsReport, error) { var out LogsReport _, err := c.Call(ctx, "daemon.logs", tailParam{Tail: tail}, &out) return &out, err } func (c *Client) DaemonStop(ctx context.Context) (*Ack, error) { var out Ack _, err := c.Call(ctx, "daemon.stop", nil, &out) return &out, err } func (c *Client) DaemonRestart(ctx context.Context) (*Ack, error) { var out Ack _, err := c.Call(ctx, "daemon.restart", nil, &out) return &out, err } func (c *Client) DaemonReload(ctx context.Context) (*Ack, error) { var out Ack _, err := c.Call(ctx, "daemon.reload", nil, &out) return &out, err } func (c *Client) DaemonRefresh(ctx context.Context, force bool) (*Ack, error) { var out Ack _, err := c.Call(ctx, "daemon.refresh", boolParam{Force: force}, &out) return &out, err } func (c *Client) DaemonDoctor(ctx context.Context) (*DoctorReport, error) { var out DoctorReport _, err := c.Call(ctx, "daemon.doctor", nil, &out) return &out, err } func (c *Client) ResourceState(ctx context.Context) (*ResourceState, error) { var out ResourceState _, err := c.Call(ctx, "resource.state", nil, &out) return &out, err } func (c *Client) ResourceSync(ctx context.Context, force bool) (*TaskAccepted, error) { var out TaskAccepted _, err := c.Call(ctx, "resource.sync", boolParam{Force: force}, &out) return &out, err } func (c *Client) ResourceVerify(ctx context.Context) (*TaskAccepted, error) { var out TaskAccepted _, err := c.Call(ctx, "resource.verify", nil, &out) return &out, err } func (c *Client) ResourceRepair(ctx context.Context) (*TaskAccepted, error) { var out TaskAccepted _, err := c.Call(ctx, "resource.repair", nil, &out) return &out, err } func (c *Client) ResourceManifest(ctx context.Context, offset int, limit int) (*ResourceManifestPage, error) { var out ResourceManifestPage _, err := c.Call(ctx, "resource.manifest", pageParam{Offset: offset, Limit: limit}, &out) return &out, err } func (c *Client) ResourceList(ctx context.Context, offset int, limit int) (*ResourceManifestPage, error) { var out ResourceManifestPage _, err := c.Call(ctx, "resource.list", pageParam{Offset: offset, Limit: limit}, &out) return &out, err } func (c *Client) ScheduleList(ctx context.Context) (json.RawMessage, error) { return c.rawData(ctx, "schedule.list", nil) } func (c *Client) ScheduleListFiltered(ctx context.Context, params ScheduleListParams) (json.RawMessage, error) { return c.rawData(ctx, "schedule.list", params) } func (c *Client) ScheduleAdd(ctx context.Context, params ScheduleMutationParams) (json.RawMessage, error) { return c.rawData(ctx, "schedule.add", params) } func (c *Client) ScheduleUpdate(ctx context.Context, params ScheduleMutationParams) (json.RawMessage, error) { return c.rawData(ctx, "schedule.update", params) } func (c *Client) ScheduleRemove(ctx context.Context, params ScheduleMutationParams) (json.RawMessage, error) { return c.rawData(ctx, "schedule.remove", params) } func (c *Client) ScheduleRun(ctx context.Context, params ScheduleRunParams) (json.RawMessage, error) { return c.rawData(ctx, "schedule.run", params) } func (c *Client) TranslationTaskUpdate(ctx context.Context, params TranslationTaskUpdateParams) (json.RawMessage, error) { return c.rawData(ctx, "translation.task.update", params) } func (c *Client) TranslationTasks(ctx context.Context, params TranslationTaskListParams) (json.RawMessage, error) { return c.rawData(ctx, "translation.tasks", params) } func (c *Client) TranslationHandoff(ctx context.Context) (json.RawMessage, error) { return c.rawData(ctx, "translation.handoff", nil) } func (c *Client) TranslationWorkerRun(ctx context.Context, params TranslationWorkerRunParams) (*TranslationWorkerRunResult, error) { var out TranslationWorkerRunResult _, err := c.Call(ctx, "translation.worker.run", params, &out) return &out, err } func (c *Client) TranslationMemorySummary(ctx context.Context, params TranslationMemorySummaryParams) (*TranslationMemorySummaryReport, error) { var out TranslationMemorySummaryReport _, err := c.Call(ctx, "translation.memory.summary", params, &out) return &out, err } func (c *Client) TranslationMemoryQuery(ctx context.Context, params TranslationMemoryQueryParams) (*TranslationMemoryQueryReport, error) { var out TranslationMemoryQueryReport _, err := c.Call(ctx, "translation.memory.query", params, &out) return &out, err } func (c *Client) TranslationMemoryConfirm(ctx context.Context, params TranslationMemoryConfirmParams) (*TranslationMemoryConfirmReport, error) { var out TranslationMemoryConfirmReport _, err := c.Call(ctx, "translation.memory.confirm", params, &out) return &out, err } func (c *Client) GlossarySummary(ctx context.Context, params GlossarySummaryParams) (*GlossarySummaryReport, error) { var out GlossarySummaryReport _, err := c.Call(ctx, "translation.glossary.summary", params, &out) return &out, err } func (c *Client) GlossaryQuery(ctx context.Context, params GlossaryQueryParams) (*GlossaryQueryReport, error) { var out GlossaryQueryReport _, err := c.Call(ctx, "translation.glossary.query", params, &out) return &out, err } func (c *Client) GlossaryDiagnose(ctx context.Context, params GlossaryDiagnoseParams) (*GlossaryDiagnoseReport, error) { var out GlossaryDiagnoseReport _, err := c.Call(ctx, "translation.glossary.diagnose", params, &out) return &out, err } func (c *Client) GlossaryAdd(ctx context.Context, params GlossaryTermMutationParams) (*GlossaryMutationReport, error) { var out GlossaryMutationReport _, err := c.Call(ctx, "translation.glossary.add", params, &out) return &out, err } func (c *Client) GlossaryUpdate(ctx context.Context, params GlossaryTermMutationParams) (*GlossaryMutationReport, error) { var out GlossaryMutationReport _, err := c.Call(ctx, "translation.glossary.update", params, &out) return &out, err } func (c *Client) GlossaryApprove(ctx context.Context, params GlossaryReviewParams) (*GlossaryMutationReport, error) { var out GlossaryMutationReport _, err := c.Call(ctx, "translation.glossary.approve", params, &out) return &out, err } func (c *Client) GlossaryDeprecate(ctx context.Context, params GlossaryReviewParams) (*GlossaryMutationReport, error) { var out GlossaryMutationReport _, err := c.Call(ctx, "translation.glossary.deprecate", params, &out) return &out, err } func (c *Client) LocalizedPublish(ctx context.Context, params LocalizedPublishParams) (json.RawMessage, error) { return c.rawData(ctx, "localized.publish", params) } func (c *Client) LocalizedRollback(ctx context.Context, params LocalizedRollbackParams) (json.RawMessage, error) { return c.rawData(ctx, "localized.rollback", params) } func (c *Client) CatalogStatus(ctx context.Context) (json.RawMessage, error) { return c.rawData(ctx, "catalog.status", nil) } func (c *Client) CatalogVersions(ctx context.Context) (json.RawMessage, error) { return c.rawData(ctx, "catalog.versions", nil) } func (c *Client) CatalogDiff(ctx context.Context) (json.RawMessage, error) { return c.rawData(ctx, "catalog.diff", nil) } func (c *Client) CatalogRefresh(ctx context.Context, force bool) (*TaskAccepted, error) { var out TaskAccepted _, err := c.Call(ctx, "catalog.refresh", boolParam{Force: force}, &out) return &out, err } func (c *Client) ParseStatus(ctx context.Context) (json.RawMessage, error) { return c.rawData(ctx, "parse.status", nil) } func (c *Client) ParseTextUnits(ctx context.Context, query TextUnitQueryParams) (json.RawMessage, error) { return c.rawData(ctx, "parse.text_units", query) } func (c *Client) ParseErrors(ctx context.Context, query TextUnitQueryParams) (json.RawMessage, error) { return c.rawData(ctx, "parse.errors", query) } func (c *Client) LocalizedStatus(ctx context.Context) (json.RawMessage, error) { return c.rawData(ctx, "localized.status", nil) } func (c *Client) UnityFSPatchTextAsset(ctx context.Context, params UnityFSTextAssetPatchParams) (json.RawMessage, error) { return c.rawData(ctx, "unityfs.patch_text_asset", params) } func (c *Client) UnityFSPatchStringField(ctx context.Context, params UnityFSStringFieldPatchParams) (json.RawMessage, error) { return c.rawData(ctx, "unityfs.patch_string_field", params) } func (c *Client) UnityFSPatchField(ctx context.Context, params UnityFSFieldPatchParams) (json.RawMessage, error) { return c.rawData(ctx, "unityfs.patch_field", params) } func (c *Client) TaskStatus(ctx context.Context, taskID string) (*TaskRecord, error) { var out TaskRecord _, err := c.Call(ctx, "task.status", taskIDParam{TaskID: taskID}, &out) return &out, err } func (c *Client) TaskList(ctx context.Context) (*TaskList, error) { var out TaskList _, err := c.Call(ctx, "task.list", nil, &out) return &out, err } func (c *Client) TaskCancel(ctx context.Context, taskID string) (*TaskCancelResult, error) { var out TaskCancelResult _, err := c.Call(ctx, "task.cancel", taskIDParam{TaskID: taskID}, &out) return &out, err } func (c *Client) TaskLogs(ctx context.Context, taskID string) (*TaskLogs, error) { var out TaskLogs _, err := c.Call(ctx, "task.logs", taskIDParam{TaskID: taskID}, &out) return &out, err } func (c *Client) rawData(ctx context.Context, method string, params any) (json.RawMessage, error) { envelope, err := c.Call(ctx, method, params, nil) if err != nil { return nil, err } return envelope.Data, nil }