1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//! Universal `config` clap module (issue #2404, epic #2400 Wave 1).
//!
//! Why: every trusty-* binary that talks to an inference provider needs the
//! SAME credential-management CLI — set a provider's key, list which providers
//! are configured (and via which tier), probe a key with a cheap live auth
//! check, and remove a key. Before this module each binary would grow its own
//! divergent `config`/`keys` handling. This is the one implementation ALL ten
//! clap binaries mount identically (#2405 does the mounting); adding it to a new
//! binary is two lines and never diverges.
//!
//! What: [`ConfigCommand`] is a clap [`clap::Args`] a binary embeds as a single
//! variant of its own top-level subcommand enum. It nests a `<feature>`
//! subcommand ([`ConfigFeature`]) so the grammar is
//! `<bin> config <feature> <verb> …`; Wave 1 ships the `keys` feature
//! ([`keys::KeysCommand`]) with `set` / `list` / `test` / `unset`. The
//! operations themselves live in the injectable [`ops`] seam so they are 100%
//! testable without a TTY or a live provider. [`ConfigCommand::run`] resolves its
//! own secure [`crate::inference::credentials::KeyStore`] and
//! [`crate::inference::Configurator`], so a mounting binary needs no wiring.
//!
//! # Mount recipe for #2405 (the entire integration — two lines)
//!
//! Add the variant to your binary's top-level clap enum:
//!
//! ```ignore
//! use trusty_common::inference::config::ConfigCommand;
//!
//! #[derive(clap::Subcommand)]
//! enum Commands {
//! // … your existing subcommands …
//! /// Manage inference provider configuration (API keys).
//! Config(ConfigCommand), // line 1: mount
//! }
//! ```
//!
//! Then dispatch it (inside your `#[tokio::main]` async entry point):
//!
//! ```ignore
//! match cli.command {
//! // … your existing arms …
//! Commands::Config(cmd) => cmd.run().await?, // line 2: dispatch
//! }
//! ```
//!
//! Adding a future `config <feature>` (e.g. `config model …`) is a new
//! [`ConfigFeature`] variant here — mount sites do not change (the
//! extensibility contract in the acceptance criteria).
//!
//! # Mount recipe for a binary that already owns `config` (#2405)
//!
//! trusty-search (`config get/set memory-limit`, daemon runtime config) and
//! trusty-installer (`config <members>`, stack-member config) each already
//! have a top-level `config` command in a DIFFERENT domain. Mounting the
//! whole-grammar [`ConfigCommand`] there would collide with their existing
//! verb, so nest just the credential feature — [`ConfigKeysCommand`] (a public
//! alias of [`keys::KeysCommand`]) — as a new variant under your EXISTING
//! `config` subcommand enum instead:
//!
//! ```ignore
//! use trusty_common::inference::config::ConfigKeysCommand;
//!
//! #[derive(clap::Subcommand)]
//! enum ConfigAction {
//! // … your existing verbs (Get, Set, …) …
//! /// Manage inference provider API keys (set / list / test / unset).
//! Keys(ConfigKeysCommand), // line 1: mount
//! }
//! ```
//!
//! ```ignore
//! match action {
//! // … your existing arms …
//! ConfigAction::Keys(cmd) => cmd.run().await?, // line 2: dispatch
//! }
//! ```
//!
//! Same `config-cli` feature requirement as the whole-command recipe above.
//! Every other primary binary should prefer the whole-grammar [`ConfigCommand`]
//! recipe — this one exists solely for the pre-existing-`config` collision case.
//!
//! Enable the `config-cli` feature in the mounting binary's dependency on
//! `trusty-common`. It implies `inference-client`; a default (no-features)
//! `trusty-common` build compiles neither this module nor `clap`.
//!
//! Test: `ops` inline tests + `crates/trusty-common/tests/config_keys_cli.rs`
//! (argv parsing, set→list→test→unset flow, tier reporting, and the
//! never-print-a-value guarantee); the embeddable-`keys` mount path is
//! exercised by `crates/trusty-search/tests/config_mount.rs` and
//! `crates/trusty-installer/tests/config_mount.rs`.
use KeysCommand;
/// Public alias for [`keys::KeysCommand`] — the embeddable `keys` feature on
/// its own, for binaries that mount it directly (see the second mount recipe
/// above) instead of the whole-grammar [`ConfigCommand`].
///
/// Why: `crate::inference::config::keys::KeysCommand` is a mouthful and an
/// internal-looking path; this re-export at the module's public surface names
/// the type the way a mounting binary should reach for it, matching
/// [`ConfigCommand`]'s own re-export at [`crate::inference`].
/// What: identical type to [`keys::KeysCommand`] — clap `Args` wrapping the
/// `set`/`list`/`test`/`unset` verbs, with a `pub async fn run(self)`.
/// Test: covered transitively by `keys`' own tests; the embeddable-mount path
/// is exercised by `crates/trusty-search/tests/config_mount.rs` and
/// `crates/trusty-installer/tests/config_mount.rs` (#2405).
pub use KeysCommand as ConfigKeysCommand;
/// The universal `config` subcommand a binary mounts as one enum variant.
///
/// Why: one embeddable type is the whole public mount surface — a binary adds
/// `Config(ConfigCommand)` and calls [`Self::run`]; everything else (feature
/// routing, store/configurator resolution, secret redaction) is internal so the
/// mount is identical across binaries and cannot drift.
/// What: a clap [`clap::Args`] wrapping the `<feature>` subcommand. `run`
/// dispatches to the selected feature's own runner.
/// Test: `crates/trusty-common/tests/config_keys_cli.rs::config_command_mounts_and_parses`.
/// The `<feature>` layer of the `config` grammar.
///
/// Why: `config` is a namespace, not a single command — keys today, potentially
/// model/provider defaults later. Modelling the feature as its own subcommand
/// enum means a new feature is one variant added HERE with zero mount-site
/// churn.
/// What: Wave 1 exposes only [`Self::Keys`]. Each variant owns a feature command
/// type that implements its own verbs.
/// Test: `config_keys_argv_grammar_parses`.