Skip to main content

agent_id_cli/
cli.rs

1use crate::activity::ActivityStateValue;
2
3use clap::{Args, Command, CommandFactory, Parser, Subcommand};
4
5#[derive(Debug, Parser)]
6#[command(
7    name = "agent-id",
8    version,
9    about = "Portable identity registry for coding-agent sessions",
10    long_about = "agent-id assigns permanent human-readable names to stable agent-harness session IDs."
11)]
12pub struct Cli {
13    #[command(subcommand)]
14    pub command: Commands,
15}
16
17#[derive(Debug, Subcommand)]
18pub enum Commands {
19    /// Register a new permanent identity for a session
20    Register(RegisterArgs),
21    /// Look up the identity already registered for a session
22    Lookup(LookupArgs),
23    /// Set or clear the current-work summary for a registered session
24    Annotate(AnnotateArgs),
25    /// List recent identity assignments
26    Discover(DiscoverArgs),
27    /// Remove identity assignments older than a cutoff
28    Prune(PruneArgs),
29    /// Output the agent-facing identity workflow manual
30    Prime(PrimeArgs),
31}
32
33#[derive(Debug, Args)]
34pub struct RegisterArgs {
35    /// Harness session ID; falls back to AGENT_ID_SESSION_ID
36    #[arg(value_name = "SESSION_ID", conflicts_with = "session_id")]
37    pub session: Option<String>,
38
39    /// Explicit harness session ID
40    #[arg(long = "session-id", value_name = "ID")]
41    pub session_id: Option<String>,
42
43    /// Prefer this family name when allocating the identity
44    #[arg(long, value_name = "NAME")]
45    pub family: Option<String>,
46
47    /// Computer realm; falls back to AGENT_REALM or config
48    #[arg(long, value_name = "NAME")]
49    pub realm: Option<String>,
50
51    /// Print the complete assignment as JSON
52    #[arg(long)]
53    pub json: bool,
54}
55
56impl RegisterArgs {
57    pub fn explicit_session(&self) -> Option<&str> {
58        self.session.as_deref().or(self.session_id.as_deref())
59    }
60}
61
62#[derive(Debug, Args)]
63pub struct LookupArgs {
64    /// Session ID, canonical name, or slug; falls back to AGENT_ID_SESSION_ID
65    #[arg(value_name = "IDENTIFIER", conflicts_with = "session_id")]
66    pub input: Option<String>,
67
68    /// Explicit session ID
69    #[arg(long = "session-id", value_name = "ID")]
70    pub session_id: Option<String>,
71
72    /// Print the complete assignment as JSON
73    #[arg(long)]
74    pub json: bool,
75}
76
77impl LookupArgs {
78    pub fn explicit_input(&self) -> Option<&str> {
79        self.input.as_deref().or(self.session_id.as_deref())
80    }
81}
82
83#[derive(Debug, Args)]
84pub struct AnnotateArgs {
85    /// Harness session ID; falls back to AGENT_ID_SESSION_ID
86    #[arg(value_name = "SESSION_ID", conflicts_with = "session_id")]
87    pub session: Option<String>,
88
89    /// Explicit harness session ID
90    #[arg(long = "session-id", value_name = "ID")]
91    pub session_id: Option<String>,
92
93    /// Set the concise current-work summary
94    #[arg(long, value_name = "TEXT", conflicts_with = "clear_summary")]
95    pub summary: Option<String>,
96
97    /// Remove the current-work summary
98    #[arg(long, conflicts_with = "summary")]
99    pub clear_summary: bool,
100
101    /// Set the activity state
102    #[arg(long, value_name = "VALUE", conflicts_with = "clear_state")]
103    pub state: Option<ActivityStateValue>,
104
105    /// Remove the activity state
106    #[arg(long, conflicts_with = "state")]
107    pub clear_state: bool,
108
109    /// Set the current working directory
110    #[arg(long, value_name = "PATH", conflicts_with = "clear_cwd")]
111    pub cwd: Option<String>,
112
113    /// Remove the current working directory
114    #[arg(long, conflicts_with = "cwd")]
115    pub clear_cwd: bool,
116
117    /// Print the complete assignment as JSON
118    #[arg(long)]
119    pub json: bool,
120}
121
122impl AnnotateArgs {
123    pub fn explicit_session(&self) -> Option<&str> {
124        self.session.as_deref().or(self.session_id.as_deref())
125    }
126}
127
128#[derive(Debug, Args)]
129pub struct DiscoverArgs {
130    /// Maximum records to print; zero prints all records
131    #[arg(long, default_value_t = 20)]
132    pub limit: usize,
133
134    /// Only include records updated within this many hours
135    #[arg(long, value_name = "HOURS")]
136    pub recent: Option<i64>,
137
138    /// Only include records in this realm
139    #[arg(long, value_name = "NAME")]
140    pub realm: Option<String>,
141
142    /// Print the complete assignments as JSON
143    #[arg(long)]
144    pub json: bool,
145}
146
147#[derive(Debug, Args)]
148pub struct PruneArgs {
149    /// Remove records with updated_at before this RFC 3339 timestamp
150    #[arg(long, value_name = "TIMESTAMP", required = true)]
151    pub before: String,
152
153    /// Preview matching records without deleting them
154    #[arg(long)]
155    pub dry_run: bool,
156
157    /// Print the prune report as JSON
158    #[arg(long)]
159    pub json: bool,
160}
161
162#[derive(Debug, Args)]
163#[command(about = "Output the agent-facing identity workflow manual")]
164pub struct PrimeArgs {
165    /// Output only the workflow prelude
166    #[arg(long)]
167    pub prelude: bool,
168
169    /// Wrap the documentation in a JSON object
170    #[arg(long)]
171    pub json: bool,
172}
173
174pub fn build_cli() -> Command {
175    Cli::command()
176}