Documentation
¶
Overview ¶
Package entity is the canonical home for clicky's entity + operation model: the entity registry and CLI generation (Entity, EntityBuilder, RegisterEntity, GenerateCLI), the command-function registries (AddCommand, the cobra annotation metadata), the RPC operation model (RPCOperation, Schema, …), and named, reusable filter/lookup definitions that work across both static (Go-struct) and dynamic (JSON-Schema) entities.
A filter is defined once — in Go via RegisterFilter, or declaratively via RegisterFilterSpec — and reused by name from any number of entities. The core abstraction (FilterSource + FilterContext) never sees a typed ListOpts, so the same definition serves a compile-time Go entity and a schema-driven dynamic entity identically.
On a static entity, attach a named filter with the typed adapter:
clicky.NewEntity[Task, TaskOpts, Task]("tasks").
Filters(entity.Use[TaskOpts]("users").As("owner")).
List(listTasks).
Register()
The dependency runs one way: this package depends only on clicky subpackages (api, flags, formatters, task) plus cobra/pflag — never on the root clicky package. The root clicky package imports this one and re-exports the model via type aliases and thin wrappers (see entity_aliases.go), so callers keep using clicky.NewEntity, clicky.Entity, clicky.RegisterEntity, etc. unchanged. Host-owned globals (the CLI format flags, HTTPie argument parsing) are injected through the RenderResult / ParseArgs hooks in render.go.
Index ¶
- Constants
- Variables
- func AddCommand[T any, R any](parent *cobra.Command, opts T, fn func(opts T) (R, error)) *cobra.Command
- func AddCommandWithContext[T any, R any](parent *cobra.Command, opts T, fn func(ctx context.Context, opts T) (R, error)) *cobra.Command
- func AddNamedCommand[T any, R any](name string, parent *cobra.Command, opts T, fn func(opts T) (R, error)) *cobra.Command
- func AddNamedCommandWithContext[T any, R any](name string, parent *cobra.Command, opts T, ...) *cobra.Command
- func GenerateCLI(parent *cobra.Command)
- func GetDataFunc(cmd *cobra.Command) func(flags map[string]string, args []string) (any, error)
- func GetLookupFunc(cmd *cobra.Command) func(flags map[string]string, args []string) (any, error)
- func RegisterDynamicEntity(spec DynamicEntitySpec)
- func RegisterEntity[T EntityItem, ListOpts any, R any](e Entity[T, ListOpts, R])
- func RegisterFilter(f NamedFilter)
- func RegisterFilterSpec(s FilterSpec)
- func RegisterSubCommand(parentName string, cmd *cobra.Command)
- func RegisterSubCommandFn(parentName string, build func(parent *cobra.Command))
- func SetCommandResponseMeta(cmd *cobra.Command, meta ResponseOpenAPIMeta)
- func Use[ListOpts any](filterName string) *attachedFilter[ListOpts]
- type ActionFlags
- type ActionInfo
- type ActionSpec
- func Action[R any](name string, fn func(id string, flags map[string]string) (R, error)) *ActionSpec[R]
- func ActionWithContext[R any](name string, ...) *ActionSpec[R]
- func ActionWithFlags[R any](name string, flags ActionFlags, ...) *ActionSpec[R]
- func ActionWithFlagsAndContext[R any](name string, flags ActionFlags, ...) *ActionSpec[R]
- func (a *ActionSpec[R]) WithFlags(flags ActionFlags) *ActionSpec[R]
- func (a *ActionSpec[R]) WithMethod(method string) *ActionSpec[R]
- func (a *ActionSpec[R]) WithOptionalID() *ActionSpec[R]
- func (a *ActionSpec[R]) WithShort(short string) *ActionSpec[R]
- func (a *ActionSpec[R]) WithToolGroup(group string) *ActionSpec[R]
- type BulkActionInfo
- type BulkActionSpec
- func BulkAction[R any](name string, fn func(ids []string, flags map[string]string) (R, error)) *BulkActionSpec[R]
- func BulkActionWithFilter[ListOpts any, R any](name string, run func(ids []string, flags map[string]string) (R, error), ...) *BulkActionSpec[R]
- func BulkFilterAction[ListOpts any, R any](name string, fn func(opts ListOpts, flags map[string]string) (R, error)) *BulkActionSpec[R]
- type ClickyOperationMeta
- type ClickySpecMeta
- type ClickySurface
- type CommandOpenAPIMeta
- type Config
- type ContextDataFunc
- type ContextFilter
- type ContextLookupFunc
- type ContextSearchableFilter
- type DataFunc
- type DynamicEntityBuilder
- type DynamicEntitySpec
- type DynamicFilter
- type DynamicGetFunc
- type DynamicListFunc
- type Entity
- type EntityAction
- type EntityBuilder
- func (b *EntityBuilder[T, ListOpts, R]) Admin(admin Entity[T, ListOpts, R]) *EntityBuilder[T, ListOpts, R]
- func (b *EntityBuilder[T, ListOpts, R]) Aliases(aliases ...string) *EntityBuilder[T, ListOpts, R]
- func (b *EntityBuilder[T, ListOpts, R]) Build() Entity[T, ListOpts, R]
- func (b *EntityBuilder[T, ListOpts, R]) Create(fn func(map[string]any) (R, error)) *EntityBuilder[T, ListOpts, R]
- func (b *EntityBuilder[T, ListOpts, R]) CreateWithContext(fn func(context.Context, map[string]any) (R, error)) *EntityBuilder[T, ListOpts, R]
- func (b *EntityBuilder[T, ListOpts, R]) Delete(fn func(string) error) *EntityBuilder[T, ListOpts, R]
- func (b *EntityBuilder[T, ListOpts, R]) DeleteWithContext(fn func(context.Context, string) error) *EntityBuilder[T, ListOpts, R]
- func (b *EntityBuilder[T, ListOpts, R]) Filters(filters ...Filter[ListOpts]) *EntityBuilder[T, ListOpts, R]
- func (b *EntityBuilder[T, ListOpts, R]) Get(fn func(string) (R, error)) *EntityBuilder[T, ListOpts, R]
- func (b *EntityBuilder[T, ListOpts, R]) GetWithContext(fn func(context.Context, string) (R, error)) *EntityBuilder[T, ListOpts, R]
- func (b *EntityBuilder[T, ListOpts, R]) GetWithFlags(flags ActionFlags, fn func(string, map[string]string) (R, error)) *EntityBuilder[T, ListOpts, R]
- func (b *EntityBuilder[T, ListOpts, R]) List(fn func(ListOpts) ([]T, error)) *EntityBuilder[T, ListOpts, R]
- func (b *EntityBuilder[T, ListOpts, R]) ListPaged(fn func(ListOpts) (PagedResult[T], error)) *EntityBuilder[T, ListOpts, R]
- func (b *EntityBuilder[T, ListOpts, R]) ListPagedWithContext(fn func(context.Context, ListOpts) (PagedResult[T], error)) *EntityBuilder[T, ListOpts, R]
- func (b *EntityBuilder[T, ListOpts, R]) ListWithContext(fn func(context.Context, ListOpts) ([]T, error)) *EntityBuilder[T, ListOpts, R]
- func (b *EntityBuilder[T, ListOpts, R]) Parent(parent string) *EntityBuilder[T, ListOpts, R]
- func (b *EntityBuilder[T, ListOpts, R]) Register()
- func (b *EntityBuilder[T, ListOpts, R]) ToolGroup(group string) *EntityBuilder[T, ListOpts, R]
- func (b *EntityBuilder[T, ListOpts, R]) Update(fn func(string, map[string]any) (R, error)) *EntityBuilder[T, ListOpts, R]
- func (b *EntityBuilder[T, ListOpts, R]) UpdateWithContext(fn func(context.Context, string, map[string]any) (R, error)) *EntityBuilder[T, ListOpts, R]
- func (b *EntityBuilder[T, ListOpts, R]) ValidArgs(fn func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective)) *EntityBuilder[T, ListOpts, R]
- func (b *EntityBuilder[T, ListOpts, R]) WithAction(action EntityAction) *EntityBuilder[T, ListOpts, R]
- func (b *EntityBuilder[T, ListOpts, R]) WithBulkAction(action EntityBulkAction) *EntityBuilder[T, ListOpts, R]
- type EntityBulkAction
- type EntityInfo
- type EntityItem
- type EntityOperation
- type ExecutableCommand
- type ExecuteOptions
- type Filter
- type FilterContext
- type FilterSource
- type FilterSourceSpec
- type FilterSpec
- type Filterable
- type Help
- type MultiFilter
- type Name
- type NamedFilter
- type PageInfo
- type Paged
- type PagedResult
- type Property
- type RPCOperation
- type RPCParameter
- type RPCService
- type ResponseOpenAPIMeta
- type Schema
- type SearchableFilter
- type TypedFilter
Constants ¶
const ( SourceStatic = "static" SourceEntity = "entity" SourceFunc = "func" // Go-only; not constructible from a spec. SourceCustom = "custom" )
Source kinds for the declarative FilterSourceSpec.
Variables ¶
var ParseArgs = func(args []string) (map[string]any, error) { return nil, fmt.Errorf("entity.ParseArgs not configured: the root clicky package must wire it") }
ParseArgs parses HTTPie-style positional arguments (key=value, key:=json, …) into a body map for create/update commands. Root clicky wires it in init() to its ParseArgumentsAsMap; the default fails loudly so a missing wiring surfaces rather than silently dropping arguments.
var RenderResult = func(o any) error { return nil }
RenderResult renders a command result through the host application's format pipeline — the global --format/--output flags and any configured sinks. Root clicky wires it in init() (to ParseFormatSpec + PrintAndWriteSinks against its global Flags); the default no-op lets the entity package's own unit tests run without a renderer.
It is a package-level hook rather than a direct dependency so the entity package stays free of the root clicky package (which owns the global flag state) — preserving the one-way entity → clicky-subpackages dependency.
Functions ¶
func AddCommand ¶
func AddCommand[T any, R any](parent *cobra.Command, opts T, fn func(opts T) (R, error)) *cobra.Command
AddCommand creates a Cobra command with automatic flag parsing from struct tags, execution, and result formatting.
Type parameter T must be a struct with tags defining flags:
- flag:"name" - flag name (required)
- help:"description" - flag help text
- default:"value" - default value
- short:"x" - short flag variant
- required:"true" - mark flag as required
- stdin:"true" - mark field as default for stdin input (only one field)
Supports @ prefix for file/URL loading:
- @file.txt - read from file
- @https://... - fetch from URL
- For slices: one value per line (skip empty lines and # comments)
- For slices: @file.csv:ColumnName reads a named column from a CSV (first row is the header, empty cells are skipped)
- For slices: @file.xlsx:ColumnName / @file.xls:ColumnName reads a named column from the first worksheet (case-insensitive header match)
Supported types:
- string, int, bool
- duration.Duration (supports "30d", "2w", etc.)
- time.Time (supports datamath like "now-7d", "now/d", "now-1M/M")
- []string, []int (slices)
Datamath expressions for time.Time fields (Elasticsearch compatible):
- now : current time
- now-7d : 7 days ago
- now+2h : 2 hours from now
- now/d : start of current day
- now-7d/d : start of day 7 days ago
- now/w : start of this week
- now-1M/M : start of last month
- now/y : start of this year
- Units: y (year), M (month), w (week), d (day), h (hour), m (minute), s (second)
Example:
type ListOptions struct {
Role string `flag:"role" help:"Filter by role" short:"r"`
Limit int `flag:"limit" help:"Max results" default:"50"`
Since time.Time `flag:"since" help:"Created since" default:"now-30d"`
Tags []string `flag:"tags" help:"Filter tags" stdin:"true"`
MaxAge duration.Duration `flag:"max-age" help:"Max age" default:"365d"`
}
cmd := &cobra.Command{Use: "list", Short: "List users"}
clicky.AddCommand(cmd, ListOptions{}, func(opts ListOptions) (any, error) {
return fetchUsers(opts)
})
Usage examples:
myapp list --tags @tags.txt # load from file myapp list --since now-30d # datamath echo -e "tag1\ntag2" | myapp list # stdin myapp list --max-age 60d --json # with formatting
func AddCommandWithContext ¶
func AddCommandWithContext[T any, R any](parent *cobra.Command, opts T, fn func(ctx context.Context, opts T) (R, error)) *cobra.Command
AddCommandWithContext is AddCommand whose closure receives the request-scoped context (cmd.Context() on the CLI, r.Context() over HTTP). It derives the command name from the opts struct exactly like AddCommand, then delegates to AddNamedCommandWithContext so the subcommand can resolve a per-request database/config instead of a process global.
func AddNamedCommand ¶
func AddNamedCommandWithContext ¶
func AddNamedCommandWithContext[T any, R any](name string, parent *cobra.Command, opts T, fn func(ctx context.Context, opts T) (R, error)) *cobra.Command
AddNamedCommandWithContext is AddNamedCommand whose closure receives the request-scoped context (cmd.Context() on the CLI, r.Context() over HTTP), so the subcommand can resolve a per-request database/config instead of a process global. Same flag/arg binding and rendering as AddNamedCommand.
func GenerateCLI ¶
GenerateCLI creates cobra subcommands for all registered entities under parent. Admin entities are nested under a shared "admin" parent command. Entities with a Parent set are nested under a shared parent cobra command, created lazily if it does not already exist.
func GetDataFunc ¶
GetDataFunc returns the direct data function registered for a command, if any. Used by the RPC converter to wire DataFunc on RPCOperation.
func GetLookupFunc ¶
GetLookupFunc returns the direct lookup function registered for a command, if any.
func RegisterDynamicEntity ¶
func RegisterDynamicEntity(spec DynamicEntitySpec)
RegisterDynamicEntity registers a schema-driven entity assembled at runtime (no compile-time Go struct). It is the single root entrypoint the entity package's dynamic builder targets; everything downstream — GenerateCLI, RPC, OpenAPI, the lookup endpoint — consumes it through the normal entity registry.
func RegisterEntity ¶
func RegisterEntity[T EntityItem, ListOpts any, R any](e Entity[T, ListOpts, R])
RegisterEntity registers a CRUD entity. Call during init(). CLI commands and HTTP routes are generated later via GenerateCLI/GenerateRoutes.
See the github.com/flanksource/clicky/entity package for the authoring guide and the best practices for operations that work well across CLI and HTTP.
func RegisterFilter ¶
func RegisterFilter(f NamedFilter)
RegisterFilter registers a named filter for reuse across entities. It panics on a duplicate name or an incomplete definition — registration happens at init/setup time, so a collision is a programming error that must fail loudly.
func RegisterFilterSpec ¶
func RegisterFilterSpec(s FilterSpec)
RegisterFilterSpec registers a declaratively-defined named filter. Like RegisterFilter it is a setup-time call and panics on an invalid spec.
func RegisterSubCommand ¶
RegisterSubCommand defers attaching cmd as a child of a parent cobra command identified by parentName. The attachment is performed by GenerateCLI after all entity parents have been created. If no command at parentName exists after entity generation, a thin parent command is created to host cmd.
parentName may be a bare command name ("policy") or a slash-delimited path ("billing/policy"). A path is resolved one segment at a time beneath root; missing intermediates are created as thin grouping commands, and existing nodes (including entity-generated parents) are reused.
Use this for non-entity cobra commands that should live under an entity-generated parent (or under an arbitrary grouping command).
func RegisterSubCommandFn ¶
RegisterSubCommandFn defers running build against a parent cobra command identified by parentName. Use this when the subcommand needs to be constructed lazily — e.g. AddNamedCommand which both builds and attaches in one call.
parentName accepts the same bare-name-or-slash-path form as RegisterSubCommand.
Example:
clicky.RegisterSubCommandFn("correspondence", func(parent *cobra.Command) {
clicky.AddNamedCommand("validate", parent, ValidateOptions{}, runValidate)
})
func SetCommandResponseMeta ¶
func SetCommandResponseMeta(cmd *cobra.Command, meta ResponseOpenAPIMeta)
SetCommandResponseMeta attaches static response metadata to a command.
func Use ¶
Use attaches a registered named filter to a typed (static) entity. The returned value implements clicky.Filter[ListOpts] (plus the searchable/context/typed extensions) so it drops straight into Entity.Filters. By default it binds to the flag/field named after the filter; override with As.
Filters(entity.Use[TaskOpts]("users").As("owner"))
Use resolves the filter eagerly and panics if the name is unregistered, so a wiring mistake fails at setup rather than at request time.
Types ¶
type ActionFlags ¶
type ActionFlags interface {
ClickyActionFlags()
}
ActionFlags is a marker interface implemented by options structs that declare typed cobra flags for a clicky Action. When an Action's Flags field is non-nil, the concrete type of the value is reflected for its `flag:"..."` struct tags and those flags are bound to the generated action cobra command.
Implementers attach a no-op `ClickyActionFlags()` method to an options struct, then pass a zero value of that struct in `Action.Flags`.
type ActionInfo ¶
type ActionInfo struct {
Name string
Short string
Method string
DataFunc func(flags map[string]string, args []string) (any, error)
// ContextDataFunc, when set, is preferred over DataFunc by both the CLI run
// path (fed cmd.Context()) and the RPC executor (fed r.Context()), mirroring
// the entity CRUD seam. Lets an action resolve request-scoped state instead
// of process globals.
ContextDataFunc ContextDataFunc
// FlagsType, if non-nil, is the struct type whose `flag:"..."` tagged
// fields are registered as cobra flags on the generated action command
// and populated into the flag map passed to DataFunc.
FlagsType reflect.Type
ResponseType reflect.Type
// OptionalID, when true, makes the positional <id> argument optional on
// the generated action command — the action is invokable with no
// argument (and the `id` passed to the run func is empty). Use for
// actions whose target is supplied entirely through flags.
OptionalID bool
// ToolGroup overrides the entity's tool group for this action only. Empty
// means the action inherits the entity's group.
ToolGroup string
}
ActionInfo is the type-erased representation of a single-entity action.
type ActionSpec ¶
type ActionSpec[R any] struct { // contains filtered or unexported fields }
func Action ¶
func Action[R any](name string, fn func(id string, flags map[string]string) (R, error)) *ActionSpec[R]
Action creates a typed custom operation on a single entity by ID.
func ActionWithContext ¶
func ActionWithContext[R any](name string, fn func(ctx context.Context, id string, flags map[string]string) (R, error)) *ActionSpec[R]
ActionWithContext creates a typed action whose run closure receives the request-scoped context (cmd.Context() on the CLI, r.Context() over HTTP), so it can resolve a per-request database/config instead of a process global.
func ActionWithFlags ¶
func ActionWithFlags[R any](name string, flags ActionFlags, fn func(id string, flags map[string]string) (R, error)) *ActionSpec[R]
ActionWithFlags creates a typed custom operation with typed action flags.
func ActionWithFlagsAndContext ¶
func ActionWithFlagsAndContext[R any](name string, flags ActionFlags, fn func(ctx context.Context, id string, flags map[string]string) (R, error)) *ActionSpec[R]
ActionWithFlagsAndContext is ActionWithContext with typed action flags.
func (*ActionSpec[R]) WithFlags ¶
func (a *ActionSpec[R]) WithFlags(flags ActionFlags) *ActionSpec[R]
func (*ActionSpec[R]) WithMethod ¶
func (a *ActionSpec[R]) WithMethod(method string) *ActionSpec[R]
WithMethod overrides the inferred HTTP method for the generated RPC/OpenAPI action route. Leave empty to keep the default inference behavior.
func (*ActionSpec[R]) WithOptionalID ¶
func (a *ActionSpec[R]) WithOptionalID() *ActionSpec[R]
WithOptionalID makes the positional <id> argument optional on the generated action command. Use for actions whose target is supplied entirely through flags; the `id` passed to the run func is then empty.
func (*ActionSpec[R]) WithShort ¶
func (a *ActionSpec[R]) WithShort(short string) *ActionSpec[R]
func (*ActionSpec[R]) WithToolGroup ¶
func (a *ActionSpec[R]) WithToolGroup(group string) *ActionSpec[R]
WithToolGroup overrides the entity's tool group for this action only. Empty (the default) means the action inherits the entity's group.
type BulkActionInfo ¶
type BulkActionInfo struct {
Name string
Short string
DataFunc func(flags map[string]string, args []string) (any, error)
FilterFunc func(flags map[string]string, args []string) (any, error)
LookupFunc func(flags map[string]string, args []string) (any, error)
ContextLookupFunc ContextLookupFunc
ListType reflect.Type
BindCompletions func(cmd *cobra.Command)
ResponseType reflect.Type
}
BulkActionInfo is the type-erased representation of a bulk action.
type BulkActionSpec ¶
type BulkActionSpec[R any] struct { // contains filtered or unexported fields }
func BulkAction ¶
func BulkAction[R any](name string, fn func(ids []string, flags map[string]string) (R, error)) *BulkActionSpec[R]
BulkAction creates a typed custom operation on multiple entity IDs.
func BulkActionWithFilter ¶
func BulkActionWithFilter[ListOpts any, R any]( name string, run func(ids []string, flags map[string]string) (R, error), runFilter func(opts ListOpts, flags map[string]string) (R, error), ) *BulkActionSpec[R]
BulkActionWithFilter creates a typed bulk action that supports both explicit IDs and filtered selections.
func BulkFilterAction ¶
func BulkFilterAction[ListOpts any, R any](name string, fn func(opts ListOpts, flags map[string]string) (R, error)) *BulkActionSpec[R]
BulkFilterAction creates a typed custom operation that runs against a typed filtered list selection instead of explicit IDs.
func (*BulkActionSpec[R]) WithShort ¶
func (b *BulkActionSpec[R]) WithShort(short string) *BulkActionSpec[R]
type ClickyOperationMeta ¶
type ClickyOperationMeta struct {
SurfaceID string `json:"-"`
Command string `json:"command,omitempty"`
Surface string `json:"surface,omitempty"`
Entity string `json:"-"`
Parent string `json:"-"`
Aliases []string `json:"-"`
Admin bool `json:"-"`
Icon string `json:"-"`
Title string `json:"-"`
Verb string `json:"verb,omitempty"`
Scope string `json:"scope,omitempty"`
ActionName string `json:"actionName,omitempty"`
IDParam string `json:"idParam,omitempty"`
SupportsLookup bool `json:"supportsLookup,omitempty"`
SupportsFilterMode bool `json:"supportsFilterMode,omitempty"`
Group string `json:"group,omitempty"`
Order int `json:"-"`
}
ClickyOperationMeta is emitted as the OpenAPI operation-level x-clicky extension. SurfaceID/Aliases are internal-only fields used while building the final surface list.
type ClickySpecMeta ¶
type ClickySpecMeta struct {
Surfaces []ClickySurface `json:"surfaces,omitempty"`
}
ClickySpecMeta is emitted as the OpenAPI-level x-clicky extension.
type ClickySurface ¶
type ClickySurface struct {
Key string `json:"key"`
Entity string `json:"entity"`
Title string `json:"title"`
Parent string `json:"parent,omitempty"`
Admin bool `json:"admin,omitempty"`
Description string `json:"description,omitempty"`
// Icon is an opaque UI icon name (e.g. "database") the frontend resolves to
// a glyph. Emitted verbatim from the entity's x-clicky-icon annotation.
Icon string `json:"icon,omitempty"`
Order int `json:"-"`
}
ClickySurface describes a UI surface resolved from clicky entity metadata.
type CommandOpenAPIMeta ¶
type CommandOpenAPIMeta struct {
Entity string
Parent string
Aliases []string
Admin bool
// Icon is an opaque UI icon name (e.g. "database"); clicky never interprets
// it — it is emitted verbatim on the surface for the frontend to resolve.
Icon string
// Title overrides the auto-generated surface title when non-empty.
Title string
Verb string
Method string
Scope string
ActionName string
IDParam string
SupportsLookup bool
SupportsFilterMode bool
// OptionalID is true when the operation's positional id is optional
// (WithOptionalID). Such operations are invocable without an id, so the
// generated REST path must NOT carry an {id} segment — otherwise the no-id
// call collides with the entity's get-by-id route.
OptionalID bool
// ToolGroup names the group an operation belongs to. It is set on the entity
// and inherited by every operation (a per-action override may replace it).
// AI tool-preference layers use it to enable/disable a set of related tools
// as one unit.
ToolGroup string
}
CommandOpenAPIMeta is the clicky-specific metadata attached to generated Cobra commands so the RPC/OpenAPI layer can expose entity semantics without guessing from paths or operationIds.
func GetCommandOpenAPIMeta ¶
func GetCommandOpenAPIMeta(cmd *cobra.Command) *CommandOpenAPIMeta
type Config ¶
type Config struct {
// DefaultMethod is the default HTTP method for operations.
DefaultMethod string
// PathPrefix is the path prefix for REST APIs.
PathPrefix string
// AutoGeneratePaths controls whether REST paths are generated from the
// command hierarchy.
AutoGeneratePaths bool
// DefaultTags are applied to all operations.
DefaultTags []string
}
Config holds configuration for RPC conversion.
func DefaultConfig ¶
func DefaultConfig() *Config
DefaultConfig returns a sensible default configuration.
type ContextDataFunc ¶
type ContextDataFunc = func(ctx context.Context, flags map[string]string, args []string) (any, error)
ContextDataFunc is the context-aware data closure stored for a command. Its signature matches rpc.ContextDataFunc structurally; the RPC converter converts it when wiring RPCOperation.ContextDataFunc. Defined here (the root package) to avoid a clicky -> clicky/rpc import cycle.
func GetContextDataFunc ¶
func GetContextDataFunc(cmd *cobra.Command) ContextDataFunc
GetContextDataFunc returns the context-aware data function registered for a command, if any. Used by the RPC converter to wire ContextDataFunc.
type ContextFilter ¶
type ContextFilter[ListOpts any] interface { OptionsWithContext(ctx context.Context, opts ListOpts) map[string]api.Textable }
ContextFilter is an OPTIONAL extension a Filter may implement when its option set is resolved from request-scoped state (e.g. a per-request database handle) rather than a process global. When the lookup handler runs with a context (the RPC path feeds r.Context(), the CLI feeds cmd.Context()) it prefers OptionsWithContext over Options; filters that don't implement it fall back to the plain Options() path unchanged.
type ContextLookupFunc ¶
type ContextLookupFunc = func(ctx context.Context, flags map[string]string, args []string) (any, error)
ContextLookupFunc is the context-aware variant of a filter lookup closure. When present, the RPC executor prefers it over LookupFunc and feeds the request's context.Context (r.Context() over HTTP, cmd.Context() on the CLI) so a filter's Options/OptionsWithQuery can resolve request-scoped state (e.g. the per-request database handle) instead of a process global.
func GetContextLookupFunc ¶
func GetContextLookupFunc(cmd *cobra.Command) ContextLookupFunc
GetContextLookupFunc returns the context-aware lookup function registered for a command, if any. Used by the RPC converter to wire ContextLookupFunc.
type ContextSearchableFilter ¶
type ContextSearchableFilter[ListOpts any] interface { OptionsWithQueryAndContext(ctx context.Context, opts ListOpts, query string, limit int) (options map[string]api.Textable, total int) }
ContextSearchableFilter is the context-aware counterpart of SearchableFilter: a large/searchable filter whose head and server-side search both need request-scoped state. The lookup handler prefers it over OptionsWithQuery when a context is available.
type DataFunc ¶
DataFunc is a function that returns structured data directly, bypassing stdout capture. Used by commands registered via AddCommand to provide data to the HTTP handler. (ContextDataFunc / ContextLookupFunc — the context-aware variants — are defined alongside the command registry in command.go.)
type DynamicEntityBuilder ¶
type DynamicEntityBuilder struct {
// contains filtered or unexported fields
}
DynamicEntityBuilder assembles a schema-driven entity and registers it through RegisterDynamicEntity. Filters referenced by x-clicky-filter must be registered (RegisterFilter / RegisterFilterSpec) before Register is called.
func NewDynamicEntity ¶
func NewDynamicEntity(name string, schema []byte) *DynamicEntityBuilder
NewDynamicEntity starts building a dynamic entity from a JSON schema.
func (*DynamicEntityBuilder) Get ¶
func (b *DynamicEntityBuilder) Get(fn DynamicGetFunc) *DynamicEntityBuilder
func (*DynamicEntityBuilder) List ¶
func (b *DynamicEntityBuilder) List(fn DynamicListFunc) *DynamicEntityBuilder
func (*DynamicEntityBuilder) Register ¶
func (b *DynamicEntityBuilder) Register()
Register parses the schema, generates the runtime types, wires the named filters, and registers the entity. It panics on an invalid schema or an unregistered filter reference — both are setup-time wiring errors.
type DynamicEntitySpec ¶
type DynamicEntitySpec struct {
Name string
Parent string
Aliases []string
// Icon is an opaque UI icon name emitted on the surface (x-clicky.surfaces[].icon).
Icon string
// Title overrides the auto-generated surface title when non-empty.
Title string
ListType reflect.Type // generated struct type: flag binding + OpenAPI params
ItemType reflect.Type // generated item struct type for the response schema
List ContextDataFunc
Get ContextDataFunc
Filters []DynamicFilter
// FilterRefs maps a filter key to the reusable named filter backing it, so
// the OpenAPI layer can emit an x-clicky-lookup $ref (see EntityInfo.FilterRefs).
FilterRefs map[string]string
}
DynamicEntitySpec is the type-erased description of a schema-driven entity, assembled by the entity package's NewDynamicEntity builder. It reuses the existing pipeline: ListType drives CLI flag binding and OpenAPI parameters, ItemType drives the response schema, and Filters feed the shared lookup engine.
type DynamicFilter ¶
type DynamicFilter struct {
Key string
Label string
Type string
Multi bool
Searchable bool
// Options returns the head set (query == "") or search matches, plus the true
// total behind the head. Required.
Options func(ctx context.Context, flags map[string]string, query string, limit int) (map[string]api.Textable, int)
// Selected labels the currently-selected value(s) of this filter's key.
// Optional; nil means "no selection rendering".
Selected func(ctx context.Context, flags map[string]string) map[string]api.Textable
}
DynamicFilter describes one filter on a dynamic (schema-driven) entity. The Options/Selected closures resolve from the request flag map — they are built by the entity package from a reusable named filter — so the type-agnostic filter logic stays out of this package while reusing the shared lookup builder.
type DynamicGetFunc ¶
DynamicGetFunc fetches a single dynamic-entity row by id.
type DynamicListFunc ¶
DynamicListFunc lists rows of a dynamic entity for the given flag map.
type Entity ¶
type Entity[T EntityItem, ListOpts any, R any] struct { Name string // Parent, when set, nests the entity's command under a parent cobra command // with that name. The parent command is created lazily by GenerateCLI if it // does not already exist. Parent string // Aliases applied to the generated entity cobra command. Aliases []string List func(opts ListOpts) ([]T, error) Get func(id string) (R, error) // ListWithContext / GetWithContext / GetWithFlagsAndContext are context-aware // variants of List / Get / GetWithFlags. When set they take precedence over // their non-context counterparts and receive the request-scoped // context.Context (r.Context() over HTTP, cmd.Context() on the CLI). Use them // to resolve per-request state (e.g. a database/config bundle) instead of // reaching for process globals. ListWithContext func(ctx context.Context, opts ListOpts) ([]T, error) ListPaged func(opts ListOpts) (PagedResult[T], error) ListPagedWithContext func(ctx context.Context, opts ListOpts) (PagedResult[T], error) GetWithContext func(ctx context.Context, id string) (R, error) GetWithFlagsAndContext func(ctx context.Context, id string, flags map[string]string) (R, error) // GetFlags, when non-nil, is a zero-value struct value implementing // ActionFlags whose `flag:"..."` tagged fields are registered as // CLI flags on the generated `get` subcommand. The parsed values are // passed into GetWithFlags. // // GetWithFlags is mutually exclusive with Get: when both are set, // GetWithFlags wins. Set GetFlags to declare the flag schema and // GetWithFlags to receive the typed values. GetFlags ActionFlags GetWithFlags func(id string, flags map[string]string) (R, error) Create func(body map[string]any) (R, error) Update func(id string, body map[string]any) (R, error) Delete func(id string) error // CreateWithContext / UpdateWithContext / DeleteWithContext are context-aware // variants of Create / Update / Delete, mirroring the read-side seam above. // When set they take precedence and receive the request-scoped context, so // writes target the request's environment rather than a process global. CreateWithContext func(ctx context.Context, body map[string]any) (R, error) UpdateWithContext func(ctx context.Context, id string, body map[string]any) (R, error) DeleteWithContext func(ctx context.Context, id string) error Filters []Filter[ListOpts] Actions []EntityAction BulkActions []EntityBulkAction // Admin groups admin-only operations (inspect, configure, etc.) // that produce different views/columns from the main CRUD operations. // Generates subcommands under an "admin" subgroup and routes like /entity/admin/{verb}. Admin *Entity[T, ListOpts, R] // ValidArgs provides shell completion for the ID argument. ValidArgs func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) // ToolGroup names the group all of this entity's operations belong to. It is // inherited by every generated operation; an action may override it via // WithToolGroup. AI tool-preference layers use it to toggle related tools // together. ToolGroup string }
Entity configures a CRUD resource. All function fields are optional. T is the type returned by List and must implement EntityItem. R is the type returned by Get/Create/Update.
type EntityAction ¶
type EntityAction interface {
// contains filtered or unexported methods
}
EntityAction is the type-erased registration surface for custom entity actions. Use Action or ActionWithFlags to construct values.
type EntityBuilder ¶
type EntityBuilder[T EntityItem, ListOpts any, R any] struct { // contains filtered or unexported fields }
EntityBuilder provides a fluent API for registering typed entities.
func NewEntity ¶
func NewEntity[T EntityItem, ListOpts any, R any](name string) *EntityBuilder[T, ListOpts, R]
NewEntity starts a typed entity registration. The resulting entity is served identically on the CLI and over HTTP/RPC. See the package github.com/flanksource/clicky/entity for an authoring guide, the best practices for operations that behave well on both surfaces, and runnable examples.
func (*EntityBuilder[T, ListOpts, R]) Admin ¶
func (b *EntityBuilder[T, ListOpts, R]) Admin(admin Entity[T, ListOpts, R]) *EntityBuilder[T, ListOpts, R]
func (*EntityBuilder[T, ListOpts, R]) Aliases ¶
func (b *EntityBuilder[T, ListOpts, R]) Aliases(aliases ...string) *EntityBuilder[T, ListOpts, R]
func (*EntityBuilder[T, ListOpts, R]) Build ¶
func (b *EntityBuilder[T, ListOpts, R]) Build() Entity[T, ListOpts, R]
func (*EntityBuilder[T, ListOpts, R]) Create ¶
func (b *EntityBuilder[T, ListOpts, R]) Create(fn func(map[string]any) (R, error)) *EntityBuilder[T, ListOpts, R]
func (*EntityBuilder[T, ListOpts, R]) CreateWithContext ¶
func (b *EntityBuilder[T, ListOpts, R]) CreateWithContext(fn func(context.Context, map[string]any) (R, error)) *EntityBuilder[T, ListOpts, R]
CreateWithContext sets the context-aware create handler. The context carries request-scoped state (e.g. the originating *http.Request via rpc.RequestFromContext), letting handlers read the raw nested JSON body the executor would otherwise flatten to string flags.
func (*EntityBuilder[T, ListOpts, R]) Delete ¶
func (b *EntityBuilder[T, ListOpts, R]) Delete(fn func(string) error) *EntityBuilder[T, ListOpts, R]
func (*EntityBuilder[T, ListOpts, R]) DeleteWithContext ¶
func (b *EntityBuilder[T, ListOpts, R]) DeleteWithContext(fn func(context.Context, string) error) *EntityBuilder[T, ListOpts, R]
DeleteWithContext sets the context-aware delete handler. See CreateWithContext.
func (*EntityBuilder[T, ListOpts, R]) Filters ¶
func (b *EntityBuilder[T, ListOpts, R]) Filters(filters ...Filter[ListOpts]) *EntityBuilder[T, ListOpts, R]
func (*EntityBuilder[T, ListOpts, R]) Get ¶
func (b *EntityBuilder[T, ListOpts, R]) Get(fn func(string) (R, error)) *EntityBuilder[T, ListOpts, R]
func (*EntityBuilder[T, ListOpts, R]) GetWithContext ¶
func (b *EntityBuilder[T, ListOpts, R]) GetWithContext(fn func(context.Context, string) (R, error)) *EntityBuilder[T, ListOpts, R]
func (*EntityBuilder[T, ListOpts, R]) GetWithFlags ¶
func (b *EntityBuilder[T, ListOpts, R]) GetWithFlags(flags ActionFlags, fn func(string, map[string]string) (R, error)) *EntityBuilder[T, ListOpts, R]
func (*EntityBuilder[T, ListOpts, R]) List ¶
func (b *EntityBuilder[T, ListOpts, R]) List(fn func(ListOpts) ([]T, error)) *EntityBuilder[T, ListOpts, R]
func (*EntityBuilder[T, ListOpts, R]) ListPaged ¶
func (b *EntityBuilder[T, ListOpts, R]) ListPaged(fn func(ListOpts) (PagedResult[T], error)) *EntityBuilder[T, ListOpts, R]
func (*EntityBuilder[T, ListOpts, R]) ListPagedWithContext ¶
func (b *EntityBuilder[T, ListOpts, R]) ListPagedWithContext(fn func(context.Context, ListOpts) (PagedResult[T], error)) *EntityBuilder[T, ListOpts, R]
func (*EntityBuilder[T, ListOpts, R]) ListWithContext ¶
func (b *EntityBuilder[T, ListOpts, R]) ListWithContext(fn func(context.Context, ListOpts) ([]T, error)) *EntityBuilder[T, ListOpts, R]
func (*EntityBuilder[T, ListOpts, R]) Parent ¶
func (b *EntityBuilder[T, ListOpts, R]) Parent(parent string) *EntityBuilder[T, ListOpts, R]
func (*EntityBuilder[T, ListOpts, R]) Register ¶
func (b *EntityBuilder[T, ListOpts, R]) Register()
func (*EntityBuilder[T, ListOpts, R]) ToolGroup ¶
func (b *EntityBuilder[T, ListOpts, R]) ToolGroup(group string) *EntityBuilder[T, ListOpts, R]
ToolGroup names the group this entity's operations belong to. Every generated operation inherits it (an action can override it via WithToolGroup). AI tool-preference layers use the group to enable/disable related tools together.
func (*EntityBuilder[T, ListOpts, R]) Update ¶
func (b *EntityBuilder[T, ListOpts, R]) Update(fn func(string, map[string]any) (R, error)) *EntityBuilder[T, ListOpts, R]
func (*EntityBuilder[T, ListOpts, R]) UpdateWithContext ¶
func (b *EntityBuilder[T, ListOpts, R]) UpdateWithContext(fn func(context.Context, string, map[string]any) (R, error)) *EntityBuilder[T, ListOpts, R]
UpdateWithContext sets the context-aware update handler. See CreateWithContext.
func (*EntityBuilder[T, ListOpts, R]) ValidArgs ¶
func (b *EntityBuilder[T, ListOpts, R]) ValidArgs(fn func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective)) *EntityBuilder[T, ListOpts, R]
func (*EntityBuilder[T, ListOpts, R]) WithAction ¶
func (b *EntityBuilder[T, ListOpts, R]) WithAction(action EntityAction) *EntityBuilder[T, ListOpts, R]
func (*EntityBuilder[T, ListOpts, R]) WithBulkAction ¶
func (b *EntityBuilder[T, ListOpts, R]) WithBulkAction(action EntityBulkAction) *EntityBuilder[T, ListOpts, R]
type EntityBulkAction ¶
type EntityBulkAction interface {
// contains filtered or unexported methods
}
EntityBulkAction is the type-erased registration surface for custom bulk actions. Use BulkAction or BulkFilterAction to construct values.
type EntityInfo ¶
type EntityInfo struct {
Name string
Parent string
Aliases []string
// Icon is an opaque UI icon name carried through to the OpenAPI surface
// (x-clicky.surfaces[].icon). Empty for entities that declare no icon.
Icon string
// Title overrides the auto-generated surface title when non-empty.
Title string
Type reflect.Type
ListType reflect.Type
Operations []EntityOperation
Actions []ActionInfo
BulkActions []BulkActionInfo
ValidArgs func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective)
IsAdmin bool
// FilterRefs maps a list filter's flag key to the name of the reusable named
// filter backing it (when the filter was attached via the entity package's
// Use/As helper). The OpenAPI layer uses it to emit an x-clicky-lookup $ref
// to the shared filter definition. Nil when no filters reference a named one.
FilterRefs map[string]string
// ToolGroup names the group all of this entity's operations belong to. It is
// inherited by every generated operation (an action may override it) and is
// used by AI tool-preference layers to toggle related tools together.
ToolGroup string
}
EntityInfo is the type-erased representation stored in the registry.
func GetEntity ¶
func GetEntity(name string) (EntityInfo, bool)
GetEntity returns the registered entity with the given name (or alias) and whether it was found.
type EntityItem ¶
EntityItem is the interface that all entity types must implement.
type EntityOperation ¶
type EntityOperation struct {
Verb string // "list", "get", "create", "update", "delete"
Method string // Optional explicit HTTP method for generated RPC/OpenAPI routes.
DataFunc func(flags map[string]string, args []string) (any, error)
// ContextDataFunc, when set, is preferred over DataFunc by both the CLI run
// path (fed cmd.Context()) and the RPC executor (fed r.Context()). Lets the
// operation resolve request-scoped state instead of process globals.
ContextDataFunc ContextDataFunc
// FlagsType, when non-nil, binds typed flags from the given struct type
// onto the generated cobra command and collects their values into the
// flag map passed to DataFunc. Used by actions that implement
// ActionFlags; ignored for the built-in CRUD verbs.
FlagsType reflect.Type
LookupFunc func(flags map[string]string, args []string) (any, error)
// ContextLookupFunc, when set, is the context-aware filter lookup closure.
// The RPC converter wires it onto RPCOperation.ContextLookupFunc and the
// executor prefers it over LookupFunc, feeding the request context.
ContextLookupFunc ContextLookupFunc
BindCompletions func(cmd *cobra.Command)
ResponseType reflect.Type
ResponseArray bool
ResponsePaged bool
ResponseEntityID bool
}
EntityOperation represents a single CRUD operation.
type ExecutableCommand ¶
type ExecutableCommand interface {
// Execute runs the command with the given options, capturing everything
// written to os.Stdout / os.Stderr (including direct writes, not just the
// cobra writers). It is safe for concurrent callers: implementations that
// swap process-global file descriptors serialize internally.
Execute(ctx context.Context, opts ExecuteOptions) (stdout, stderr string, err error)
// Path is the full space-joined command path ("user create").
Path() string
// Name is the leaf command name ("create").
Name() string
// RootName is the top-level application command name ("xero-cli"), used for
// the MCP tool title.
RootName() string
// Runnable reports whether the command has a Run/RunE (not a pure group).
Runnable() bool
// Hidden reports whether the command is hidden from help/listing.
Hidden() bool
// IsBoolFlag reports whether the named flag is a boolean flag. Used by the
// CLI-string reconstruction to render "--flag" vs "--flag=value".
IsBoolFlag(name string) bool
}
ExecutableCommand is the transport-neutral handle an RPCOperation holds onto in place of a concrete *cobra.Command. It encapsulates everything the execution path (RPC executor, MCP server) and the tool-surfacing layers (aichat) need, so those packages no longer reference cobra directly.
The cobra-specific machinery — the global os.Stdout/os.Stderr pipe swap, flag copying, state reset — lives entirely inside the CobraExecutableCommand implementation (rpc package).
type ExecuteOptions ¶
type ExecuteOptions struct {
// Args are the positional arguments.
Args []string
// Flags maps flag name -> string value. A flag absent on the command is
// silently skipped (path params and other non-flag keys may appear here);
// a present flag whose value fails to parse returns an error.
Flags map[string]string
// FormatOverrides are best-effort flag values applied before execution
// (e.g. {"format":"markdown","no-color":"true"}). A flag absent on the
// command is silently skipped. Used by the MCP server's format forcing.
FormatOverrides map[string]string
}
ExecuteOptions controls how an ExecutableCommand runs one invocation. It is the transport-neutral subset of what the RPC executor and MCP server previously poked directly onto a *cobra.Command.
type Filter ¶
type Filter[ListOpts any] interface { Key() string Label() string Lookup(opts *ListOpts) (map[string]api.Textable, error) Options(opts ListOpts) map[string]api.Textable }
Filter resolves raw entity option values into the backend-specific shape and exposes UI metadata for the currently selected and available values.
func LiftFilters ¶
func LiftFilters[Outer any, Inner any]( filters []Filter[Inner], project func(*Outer) *Inner, ) []Filter[Outer]
LiftFilters adapts a Filter[Inner] slice so the same picker definitions work against an outer struct that embeds (or otherwise reaches) the inner filter struct. The project func extracts a *Inner from any *Outer the filter system hands us; lookup keys, labels, options, and selected-value reads/writes flow through unchanged. Use this to keep picker constructors scoped to the inner filter type while letting subcommand options structs — which also carry positional args, behaviour flags, etc. — satisfy Filterable[Outer].
type FilterContext ¶
type FilterContext struct {
// Context is the request context (HTTP request or CLI command). It may be
// nil when a source is invoked outside a request (e.g. shell completion).
Context context.Context
// Key is the bound flag/field name this filter resolves on the current
// entity (e.g. "owner" when a "users" filter is attached via .As("owner")).
Key string
// Params holds the current values of every flag/filter on the entity, so a
// source can narrow its options against sibling selections (cascading).
Params map[string]string
}
FilterContext carries the request-scoped state a FilterSource needs to resolve its options. It is the single representation both static and dynamic entities can produce: a static entity reflects its typed ListOpts into Params, a dynamic entity already holds the flag map.
func (FilterContext) Ctx ¶
func (fc FilterContext) Ctx() context.Context
Ctx returns the context, defaulting to context.Background when none was set.
type FilterSource ¶
type FilterSource interface {
// Options returns the available options, optionally narrowed by query, and
// the true total count behind the (possibly capped) returned set. An empty
// query means "the head set". A non-positive limit means "no cap".
Options(fc FilterContext, query string, limit int) (options map[string]api.Textable, total int, err error)
// Resolve labels the currently-selected raw value(s) for display. A value
// with no known label is echoed back as plain text.
Resolve(fc FilterContext, values []string) (map[string]api.Textable, error)
}
FilterSource produces the options for a NamedFilter. Implementations are type-agnostic — they read FilterContext.Params rather than a typed struct — so one source serves any entity that references the filter.
func EntityOptions ¶
func EntityOptions(entityName string) FilterSource
EntityOptions is a FilterSource that resolves its options from another registered entity: value = GetID(), label = PrettyShort()/GetName(). Search is an in-memory substring match over the source entity's list.
func FuncOptions ¶
func FuncOptions(fn func(fc FilterContext, query string, limit int) (map[string]api.Textable, int, error)) FilterSource
FuncOptions is a FilterSource backed by a user-supplied function — the general escape hatch for DB-backed or computed options with server-side search. The function owns query matching and the limit cap.
func StaticOptions ¶
func StaticOptions(options map[string]api.Textable) FilterSource
StaticOptions is a FilterSource backed by a fixed set of options, narrowed by case-insensitive substring match on the option key or its rendered label.
type FilterSourceSpec ¶
type FilterSourceSpec struct {
Kind string `json:"kind" yaml:"kind"`
// Options is the value→label map for a static source.
Options map[string]string `json:"options,omitempty" yaml:"options,omitempty"`
// Entity is the source entity name for an entity source.
Entity string `json:"entity,omitempty" yaml:"entity,omitempty"`
}
FilterSourceSpec is the declarative description of where a filter's options come from. "static" and "entity" are constructible from a spec; "func" is Go-only and only ever appears on the emit side (NamedFilter.Spec).
type FilterSpec ¶
type FilterSpec struct {
Name string `json:"name" yaml:"name"`
Label string `json:"label,omitempty" yaml:"label,omitempty"`
Type string `json:"type,omitempty" yaml:"type,omitempty"`
Multi bool `json:"multi,omitempty" yaml:"multi,omitempty"`
Source FilterSourceSpec `json:"source" yaml:"source"`
}
FilterSpec is the JSON/YAML-authorable form of a NamedFilter. It is also the shape emitted for OpenAPI (NamedFilter.Spec), so a Go-defined filter and a declaratively-defined one are indistinguishable to clients.
type Filterable ¶
Filterable is implemented by AddNamedCommand options structs that want to expose typed filter lookups (dropdowns/typeaheads on the web UI, shell completions on the CLI) on the subcommand itself rather than inheriting only the parent entity's Filters slice. The same Filter[T] values that back an Entity's Filters slice work here; AddNamedCommand stores a LookupFunc in the lookupFuncRegistry and binds completions whenever an opts struct satisfies this interface.
Use this whenever a subcommand's flag surface diverges from its parent list view — typically when a positional argument pins one or more identifier filters and the subcommand only exposes the orthogonal (status, type, date range) lenses.
type Help ¶
Help is implemented by options structs that supply their own long-form command help. The generated command sets cmd.Long from Help().ANSI().
type MultiFilter ¶
type MultiFilter []string
MultiFilter is a string-list flag whose values are interpreted with collections.MatchItems semantics: plain values include, !value excludes.
type NamedFilter ¶
type NamedFilter struct {
// Name is the unique registry key.
Name string
// Label is the human-facing control label. Defaults to Name when empty.
Label string
// Type is the UI control type: "select" (default), "multi-select", "date",
// "from", or "to".
Type string
// Multi reports whether the control accepts multiple selections.
Multi bool
// Source resolves the filter's options.
Source FilterSource
}
NamedFilter is a reusable filter definition registered under a unique name and attached to entities by reference. Authored in Go (RegisterFilter) or declaratively (RegisterFilterSpec), both normalize to this type.
func FilterFromSpec ¶
func FilterFromSpec(s FilterSpec) (NamedFilter, error)
FilterFromSpec builds (but does not register) a NamedFilter from a declarative spec, validating the source kind.
func GetFilter ¶
func GetFilter(name string) (NamedFilter, bool)
GetFilter returns the named filter and whether it was found.
func MustGetFilter ¶
func MustGetFilter(name string) NamedFilter
MustGetFilter returns the named filter, panicking if it is not registered. Used at attach time (Use/.As), where an unknown reference is a wiring bug.
func (NamedFilter) Spec ¶
func (f NamedFilter) Spec() FilterSpec
Spec emits the declarative form of a NamedFilter, used for OpenAPI generation and round-tripping. A func/custom source emits its kind without detail (its options are resolved server-side via the lookup endpoint).
type PageInfo ¶
type PageInfo struct {
Limit int `json:"limit"`
Offset int `json:"offset"`
Total int64 `json:"total"`
}
PageInfo carries the effective paging window for a list response.
type PagedResult ¶
PagedResult is a typed list response with paging metadata.
func NewPagedResult ¶
func NewPagedResult[T any](rows []T, limit, offset int, total int64) PagedResult[T]
NewPagedResult returns a paged result with a stable non-nil data array.
func (PagedResult[T]) PageMetadata ¶
func (p PagedResult[T]) PageMetadata() PageInfo
func (PagedResult[T]) PageRows ¶
func (p PagedResult[T]) PageRows() any
type Property ¶
type Property struct {
Type string `json:"type"`
Description string `json:"description"`
Enum []string `json:"enum,omitempty"`
Default interface{} `json:"default,omitempty"`
}
Property represents a JSON schema property.
type RPCOperation ¶
type RPCOperation struct {
Name string `json:"name"`
Description string `json:"description"`
Parameters []RPCParameter `json:"parameters"`
Schema Schema `json:"schema"`
Command ExecutableCommand `json:"-"` // Transport-neutral handle to the original command
Path string `json:"path,omitempty"` // For REST APIs
Method string `json:"method,omitempty"` // HTTP method
Tags []string `json:"tags,omitempty"` // OpenAPI tags (auto-derived from the parent command)
Group string `json:"group,omitempty"` // tool-group this operation belongs to (clicky/tool-group)
DataFunc DataFunc `json:"-"` // Direct data provider, bypasses stdout capture
ContextDataFunc ContextDataFunc `json:"-"` // Context-aware data provider; preferred over DataFunc when set
LookupFunc DataFunc `json:"-"` // Direct filter metadata provider
ContextLookupFunc ContextLookupFunc `json:"-"` // Context-aware filter metadata provider; preferred over LookupFunc when set
Clicky *ClickyOperationMeta `json:"-"` // Entity semantics used for OpenAPI extensions
ResponseType reflect.Type `json:"-"` // Static response type for OpenAPI generation
ResponseArray bool `json:"-"` // Response body is an array of ResponseType
ResponsePaged bool `json:"-"` // Response body is a paged envelope around ResponseType rows
ResponseEntityID bool `json:"-"` // Array item schema should include Clicky _id metadata
}
RPCOperation represents a generic RPC operation that can be converted to various formats (OpenAPI, MCP tools, …).
type RPCParameter ¶
type RPCParameter struct {
Name string `json:"name"`
Type string `json:"type"`
Description string `json:"description"`
Required bool `json:"required"`
Default interface{} `json:"default,omitempty"`
In string `json:"in,omitempty"` // "query", "path", "header" for REST
}
RPCParameter represents a parameter in an RPC operation.
type RPCService ¶
type RPCService struct {
Name string `json:"name"`
Version string `json:"version"`
Description string `json:"description"`
Operations []RPCOperation `json:"operations"`
}
RPCService represents a collection of RPC operations.
type ResponseOpenAPIMeta ¶
ResponseOpenAPIMeta describes the static response type for a generated command. It is consumed by the RPC/OpenAPI layer without executing handlers.
func GetCommandResponseMeta ¶
func GetCommandResponseMeta(cmd *cobra.Command) *ResponseOpenAPIMeta
GetCommandResponseMeta returns static response metadata attached to a command.
type Schema ¶
type Schema struct {
Type string `json:"type"`
Properties map[string]Property `json:"properties"`
Required []string `json:"required"`
}
Schema represents a JSON schema for operation input/output.
type SearchableFilter ¶
type SearchableFilter[ListOpts any] interface { OptionsWithQuery(opts ListOpts, query string, limit int) (options map[string]api.Textable, total int) }
SearchableFilter is an OPTIONAL extension a Filter may implement when its option set is too large to enumerate in one shot (e.g. a SQL DISTINCT column with thousands of values). The lookup handler type-asserts to it; filters that don't implement it keep the plain Options() behaviour unchanged.
OptionsWithQuery returns at most limit options. An empty query means "the head set": the first limit options plus total = the true distinct count, so the UI can show "… and N more". A non-empty query returns up to limit options matching it (server-side search), letting the UI surface values that sort beyond the head. total is only meaningful for the head (query == "") call.
type TypedFilter ¶
TypedFilter is an OPTIONAL extension a Filter may implement when the underlying flag type is intentionally broader than the UI control type. For example, date-math flags often remain strings at the CLI layer while the web lookup response should still advertise a from/to date-range control.