Skip to main content

oino/cli/
help.rs

1//! `printHelp` (D13): product name, `~/.oino`, `OINO_*`
2//! variables; provider variables, MCP and codemode lines are gone (providers are
3//! extensions, deviations/modes.md).
4
5use std::fmt::Write as _;
6
7use oino_core::extensions::api::{FlagSpec, FlagType};
8
9/// Extension flag with the extension that registered it.
10#[derive(Clone, Debug, PartialEq)]
11pub struct ExtensionFlag {
12    /// Registering extension (path/id).
13    pub extension_path: String,
14    /// The flag.
15    pub flag: FlagSpec,
16}
17
18const OPTIONS: &str = r#"Usage:
19  oino [options] [--] [@files...] [messages...]
20
21Commands:
22  oino install <source> [-l] [-y] Install an extension package (dir, archive, URL, git+https)
23  oino remove <id> [-l]          Remove an installed extension package
24  oino uninstall <id> [-l]       Alias for remove
25  oino update [--check]          Update Oino itself from the latest release
26  oino update <id>|--extensions  Re-install extension packages from their recorded source
27  oino list                      List distribution, installed and project extension packages
28  oino config                    Print the settings.json paths
29  oino auth <command>            Print credentials or check provider readiness
30  oino serve                     Serve sessions to remote clients
31  oino <command> --help          Show help for install/remove/uninstall/update/list/config/auth
32
33Options:
34  --provider <name>              Provider to search for --model (requires --model)
35  --model <pattern>              Model pattern or ID (supports "provider/id" and optional ":<thinking>")
36  --api-key <key>                API key (defaults to env vars)
37  --system-prompt <text>         System prompt (default: coding assistant prompt)
38  --append-system-prompt <text>  Append text or file contents to the system prompt (can be used multiple times)
39  --mode <mode>                  Output mode: text (default), json, rpc, or acp
40  --print, -p                    Non-interactive mode: process prompt and exit
41  --continue, -c                 Continue previous session
42  --resume, -r                   Select a session to resume
43  --session <path|id>            Use specific session file or partial UUID
44  --session-id <id>              Use exact project session ID, creating it if missing
45  --fork <path|id>               Fork specific session file or partial UUID into a new session
46  --session-dir <dir>            Directory for session storage and lookup
47  --no-session                   Don't save session (ephemeral)
48  --name, -n <name>              Set session display name
49  --models <patterns>            Comma-separated model patterns for Ctrl+P cycling
50                                 Supports globs (anthropic/*, *sonnet*) and fuzzy matching
51  --no-tools, -nt                Disable all tools by default (built-in and extension)
52  --no-builtin-tools, -nbt       Disable built-in tools by default but keep extension/custom tools enabled
53  --tools, -t <tools>            Comma-separated allowlist of tool names or patterns (*) to enable
54                                 Only +name/-name entries add to or remove from the defaults
55  --exclude-tools, -xt <tools>   Comma-separated denylist of tool names or patterns (*) to disable
56  --thinking <level>             Set thinking level: off, minimal, low, medium, high, xhigh, max
57  --extension, -e <path>         Load an extension file or builtin:<name> (can be used multiple times)
58  --no-extensions, -ne           Disable extension discovery and built-in extensions (explicit -e paths still work)
59  --exclude-extension <id>       Exclude an extension or provider package by id for this run (repeatable,
60                                 comma-separated; e.g. --exclude-extension acme.notify,oino.anthropic)
61  --skill <path>                 Load a skill file or directory (can be used multiple times)
62  --no-skills, -ns               Disable skills discovery and loading
63  --prompt-template <path>       Load a prompt template file or directory (can be used multiple times)
64  --no-prompt-templates, -np     Disable prompt template discovery and loading
65  --theme <path>                 Load a theme file or directory (can be used multiple times)
66  --use-theme <name[/name]>      Set the initial interactive theme for this run
67  --no-themes                    Disable theme discovery and loading
68  --no-context-files, -nc        Disable AGENTS.md and CLAUDE.md discovery and loading
69  --export <file>                Export session file to HTML and exit
70  --list-models [search]         List available models (with optional fuzzy search)
71  --verbose                      Force verbose startup (overrides quietStartup setting)
72  --tui-mode <mode>              TUI mode: fullscreen (default) or regular
73  --approve, -a                  Trust project-local files for this run
74  --no-approve, -na              Ignore project-local files for this run
75  --offline                      Disable startup network operations (same as OINO_OFFLINE=1)
76  --remote <url>                 Interactive mode over a remote session (oino://host:port?token=…)
77  --agent-dir <dir>              Config directory (same as OINO_AGENT_DIR)
78  --                             End option parsing; treat remaining arguments as messages/files
79  --help, -h                     Show this help
80  --version, -v                  Show version number
81
82Extensions can register additional flags (e.g., --plan from plan-mode extension)."#;
83
84const EXAMPLES: &str = r#"
85
86Examples:
87  # Interactive mode
88  oino
89
90  # Interactive mode with initial prompt
91  oino "List all .ts files in src/"
92
93  # Include files in initial message
94  oino @prompt.md @image.png "What color is the sky?"
95
96  # Non-interactive mode (process and exit)
97  oino -p "List all .ts files in src/"
98
99  # Prompt beginning with a dash
100  oino -p -- "- Summarize these points"
101
102  # Multiple messages (interactive)
103  oino "Read package.json" "What dependencies do we have?"
104
105  # Continue previous session
106  oino --continue "What did we discuss?"
107
108  # Start a named session
109  oino --name "Refactor auth module"
110
111  # Use different model
112  oino --provider openai --model gpt-4o-mini "Help me refactor this code"
113
114  # Use model with provider prefix (no --provider needed)
115  oino --model openai/gpt-4o "Help me refactor this code"
116
117  # Use model with thinking level shorthand
118  oino --model sonnet:high "Solve this complex problem"
119
120  # Limit model cycling to specific models
121  oino --models claude-sonnet,claude-haiku,gpt-4o
122
123  # Limit to a specific provider with glob pattern
124  oino --models "github-copilot/*"
125
126  # Cycle models with fixed thinking levels
127  oino --models sonnet:high,haiku:low
128
129  # Start with a specific thinking level
130  oino --thinking high "Solve this complex problem"
131
132  # Read-only mode (no file modifications possible)
133  oino --tools read,grep,find,ls -p "Review the code in src/"
134
135  # Disable one tool while keeping the rest available
136  oino --exclude-tools ask_question
137
138  # Exclude one extension package for this run
139  oino --exclude-extension acme.notify -p "Summarize src/"
140
141  # Export a session file to HTML
142  oino --export ~/.oino/sessions/--path--/session.jsonl
143  oino --export session.jsonl output.html
144
145Environment Variables:
146  OINO_AGENT_DIR                   - Config directory (default: ~/.oino)
147  OINO_SESSION_DIR                 - Session storage directory (overridden by --session-dir)
148  OINO_OFFLINE                     - Disable startup network operations when set to 1/true/yes
149  OINO_CACHE_RETENTION             - Prompt cache retention (none, short, long)
150
151Built-in Tool Names:
152  read       - Read file contents
153  bash       - Execute bash commands
154  powershell - Execute PowerShell commands on Windows
155  edit       - Edit files with find/replace
156  write      - Write files (creates/overwrites)
157  grep       - Search file contents (read-only, off by default)
158  find       - Find files by glob pattern (read-only, off by default)
159  ls         - List directory contents (read-only, off by default)
160"#;
161
162/// `printHelp(extensionFlags)` text.
163#[must_use]
164pub fn help_text(extension_flags: &[ExtensionFlag]) -> String {
165    let mut text =
166        String::from("oino - AI coding assistant with read, bash, edit, write tools\n\n");
167    text.push_str(OPTIONS);
168    if !extension_flags.is_empty() {
169        text.push_str("\nExtension CLI Flags:\n");
170        for ExtensionFlag {
171            extension_path,
172            flag,
173        } in extension_flags
174        {
175            let value = if flag.kind == FlagType::String {
176                " <value>"
177            } else {
178                ""
179            };
180            let description = if flag.description.is_empty() {
181                format!("Registered by {extension_path}")
182            } else {
183                flag.description.clone()
184            };
185            let left = format!("  --{}{value}", flag.name);
186            let _ = writeln!(text, "{left:<30}{description}");
187        }
188    }
189    text.push_str(EXAMPLES);
190    // `console.log` adds the final newline after the template's own.
191    text.push('\n');
192    text
193}
194
195#[cfg(test)]
196mod tests {
197    use super::*;
198
199    #[test]
200    fn lists_extension_flags_padded() {
201        let text = help_text(&[ExtensionFlag {
202            extension_path: "ext.plan".into(),
203            flag: FlagSpec {
204                name: "plan".into(),
205                kind: FlagType::Boolean,
206                default: None,
207                description: String::new(),
208            },
209        }]);
210        let expected = format!(
211            "extension).\nExtension CLI Flags:\n{:<30}Registered by ext.plan\n\n\nExamples:",
212            "  --plan"
213        );
214        assert!(text.contains(&expected), "{text}");
215        assert!(help_text(&[]).contains("extension).\n\nExamples:"));
216        assert!(help_text(&[]).starts_with("oino - AI coding assistant"));
217    }
218}