Skip to main content

gloamy/
lib.rs

1#![warn(clippy::all)]
2#![allow(
3    clippy::assigning_clones,
4    clippy::await_holding_lock,
5    clippy::bool_to_int_with_if,
6    clippy::case_sensitive_file_extension_comparisons,
7    clippy::cast_possible_truncation,
8    clippy::cast_sign_loss,
9    clippy::cast_possible_wrap,
10    clippy::doc_markdown,
11    clippy::collapsible_if,
12    clippy::collapsible_str_replace,
13    clippy::derivable_impls,
14    clippy::field_reassign_with_default,
15    clippy::float_cmp,
16    clippy::format_collect,
17    clippy::format_push_string,
18    clippy::if_not_else,
19    clippy::ignore_without_reason,
20    clippy::implicit_clone,
21    clippy::incompatible_msrv,
22    clippy::items_after_statements,
23    clippy::large_futures,
24    clippy::manual_pattern_char_comparison,
25    clippy::manual_string_new,
26    clippy::manual_unwrap_or_default,
27    clippy::map_unwrap_or,
28    clippy::match_same_arms,
29    clippy::match_wildcard_for_single_variants,
30    clippy::manual_let_else,
31    clippy::missing_errors_doc,
32    clippy::missing_panics_doc,
33    clippy::module_name_repetitions,
34    clippy::must_use_candidate,
35    clippy::needless_borrow,
36    clippy::needless_return,
37    clippy::new_ret_no_self,
38    clippy::new_without_default,
39    clippy::needless_pass_by_value,
40    clippy::needless_raw_string_hashes,
41    clippy::question_mark,
42    clippy::ref_option,
43    clippy::redundant_closure_for_method_calls,
44    clippy::return_self_not_must_use,
45    clippy::similar_names,
46    clippy::single_match_else,
47    clippy::struct_excessive_bools,
48    clippy::struct_field_names,
49    clippy::too_many_lines,
50    clippy::type_complexity,
51    clippy::uninlined_format_args,
52    clippy::unreadable_literal,
53    clippy::unnecessary_cast,
54    clippy::unnecessary_lazy_evaluations,
55    clippy::unnecessary_literal_bound,
56    clippy::unnecessary_map_or,
57    clippy::unused_async,
58    clippy::used_underscore_binding,
59    clippy::unused_self,
60    clippy::cast_precision_loss,
61    clippy::unnecessary_wraps,
62    dead_code
63)]
64
65use clap::Subcommand;
66use serde::{Deserialize, Serialize};
67
68pub mod agent;
69pub(crate) mod approval;
70pub(crate) mod auth;
71pub mod channels;
72pub mod config;
73pub(crate) mod cost;
74pub(crate) mod cron;
75pub(crate) mod daemon;
76pub(crate) mod doctor;
77pub mod gateway;
78pub mod grounding;
79pub(crate) mod hardware;
80pub(crate) mod health;
81pub(crate) mod heartbeat;
82pub mod hooks;
83pub(crate) mod identity;
84pub(crate) mod integrations;
85pub mod memory;
86pub(crate) mod migration;
87pub(crate) mod multimodal;
88pub mod observability;
89pub(crate) mod onboard;
90pub mod perception;
91pub mod peripherals;
92pub mod providers;
93pub mod rag;
94pub mod runtime;
95pub(crate) mod security;
96pub(crate) mod service;
97pub(crate) mod skills;
98pub mod tools;
99pub(crate) mod tunnel;
100pub(crate) mod util;
101
102pub use config::Config;
103
104/// Service management subcommands
105#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
106pub enum ServiceCommands {
107    /// Install daemon service unit for auto-start and restart
108    Install,
109    /// Start daemon service
110    Start,
111    /// Stop daemon service
112    Stop,
113    /// Restart daemon service to apply latest config
114    Restart,
115    /// Check daemon service status
116    Status,
117    /// Uninstall daemon service unit
118    Uninstall,
119}
120
121/// Channel management subcommands
122#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
123pub enum ChannelCommands {
124    /// List all configured channels
125    List,
126    /// Start all configured channels (handled in main.rs for async)
127    Start,
128    /// Run health checks for configured channels (handled in main.rs for async)
129    Doctor,
130    /// Add a new channel configuration
131    #[command(long_about = "\
132Add a new channel configuration.
133
134Provide the channel type and a JSON object with the required \
135configuration keys for that channel type.
136
137Supported types: telegram, discord, slack, whatsapp, matrix, imessage, email.
138
139Examples:
140  gloamy channel add telegram '{\"bot_token\":\"...\",\"name\":\"my-bot\"}'
141  gloamy channel add discord '{\"bot_token\":\"...\",\"name\":\"my-discord\"}'")]
142    Add {
143        /// Channel type (telegram, discord, slack, whatsapp, matrix, imessage, email)
144        channel_type: String,
145        /// Optional configuration as JSON
146        config: String,
147    },
148    /// Remove a channel configuration
149    Remove {
150        /// Channel name to remove
151        name: String,
152    },
153    /// Bind a Telegram identity (username or numeric user ID) into allowlist
154    #[command(long_about = "\
155Bind a Telegram identity into the allowlist.
156
157Adds a Telegram username (without the '@' prefix) or numeric user \
158ID to the channel allowlist so the agent will respond to messages \
159from that identity.
160
161Examples:
162  gloamy channel bind-telegram gloamy_user
163  gloamy channel bind-telegram 123456789")]
164    BindTelegram {
165        /// Telegram identity to allow (username without '@' or numeric user ID)
166        identity: String,
167    },
168}
169
170/// Skills management subcommands
171#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
172pub enum SkillCommands {
173    /// List all installed skills
174    List,
175    /// Audit a skill source directory or installed skill name
176    Audit {
177        /// Skill path or installed skill name
178        source: String,
179    },
180    /// Install a new skill from a URL or local path
181    Install {
182        /// Source URL or local path
183        source: String,
184    },
185    /// Remove an installed skill
186    Remove {
187        /// Skill name to remove
188        name: String,
189    },
190}
191
192/// Migration subcommands
193#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
194pub enum MigrateCommands {
195    /// Import memory from an `OpenClaw` workspace into this `Gloamy` workspace
196    Openclaw {
197        /// Optional path to `OpenClaw` workspace (defaults to ~/.openclaw/workspace)
198        #[arg(long)]
199        source: Option<std::path::PathBuf>,
200
201        /// Validate and preview migration without writing any data
202        #[arg(long)]
203        dry_run: bool,
204    },
205}
206
207/// Cron subcommands
208#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
209pub enum CronCommands {
210    /// List all scheduled tasks
211    List,
212    /// Add a new scheduled task
213    #[command(long_about = "\
214Add a new recurring scheduled task.
215
216Uses standard 5-field cron syntax: 'min hour day month weekday'. \
217Times are evaluated in UTC by default; use --tz with an IANA \
218timezone name to override.
219
220Examples:
221  gloamy cron add '0 9 * * 1-5' 'Good morning' --tz America/New_York
222  gloamy cron add '*/30 * * * *' 'Check system health'")]
223    Add {
224        /// Cron expression
225        expression: String,
226        /// Optional IANA timezone (e.g. America/Los_Angeles)
227        #[arg(long)]
228        tz: Option<String>,
229        /// Command to run
230        command: String,
231    },
232    /// Add a one-shot scheduled task at an RFC3339 timestamp
233    #[command(long_about = "\
234Add a one-shot task that fires at a specific UTC timestamp.
235
236The timestamp must be in RFC 3339 format (e.g. 2025-01-15T14:00:00Z).
237
238Examples:
239  gloamy cron add-at 2025-01-15T14:00:00Z 'Send reminder'
240  gloamy cron add-at 2025-12-31T23:59:00Z 'Happy New Year!'")]
241    AddAt {
242        /// One-shot timestamp in RFC3339 format
243        at: String,
244        /// Command to run
245        command: String,
246    },
247    /// Add a fixed-interval scheduled task
248    #[command(long_about = "\
249Add a task that repeats at a fixed interval.
250
251Interval is specified in milliseconds. For example, 60000 = 1 minute.
252
253Examples:
254  gloamy cron add-every 60000 'Ping heartbeat'     # every minute
255  gloamy cron add-every 3600000 'Hourly report'    # every hour")]
256    AddEvery {
257        /// Interval in milliseconds
258        every_ms: u64,
259        /// Command to run
260        command: String,
261    },
262    /// Add a one-shot delayed task (e.g. "30m", "2h", "1d")
263    #[command(long_about = "\
264Add a one-shot task that fires after a delay from now.
265
266Accepts human-readable durations: s (seconds), m (minutes), \
267h (hours), d (days).
268
269Examples:
270  gloamy cron once 30m 'Run backup in 30 minutes'
271  gloamy cron once 2h 'Follow up on deployment'
272  gloamy cron once 1d 'Daily check'")]
273    Once {
274        /// Delay duration
275        delay: String,
276        /// Command to run
277        command: String,
278    },
279    /// Remove a scheduled task
280    Remove {
281        /// Task ID
282        id: String,
283    },
284    /// Update a scheduled task
285    #[command(long_about = "\
286Update one or more fields of an existing scheduled task.
287
288Only the fields you specify are changed; others remain unchanged.
289
290Examples:
291  gloamy cron update <task-id> --expression '0 8 * * *'
292  gloamy cron update <task-id> --tz Europe/London --name 'Morning check'
293  gloamy cron update <task-id> --command 'Updated message'")]
294    Update {
295        /// Task ID
296        id: String,
297        /// New cron expression
298        #[arg(long)]
299        expression: Option<String>,
300        /// New IANA timezone
301        #[arg(long)]
302        tz: Option<String>,
303        /// New command to run
304        #[arg(long)]
305        command: Option<String>,
306        /// New job name
307        #[arg(long)]
308        name: Option<String>,
309    },
310    /// Pause a scheduled task
311    Pause {
312        /// Task ID
313        id: String,
314    },
315    /// Resume a paused task
316    Resume {
317        /// Task ID
318        id: String,
319    },
320}
321
322/// Memory management subcommands
323#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
324pub enum MemoryCommands {
325    /// List memory entries with optional filters
326    List {
327        /// Filter by category (core, daily, conversation, or custom name)
328        #[arg(long)]
329        category: Option<String>,
330        /// Filter by session ID
331        #[arg(long)]
332        session: Option<String>,
333        /// Maximum number of entries to display
334        #[arg(long, default_value = "50")]
335        limit: usize,
336        /// Number of entries to skip (for pagination)
337        #[arg(long, default_value = "0")]
338        offset: usize,
339    },
340    /// Get a specific memory entry by key
341    Get {
342        /// Memory key to look up
343        key: String,
344    },
345    /// Show memory backend statistics and health
346    Stats,
347    /// Clear memories by category, by key, or clear all
348    Clear {
349        /// Delete a single entry by key (supports prefix match)
350        #[arg(long)]
351        key: Option<String>,
352        /// Only clear entries in this category
353        #[arg(long)]
354        category: Option<String>,
355        /// Skip confirmation prompt
356        #[arg(long)]
357        yes: bool,
358    },
359}
360
361/// Integration subcommands
362#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
363pub enum IntegrationCommands {
364    /// Show details about a specific integration
365    Info {
366        /// Integration name
367        name: String,
368    },
369}
370
371/// Hardware discovery subcommands
372#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
373pub enum HardwareCommands {
374    /// Enumerate USB devices (VID/PID) and show known boards
375    #[command(long_about = "\
376Enumerate USB devices and show known boards.
377
378Scans connected USB devices by VID/PID and matches them against \
379known development boards (STM32 Nucleo, Arduino, ESP32).
380
381Examples:
382  gloamy hardware discover")]
383    Discover,
384    /// Introspect a device by path (e.g. /dev/ttyACM0)
385    #[command(long_about = "\
386Introspect a device by its serial or device path.
387
388Opens the specified device path and queries for board information, \
389firmware version, and supported capabilities.
390
391Examples:
392  gloamy hardware introspect /dev/ttyACM0
393  gloamy hardware introspect COM3")]
394    Introspect {
395        /// Serial or device path
396        path: String,
397    },
398    /// Get chip info via USB (probe-rs over ST-Link). No firmware needed on target.
399    #[command(long_about = "\
400Get chip info via USB using probe-rs over ST-Link.
401
402Queries the target MCU directly through the debug probe without \
403requiring any firmware on the target board.
404
405Examples:
406  gloamy hardware info
407  gloamy hardware info --chip STM32F401RETx")]
408    Info {
409        /// Chip name (e.g. STM32F401RETx). Default: STM32F401RETx for Nucleo-F401RE
410        #[arg(long, default_value = "STM32F401RETx")]
411        chip: String,
412    },
413}
414
415/// Peripheral (hardware) management subcommands
416#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
417pub enum PeripheralCommands {
418    /// List configured peripherals
419    List,
420    /// Add a peripheral (board path, e.g. nucleo-f401re /dev/ttyACM0)
421    #[command(long_about = "\
422Add a peripheral by board type and transport path.
423
424Registers a hardware board so the agent can use its tools (GPIO, \
425sensors, actuators). Use 'native' as path for local GPIO on \
426single-board computers like Raspberry Pi.
427
428Supported boards: nucleo-f401re, rpi-gpio, esp32, arduino-uno.
429
430Examples:
431  gloamy peripheral add nucleo-f401re /dev/ttyACM0
432  gloamy peripheral add rpi-gpio native
433  gloamy peripheral add esp32 /dev/ttyUSB0")]
434    Add {
435        /// Board type (nucleo-f401re, rpi-gpio, esp32)
436        board: String,
437        /// Path for serial transport (/dev/ttyACM0) or "native" for local GPIO
438        path: String,
439    },
440    /// Flash Gloamy firmware to Arduino (creates .ino, installs arduino-cli if needed, uploads)
441    #[command(long_about = "\
442Flash Gloamy firmware to an Arduino board.
443
444Generates the .ino sketch, installs arduino-cli if it is not \
445already available, compiles, and uploads the firmware.
446
447Examples:
448  gloamy peripheral flash
449  gloamy peripheral flash --port /dev/cu.usbmodem12345
450  gloamy peripheral flash -p COM3")]
451    Flash {
452        /// Serial port (e.g. /dev/cu.usbmodem12345). If omitted, uses first arduino-uno from config.
453        #[arg(short, long)]
454        port: Option<String>,
455    },
456    /// Setup Arduino Uno Q Bridge app (deploy GPIO bridge for agent control)
457    SetupUnoQ {
458        /// Uno Q IP (e.g. 192.168.0.48). If omitted, assumes running ON the Uno Q.
459        #[arg(long)]
460        host: Option<String>,
461    },
462    /// Flash Gloamy firmware to Nucleo-F401RE (builds + probe-rs run)
463    FlashNucleo,
464}