Help us shape the future of Go! Take the 2026 Go Developer Survey

cmdutil

package
v0.15.0 Latest Latest
Warning

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

Go to latest
Published: Sep 23, 2026 License: MIT Imports: 22 Imported by: 0

Documentation

Overview

Package cmdutil provides the Factory injected into every command: lazily-resolved config, token store, and API client, plus the values of the persistent --json/--server/--app flags.

Index

Constants

View Source
const (
	WhereFlagUsage = `structured predicate over one JSONB column — "properties" unless a leaf sets "field":"data"` +
		` (e.g. '{"field":"data","path":["authorName"],"exists":true}')`
	SortPropertyFlagUsage = `order by a JSON path in one JSONB column — same "field" key and "properties" default as --where` +
		` (e.g. '{"field":"data","path":["rank"],"as":"number","direction":"desc"}')`
)

WhereFlagUsage and SortPropertyFlagUsage are the shared `--where` / `--sort-property` help strings, defined once so the two commands offering them cannot drift (#603).

Both name the DEFAULT COLUMN and show "field" in the example, which the previous wording did not. It read "structured predicate over properties/data", which a reader reasonably takes to mean the predicate searches BOTH — and the example it gave omitted "field" entirely, so copying it aimed the predicate at `properties` without ever mentioning the choice. A node's free-form envelope lives in `data`, so that spelling returns a silent zero for the commonest thing anyone wants to ask about.

Variables

This section is empty.

Functions

func AppParts added in v0.13.0

func AppParts(ref string) (root, slug string, ok bool)

AppParts decomposes an App reference into its grammar-v2 (root, slug) atoms. It accepts every spelling the CLI advertises — a bare "root:slug" or legacy "root::slug", or an hrn:app:/urn:app: URN in either separator — and normalizes the separator either way. ok is false for an id (no separator), a URN of another type (hrn:worker:…), or a malformed multi-part ref.

func BatchNodeRef added in v0.9.0

func BatchNodeRef(memory, ref string) (string, error)

BatchNodeRef canonicalizes a node reference for a server op that resolves a PK-or-URN itself, WITHOUT the resolveUrn round trip ResolveNodeRef costs — today nodeBatch(refs:), which accepts both since hadron-server#813. It takes the same inputs ResolveNodeRef does (a fully-qualified URN, or a bare loc with -m/--memory) and applies the same composition, but returns the ref to send instead of an id. That is what makes a batch of URNs ONE call rather than N resolves plus a batch.

It rejects locally what the server would reject loudly: the server errors on a malformed / unqualified ref rather than listing it as unavailable, and one mistyped ref must not cost the other nineteen their read. Callers map the returned Usage error onto their own unavailable list.

func CanonicalAppRef added in v0.13.0

func CanonicalAppRef(what, ref string) (string, error)

CanonicalAppRef validates an App reference client-side and normalizes it to the canonical grammar-v2 URN hrn:app:<root>:<slug> — the App counterpart of CanonicalMemoryRef, with one difference: an unrecognized shape is REFUSED as a usage error rather than passed through for the server to reject.

The server's refusal is the wrong one to relay (#540): it describes the ref in the server's terms rather than naming the flag the caller typed, and its hint teaches the retired `::` grammar. Checking the shape here costs no round trip and lets the message say what the caller can act on. `what` names the source for that message — "--app", "--install-into", "<app-ref>".

One of #540's three reasons has since been fixed elsewhere and is deliberately NOT listed above: the refusal used to arrive wrapped in genqlient's `input:3: <field> ` location prefix, and #566 removed that for every server error. The remaining two are the load-bearing ones and neither depends on it — a message that names `--app` beats one that names a GraphQL argument however cleanly the latter is rendered, and the `::` hint is the server's wording, not its packaging. Said explicitly because a reader who checks the old rationale against today's output would find a third of it untrue and reasonably wonder whether this whole function still earns its place. It does.

An id passes through verbatim (the server dispatches PKs); an empty ref returns "" with no error, since whether an App is REQUIRED is the caller's question, not this function's.

func CanonicalMemoryRef added in v0.6.0

func CanonicalMemoryRef(ref string) string

CanonicalMemoryRef normalizes a memory reference to the canonical grammar-v2 flat URN hrn:mem:<root>:<slug> (#697 emission flip) for the server's memory(ref:) dispatch. A raw id (no separator) or an unrecognized shape passes through untouched — the server accepts every legacy spelling forever (#239), so the short forms the CLI advertises resolve consistently either way (#108).

func CanonicalNodeRef added in v0.8.0

func CanonicalNodeRef(ref string) string

CanonicalNodeRef canonicalizes a node reference for a server op that itself accepts an ID or a URN (spec 007 dispatch) — e.g. the object store's object(ref:)/updateObject/deleteObject, which forward ref to node(ref:). A scheme-prefixed URN passes through, a bare/legacy fully-qualified node URN (<org>::<memory>::<loc>) gets the canonical hrn:node: prefix, and a raw id (or any unrecognized shape) is left for the server to resolve. Unlike ResolveNodeURN it does NOT round-trip through resolveUrn, so a raw object id works without a lookup and without being rejected as "not a URN".

func CanonicalNodeURN added in v0.6.0

func CanonicalNodeURN(ref string) (string, error)

CanonicalNodeURN validates and normalizes a fully-qualified entry-node URN for the headless-run surface (schedule/webhook/trigger entryNodeUrn). It is the no-network half of ResolveNodeURN: a scheme-prefixed ref (hrn:/urn:) passes through verbatim; a bare <org>::<memory>::<loc> gets the canonical hrn:node: prefix; anything without the two `::` separators is rejected as ambiguous. The result is a URN the server stores, not a node ID — the entry node is resolved at run time, not now.

func CanonicalizeURN added in v0.8.0

func CanonicalizeURN(flag, input string) (string, error)

CanonicalizeURN validates a scheme-prefixed Hadron URN and returns its parser-canonical form. It is intentionally kept as a thin wrapper for the spec-047 golden tests, which pin CLI parser parity to urn-lib-go.

func Confirm added in v0.2.0

func Confirm(io *output.IOStreams, yes bool, prompt string) error

Confirm gates a significant but non-deletion action behind the same rule as ConfirmDeletion: --yes skips the prompt, an interactive terminal is asked y/N, and a non-interactive caller without --yes is refused with a Usage error so the action is always explicit. `prompt` is the full question, without the trailing " (y/N)".

func ConfirmDeletion

func ConfirmDeletion(io *output.IOStreams, yes bool, what string) error

ConfirmDeletion gates destructive commands. --yes skips the prompt; otherwise an interactive terminal asks y/N, and a non-interactive caller (scripts, agents) is refused with a Usage error so deletions are always explicit.

func DescribeUser added in v0.9.0

func DescribeUser(u gen.UserFields) string

DescribeUser renders a user for a confirmation prompt or an error: the id always, plus whichever human identifiers exist. The id alone is unreadable and the handle alone is not unique enough to confirm against.

func EdgeDisplay added in v0.3.0

func EdgeDisplay(name *string, loc string) string

EdgeDisplay is the human handle for an edge: its name, or its loc when the name is empty (spec 037 — an edge's name is optional, its loc is the identity, so a nameless edge still prints something addressable).

func InstallForbiddenGuidance added in v0.13.0

func InstallForbiddenGuidance(err error) error

InstallForbiddenGuidance turns the server's bare FORBIDDEN on an install/uninstall into the actual rule (#389). The gate is NOT App membership: installing an existing Agent is itself a read grant on that Agent's design — its system memory becomes readable from every App context and the returned Agent carries its systemPrompt — so it sits at the level that can already read the org's Agents. hadron-server#952 proposed admitting non-reader AppMembers and that was declined for exactly this reason, which means a team member who is not an org member will hit this and deserves better than one word.

It lives in cmdutil rather than in the `app` command package because two command groups now reach the same mutation — `app agent add/remove` and `agent create --install-into` — and a second copy of this prose would drift from the first the next time the rule moves.

func IsAppID added in v0.13.0

func IsAppID(ref string) bool

IsAppID reports whether ref is an App PK rather than a URN. The server dispatches on exactly these two shapes and treats EVERYTHING else as a URN that must be fully qualified — so a colon-less slug ("dev-team") is not an id here either, and forwarding it would only buy the server's refusal, in the server's words (#540).

Unlike IsNodeID this admits the cuid shape. noderef.go refuses it because a cuid is indistinguishable from an ordinary loc; nothing loc-shaped is ever an App ref, so that hazard has no counterpart here.

func IsBareID added in v0.14.0

func IsBareID(ref string) bool

IsBareID reports whether ref has the shape of an opaque platform id — 32 lowercase hex characters — rather than a name, loc, or URN.

This is the rule IsNodeID applies to nodes, named for what it actually tests so that entities with NO URN yet — a Scope, a Channel (spec 049 says "no URN yet" for both) — can share it instead of copying the regex. The point is that the shape lives in ONE place and cannot drift between two copies.

It is NOT a claim about every Hadron id: an App id may also be a 25-character CUID, which IsAppID accepts explicitly (see appref.go). Use this only where the accepted id form really is the 32-hex one.

See IsNodeID for why the rule is deliberately NOT widened to CUIDs.

func IsNodeID added in v0.9.0

func IsNodeID(ref string) bool

IsNodeID reports whether ref is a bare node id rather than a URN or loc.

Every --json surface prints these (`id`, and `otherNodeId` on each edge) and both node(ref:) and nodeBatch(refs:) accept them, so a ref the CLI just emitted has to be feedable straight back (#336). It is matched by SHAPE, not merely by "contains no colon": a bare loc typed without -m (`start-here`) is also colon-free, and treating that as an id would swap a usage error naming -m for a bare "not found".

Note resolveUrn does NOT accept an id — it returns null for one — so callers short-circuit rather than round-tripping.

NOT widened to the CUID the schema also names as a PK form ("PK (CUID / 32-char hex)"). A CUID-shaped rule — letter-led lowercase alphanumeric — is indistinguishable from an ordinary loc, and would capture 16 real ones in the sampled memories, including `preflight`, `instructions`, `conventions` and `findings`: `node get preflight` would stop reporting "pass -m" and start reporting "not found". Nothing is lost by the narrow gate — a CUID-backed node is still addressable by its URN — whereas widening breaks refs that work today.

func IsQualifiedNodeRef added in v0.9.0

func IsQualifiedNodeRef(ref string) bool

IsQualifiedNodeRef reports whether ref already names its own memory — a scheme-prefixed URN (hrn:node:/urn:node:) or the legacy fully-qualified <org>::<memory>::<loc>. It is the same grammar ResolveNodeURN accepts, in predicate form.

It exists for commands whose -m/--memory is REQUIRED for another reason (it names where a write lands, say) but which also take a node ref that may point at another memory. ResolveNodeRef treats its ref as a bare loc whenever a memory is supplied, so passing a qualified ref through composes it INTO that memory — `hrn:node:acme.com:kb:hrn:node:other.org:dev:x`, which resolves to nothing, or "" for the legacy spelling. Gate on this and pass an empty memory for qualified refs so they resolve where they actually live.

A bare node id is NOT covered here and needs no gate: ResolveNodeRef short-circuits on IsNodeID before -m is considered.

func KeyValsToJSON added in v0.6.0

func KeyValsToJSON(pairs []string, flag string) (*json.RawMessage, error)

KeyValsToJSON assembles repeated key=value flags into a JSON object (e.g. `--arg k=v` → an eventData object, `--param k=v` → a provider-params object). Each value is sent as JSON when it parses as JSON (numbers, booleans, arrays, objects), otherwise as a string. Returns nil for no pairs so the variable is omitted, not sent as `{}`. `flag` names the source flag in the error.

func MemoryParts added in v0.8.0

func MemoryParts(ref string) (root, slug string, ok bool)

MemoryParts decomposes a memory reference into its grammar-v2 (root, slug) atoms. It accepts every spelling the CLI advertises — a bare "org:slug" or "org::slug", or an hrn:memory:/urn:memory: (v1) / hrn:mem:/urn:mem: (v2) URN — and normalizes the separator either way. ok is false for a raw id (no separator), an unrelated scheme (hrn:node:…), or a malformed multi-part ref; callers pass those through for the server to resolve.

func NodeURN added in v0.6.0

func NodeURN(memory, loc string) string

NodeURN composes the canonical grammar-v2 flat node URN hrn:node:<root>:<slug>:<loc…> for a (memory, loc). The memory's separators are normalized (single-colon and legacy "::" both accepted). It returns "" when the memory isn't an <org>::<slug> pair (a raw id, or a malformed multi-part ref) or loc is empty — composing a URN from those would produce an invalid one that resolves to nothing, silently defeating the existence probe (#129 review). The caller must probe otherwise.

func ParseJSONArg added in v0.6.0

func ParseJSONArg(s, what string) (*json.RawMessage, error)

ParseJSONArg parses a JSON-document flag (--policy, --args-schema). An empty string means "not provided" and returns nil so the variable is omitted; a non-empty value must be valid JSON. The `what` label names the flag in the error.

func ParseNodePropertySort added in v0.8.0

func ParseNodePropertySort(raw string) (*gqltypes.NodePropertySort, error)

ParseNodePropertySort parses the raw-JSON `--sort-property` value (server NodePropertySort, #719) into the bound gqltypes struct. Same grammar-parity contract as ParseNodeWhere: keys are path (required), field, as, direction.

func ParseNodeWhere added in v0.8.0

func ParseNodeWhere(raw string) (*gqltypes.NodeWhereInput, error)

ParseNodeWhere parses the raw-JSON `--where` predicate (grammar parity with the server's NodeWhereInput, #719) into the bound gqltypes struct. The JSON keys are the GraphQL field names verbatim (and/or/not, path, field, as, and one of eq|ne|in|lt|lte|gt|gte|between|exists|contains), so a user's predicate unmarshals straight through — the struct's omitempty tags then omit every field they left unset, which the server's "exactly one operator" leaf check requires (it counts any operator key that is not undefined). Deep validation (depth, leaf-arity, path shape) is the server's job and surfaces as BAD_USER_INPUT; this only enforces well-formed JSON and rejects unknown keys so a typo like "equals" fails loudly instead of being silently dropped.

func ProjectedColumn added in v0.14.0

func ProjectedColumn(raw *json.RawMessage) json.RawMessage

ProjectedColumn renders one opt-in JSONB column (`properties` / `data`) for a command's --json DTO, given what the server returned for it (#602).

Call it ONLY on the path where the projection flag asked for the column, and store the result in a NON-POINTER json.RawMessage field tagged omitempty. That combination is what lets one key carry three distinct answers:

not requested      -> never call this; leave the field nil (len 0) and
                      omitempty drops the key entirely
requested, a value -> the value
requested, null    -> the 4-byte `null` literal, which is non-empty, so the
                      key stays PRESENT

The third state is the whole point and it is easy to lose. A *json.RawMessage cannot express it: encoding/json sets the pointer to nil for a JSON `null`, so a requested-but-null column would vanish from the payload exactly as an unrequested one does, and a caller who asked for `data` and got no `data` key could not tell "this node has none" from "you did not ask". That ambiguity is the defect #602 was filed for — a zero you cannot interpret — and it is the same lesson already recorded on nodeDetailDTO.AbstractOriginHash (#306): jq returns null for a key that is not there.

It follows that the FLAG must decide whether the key is present, never the returned value, because on the wire an unselected column and a selected-null one are indistinguishable. This helper deliberately cannot make that decision for you — it does not take the flag — so the call site has to.

func ReadDocumentStdin added in v0.15.0

func ReadDocumentStdin(stdin io.Reader, stdinIsTerminal bool, flag, fileFlag string) (string, error)

ReadDocumentStdin reads a DOCUMENT-shaped value from stdin (a node body, a message, a handoff) and refuses an interactive terminal (#643).

A terminal in canonical mode has a line-discipline buffer — typically 4 KB — and a writer that exceeds it without the reader draining loses the overflow. So an agent driving the CLI through a PTY can hand over a 10 KB document, have the command exit 0, and store a silently truncated node. That was observed: an agent-authored report came back with unrelated sections missing and others joined together, matching the mangled terminal input rather than the source file.

REFUSED rather than warned, because the damage is done before anything could warn: the bytes are lost in the kernel before the CLI reads them, so there is nothing to detect afterwards and no byte count here that would be trustworthy. The documented form — `cat file | hadron …` — is a pipe, not a terminal, so this refuses only an undocumented use whose one outcome is corruption.

NOT every `-` reader should call this. `memory encrypt --data-key -` and `secret set --value -` read a SECRET from a terminal deliberately, so it never enters argv or shell history, and they are short and single-line — guarding them would break the safe path they exist to offer. The test is whether the value is a DOCUMENT, not whether the stream is a TTY.

flag names the source in the diagnostic (e.g. `--content -`), and fileFlag the companion that reads a path (e.g. `--content-file`), so the remedy is specific to the caller rather than generic advice.

func RefuseDocumentStdinFromTerminal added in v0.15.0

func RefuseDocumentStdinFromTerminal(stdinIsTerminal bool, flag, fileFlag string) error

RefuseDocumentStdinFromTerminal is ReadDocumentStdin's refusal on its own, so a command can fail FAST — before it resolves refs or fetches the node it is about to edit. `node update` reads the target before building its input, and a guard that only fired at the read would spend two network round trips before rejecting an argument it could have rejected immediately.

One definition, two entry points: the message lives here and ReadDocumentStdin delegates, so an early check and a late one can never disagree about what is refused or what it says.

func ResolveAppRef added in v0.6.0

func ResolveAppRef(f *Factory, flag string) (string, error)

ResolveAppRef resolves the App a headless-run command targets: the explicit --app flag when set, otherwise the configured/global App context (the same source `hadron app use` and the persistent --app write). Empty both ways is a usage error — every run/schedule/webhook command names an App. The ref is shape-checked and canonicalized here (CanonicalAppRef, #540); the server then dispatches an ID or a URN.

func ResolveNodeRef added in v0.3.0

func ResolveNodeRef(cmd *cobra.Command, client graphql.Client, memory, ref string) (string, error)

ResolveNodeRef resolves a node reference into a node ID. With an empty memory it requires a fully-qualified URN (ResolveNodeURN). With a memory (the `org::memory` form, optionally hrn:/urn:-prefixed) the ref is a bare loc within that memory: a node URN is just <org>::<memory>::<loc>, so the two are joined and resolved. The memory form is the additive convenience; without it the strict-URN behavior is unchanged.

func ResolveNodeURN

func ResolveNodeURN(cmd *cobra.Command, client graphql.Client, ref string) (string, error)

ResolveNodeURN turns a fully-qualified node URN into a node ID via Query.resolveUrn. Bare locs are rejected client-side with a usage error: node references always name the memory (same-loc collisions across memories made anything less ambiguous). A URN that resolves to a different entity kind is a usage error too.

func ResolveTextInput added in v0.3.0

func ResolveTextInput(flag, value, file string, stdin io.Reader) (string, error)

ResolveTextInput resolves a text field that may be supplied inline, from a file, or on stdin — the same convention the --content / --content-file / "-" flags already use, factored out so every write flag behaves identically.

flag is the user-facing flag name (e.g. "abstract"): the inline value comes from --<flag>, the file from --<flag>-file, and a sentinel value of "-" reads stdin. The inline value and the file are mutually exclusive. Callers that gate on cmd.Flags().Changed decide whether an empty result means "clear" (an explicit empty string) or "leave unset".

A paragraph-length field with backticks or newlines is hostile to inline shell quoting, so --<flag>-file / stdin are the ergonomic path (issue #38).

func ResolveUser added in v0.9.0

func ResolveUser(cmd *cobra.Command, client graphql.Client, ref string) (fields gen.UserFields, found bool, err error)

ResolveUser is ResolveUserID's underlying lookup, returning everything the resolution already read instead of just the id — both paths fetch the full UserFields, so a caller that also needs the user's current state (roles, handle) gets it without a second round trip.

found reports whether a user was actually matched. It is false only for the pass-through case described above, where an unmatched bare token is returned verbatim as a literal id and fields carries nothing but that Id — the caller decides whether that is enough to act on.

func ResolveUserExactly added in v0.9.0

func ResolveUserExactly(cmd *cobra.Command, client graphql.Client, ref string) (fields gen.UserFields, found bool, err error)

ResolveUserExactly is ResolveUser restricted to an EXACT identifier match.

ResolveUser deliberately falls back to a sole substring hit, which is right for additive operations (sharing a memory with "alic" when only "alice" matches is a convenience). It is wrong for a destructive global write: a typo would silently retarget a different account. Commands that overwrite or remove state should resolve through this instead, so a partial match is a usage error naming what it matched rather than a silent retarget.

The pass-through case is preserved: a bare token nothing matched is still returned verbatim as a literal id with found=false, so an explicit id the caller cannot read still works.

func ResolveUserID added in v0.9.0

func ResolveUserID(cmd *cobra.Command, client graphql.Client, ref string) (string, error)

ResolveUserID turns a user reference (id, email, handle, or an hrn:user:/urn:user: URN wrapping one of those) into a User ID — the form the server's user-keyed mutations accept today (there is no user-URN support yet, hadron-server#325). An id- or handle-shaped ref resolves via the uniform user(ref:) find-one first (one round trip, no paging); anything else — or a find-one miss — goes through users(filter: { query }), which is itself access-scoped to the caller. A bare token neither path can match is passed through verbatim as a literal id so an explicit id always works; an email/handle that matches nothing is a not-found error.

Shared by `access check` (resource authorization) and `memory share` (grantee), so both accept the same ref forms (hadron-cli#280).

func ValidateAgentURNPath added in v0.8.0

func ValidateAgentURNPath(flag, path string) error

ValidateAgentURNPath checks an agent slug path supplied as a partial URN component. Unlike a node loc, an agent path may include owner/author context; urn-lib-go owns those shape rules.

func ValidateOrgSlug added in v0.9.0

func ValidateOrgSlug(flag, slug string) error

ValidateOrgSlug checks an organization slug supplied on a create/rename flag. An org root must be a bare, dotted domain (no scheme prefix or colon) that also satisfies the shared slug rules — the shared urn-lib owns the policy (grammar-v2 / #692), so the CLI fails fast with the same rule the server enforces rather than surfacing a less actionable server error.

func ValidateURNPath added in v0.7.0

func ValidateURNPath(flag, path string) error

ValidateURNPath checks a colon-delimited node loc. A loc is a single hierarchy leaf whose atoms are separated by single colons.

func ValidateURNSlug added in v0.7.0

func ValidateURNSlug(flag, slug string) error

ValidateURNSlug checks a single URN slug atom supplied on a create/rename flag. The shared urn-lib owns the create-time slug policy.

func ValidateUserHandle added in v0.9.0

func ValidateUserHandle(flag, handle string) error

ValidateUserHandle checks a user handle supplied on a create/rename flag. A handle is a slug that must additionally be dot-free, so it stays disjoint from dotted org roots in the shared principal pool (#692). The shared urn-lib owns the policy.

func WhereDefaultColumnNote added in v0.14.0

func WhereDefaultColumnNote(where *gqltypes.NodeWhereInput, matched *int) string

WhereDefaultColumnNote returns the stderr note for the silent-zero case (#603), or "" when there is nothing to say.

`--where` reads the `properties` JSONB column unless a leaf names the other one, and a node's free-form envelope lives in `data`. A predicate aimed at `data` that omits "field" therefore matches nothing and returns a plain `0` — not an error, not an empty-with-caveat, just a zero, which reads as evidence that the corpus has none. Two people on this team published a conclusion off one within an hour of each other.

The note fires on exactly that shape: a predicate was given, NO leaf named a column, and the PREDICATE matched nothing. It costs nothing when there are matches, and nothing for an author who already passes "field" — so it targets the silent zero without nagging a correct caller.

`matched` is how many rows the PREDICATE matched, and it must NOT be the number of rows the caller ended up displaying. Those differ whenever something narrows the result after the predicate has run — `--offset` past the last row, or `node list`'s client-side `--seq-gt` — and there a count of zero says nothing about the column. Firing on it would tell a caller whose offset was too high to go and query `data`: a confident wrong answer about their data, which is the exact failure this note exists to prevent, pointed the other way. (@codex caught it on PR #604.)

It is a POINTER because "how many matched" is genuinely unanswerable on some paths, and a nil says so. `findNodes.total` would be the obvious source and is not usable — the server leaves it null even when rows match — so each caller decides from what it knows: the row count is the answer exactly when nothing narrowed the result after the predicate.

A NIL `matched` keeps the note SILENT, deliberately rather than defensively. The two failure modes are not symmetric: staying quiet leaves the caller with the bare zero they have today, while guessing leaves them with a note that may be false — and a warning that fires wrongly is how a reader learns to ignore the one that is right.

Types

type Factory

type Factory struct {
	IOStreams  *output.IOStreams
	HTTPClient *http.Client

	// Persistent flag values, bound by the root command.
	JSON       bool
	ServerFlag string
	AppFlag    string

	// Overridable for tests.
	ConfigFn     func() (*config.Config, error)
	TokenStoreFn func() store.Store
	// contains filtered or unexported fields
}

func NewFactory

func NewFactory() *Factory

func (*Factory) App

func (f *Factory) App() (string, error)

App resolves the App context — the --app flag, then the config default — shape-checked and canonicalized (CanonicalAppRef, #540): what comes back is an App id or hrn:app:<root>:<slug>, never a value the server would refuse as "not fully qualified" in its own words. Empty means no App context, which the server treats as fine.

func (*Factory) Config

func (f *Factory) Config() (*config.Config, error)

func (*Factory) GraphQLClient

func (f *Factory) GraphQLClient() (graphql.Client, error)

GraphQLClient returns an authenticated genqlient client, failing with the AuthRequired exit code when no credentials are present.

func (*Factory) NoteAgentNotInstalled added in v0.13.0

func (f *Factory) NoteAgentNotInstalled(agentRef string)

NoteAgentNotInstalled says on stderr that a freshly-created agent is in no App's cast pool yet (#535). "✓ created" reads as done, but an agent that is not installed anywhere cannot be cast as a worker — and the failure surfaces later, at `team worker cast`, as WORKER_AGENT_NOT_FOUND, which points at the role rather than at the missing install.

Stderr, so the --json stdout contract is untouched; and only when --install-into was NOT passed, since having done the install is the answer.

func (*Factory) NoteAppIsContextOnly added in v0.9.0

func (f *Factory) NoteAppIsContextOnly(scope string)

NoteAppIsContextOnly warns on stderr that an explicitly-passed --app did NOT scope this listing (#383). `--app` is the persistent App-CONTEXT flag, not a filter, so `agent list --app <A>` returns the same rows for every <A> — which is how an agent installed only in another org's App came to be printed as though it were on this team.

Only the explicit flag triggers the note: a configured default App is ambient context nobody passed expecting a filter, so noting it on every invocation would be pure noise. Stderr keeps the --json stdout contract untouched.

func (*Factory) PublicGraphQLClient added in v0.9.0

func (f *Factory) PublicGraphQLClient() (client graphql.Client, authenticated bool, err error)

PublicGraphQLClient returns a client for the server's PUBLIC surface. It attaches credentials when they exist but does NOT require them, so a query the server serves anonymously still works when signed out.

authenticated reports whether credentials were attached — a caller can then say which surface the answer came from instead of implying it was privileged. A corrupt token store still errors rather than silently degrading to anonymous (#125): failing loud beats a confusing half-answer.

func (*Factory) Server

func (f *Factory) Server() (string, error)

Server resolves the server base URL: --server flag, then HADRON_SERVER env, then config, then the hosted default.

func (*Factory) Token

func (f *Factory) Token() (string, auth.TokenSource, error)

Token returns the active token and its source for the resolved server ("" source when unauthenticated). HADRON_TOKEN is checked before the token store so CI never triggers a keyring probe.

func (*Factory) TokenStore

func (f *Factory) TokenStore() store.Store

Jump to

Keyboard shortcuts

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