gleamunison/cli_lifecycle
Where a store lives, whether a run trusts it, and which branch it reads.
Three decisions belong here rather than scattered across commands: the store directory (an override for tests, CI, and running an artifact from anywhere), whether unverified content may execute, and which branch a session or command is bound to. All three are resolved through the live configuration layer and passed in as data.
Types
The --store/--branch tail every store-scoped command shares, as data.
branch is a plain accumulator with the caller’s default already in it,
so a command needs exactly one parser no matter where --branch appears
— cli_pkg used to grow a second parser (parse_args_with_branch) solely
because branch was kept out of the accumulator, and that second parser
then forgot flags the first one knew.
pub type FlagTail {
FlagTail(store: option.Option(String), branch: String)
}
Constructors
-
FlagTail(store: option.Option(String), branch: String)
What the head of an argument list is, to the shared tail.
pub type FlagTake {
Taken(tail: FlagTail, rest: List(String))
MissingValue(flag: String)
NotTailFlag
}
Constructors
-
Taken(tail: FlagTail, rest: List(String))A
--store/--branchflag and its value were consumed. -
MissingValue(flag: String)One of those flags is present but its value is missing. The caller builds the error from its own usage() via missing_store_value / missing_branch_value above, so wording and exit code stay owned here.
-
NotTailFlagThe head is something else: a positional, a command’s own flag, or an unknown argument. The caller decides which.
pub type StoreContext {
StoreContext(
store_path: String,
manifest_path: String,
root_dir: String,
)
}
Constructors
-
StoreContext( store_path: String, manifest_path: String, root_dir: String, )
Values
pub const default_branch: String
The branch a store-scoped command runs against when --branch is absent.
The commands that peel --store/--branch take their default from here
instead of declaring their own “main”, so the default cannot drift between
them.
Two look-alikes deliberately stay where they are: cli_publish.publish_branch
is where publish records its entries — a decision of its own that happens to
share the name — and run_ref.default_branch is public surface the
branch-scope tests read.
pub fn default_store_dir() -> String
pub fn manifest_path(context: StoreContext) -> String
pub fn missing_branch_value(usage: String) -> #(Int, String)
--branch given with no name after it. Same two commands, same exceptions.
pub fn missing_store_value(usage: String) -> #(Int, String)
--store given with no path after it. purge and unpublish refuse with
exactly these bytes and this exit code, so the wording lives here rather
than in two files that could drift apart.
cli_run delegates its tail spelling to take_flag below but keeps its own missing-value bytes, because its errors carry the “run: “ prefix users have always seen. pkg’s publish subcommand has its own –name/–version grammar, and sync’s –branch is an Option (absent means “pull no branch”) rather than a defaulted name. Folding those in would mean parameterising the message, the error type and the precedence: more machinery than the four lines it would save.
pub fn resolve_allow_unverified() -> Result(Bool, String)
The escape hatch: GLEAMUNISON_STORE_ALLOW_UNVERIFIED=1 lets a run execute
content whose evidence does not verify. Absent means verify; a malformed
configuration is an error rather than a silent default.
pub fn resolve_branch() -> Result(String, String)
The branch a session or command is bound to: GLEAMUNISON_BRANCH through
the CLI > TOML > env precedence, else default_branch. This lived in
mcp_session, which made the refresh path and the hand-written HTTP routes
depend on a 443-line session module for a pure configuration decision.
pub fn resolve_context(
store_override: option.Option(String),
) -> Result(StoreContext, String)
Resolve all sibling paths from one selected store file. Commands with a
--store flag pass that path here; other commands pass None and use the
configured/default directory. The context keeps DETS, manifests, and logs
on one boundary instead of letting each command choose a root independently.
pub fn resolve_store_dir() -> Result(String, String)
The store directory: GLEAMUNISON_STORE_DIR when set, else .gleamunison.
A relative override is refused rather than guessed at — a store resolved
against the wrong working directory looks empty, and an empty store reads
as “your definition was never published”.
pub fn resolve_store_path() -> Result(String, String)
The store file inside the environment-resolved directory.
pub fn root_dir(context: StoreContext) -> String
pub fn store_path(context: StoreContext) -> String
pub fn take_flag(args: List(String), tail: FlagTail) -> FlagTake
Consume one --store/--branch flag (with its value) from the head of
args. This owns the spelling of the shared tail; each command keeps its
own positionals and extra flags, which is why grammars that genuinely
differ (cli_find’s multi-word query) stay hand-rolled.