1package agent
2
3import (
4 "fmt"
5 "os"
6 "strings"
7)
8
9// Mode is the CLI run mode.
10type Mode string
11
12const (
13 ModeInteractive Mode = "interactive"
14 ModePrint Mode = "print"
15 ModeJSON Mode = "json"
16 ModeRPC Mode = "rpc"
17)
18
19// Args holds parsed command-line options.
20type Args struct {
21 Mode Mode
22 Provider string
23 Model string
24 APIKey string
25
26 BaseURL string // override provider base URL (for tests/self-hosted)
27 SystemPrompt string
28 AppendSystemPrompt []string
29 Reasoning string
30
31 Continue bool
32 Resume bool
33 Session string
34 NoSess bool
35
36 CWD string
37 NoTools bool
38 Tools []string
39 MaxSteps int
40
41 // Exts is a list of directory paths the user passed via --ext.
42 // Each must contain an extension.json. Loaded for one session
43 // only; never persisted. Take precedence over installed exts of
44 // the same name.
45 Exts []string
46
47 ListModels bool
48 Help bool
49 Version bool
50
51 Prompt string // concatenated positional args
52}
53
54// ParseArgs parses the process arguments (excluding argv[0]).
55func ParseArgs(in []string) (Args, error) {
56 a := Args{Mode: ModeInteractive, MaxSteps: 50}
57 positional := []string{}
58
59 want := func(i *int, flag string) (string, error) {
60 *i++
61 if *i >= len(in) {
62 return "", fmt.Errorf("%s requires a value", flag)
63 }
64 return in[*i], nil
65 }
66
67 for i := 0; i < len(in); i++ {
68 arg := in[i]
69 switch arg {
70 case "-h", "--help":
71 a.Help = true
72 case "-v", "--version":
73 a.Version = true
74 case "-p", "--print":
75 a.Mode = ModePrint
76 case "--json":
77 a.Mode = ModeJSON
78 case "--rpc":
79 a.Mode = ModeRPC
80 case "-c", "--continue":
81 a.Continue = true
82 case "-r", "--resume":
83 a.Resume = true
84 case "--no-session":
85 a.NoSess = true
86 case "--no-tools":
87 a.NoTools = true
88 case "--list-models":
89 a.ListModels = true
90 case "--experimental-oauth":
91 // deprecated: subscription login is always available.
92 // accepted silently for backwards compatibility.
93 case "--provider":
94 v, err := want(&i, arg)
95 if err != nil {
96 return a, err
97 }
98 a.Provider = v
99 case "--model":
100 v, err := want(&i, arg)
101 if err != nil {
102 return a, err
103 }
104 a.Model = v
105 case "--api-key":
106 v, err := want(&i, arg)
107 if err != nil {
108 return a, err
109 }
110 a.APIKey = v
111 case "--base-url":
112 v, err := want(&i, arg)
113 if err != nil {
114 return a, err
115 }
116 a.BaseURL = v
117 case "--system-prompt":
118 v, err := want(&i, arg)
119 if err != nil {
120 return a, err
121 }
122 a.SystemPrompt = v
123 case "--append-system-prompt":
124 v, err := want(&i, arg)
125 if err != nil {
126 return a, err
127 }
128 a.AppendSystemPrompt = append(a.AppendSystemPrompt, v)
129 case "--ext", "-e":
130 v, err := want(&i, arg)
131 if err != nil {
132 return a, err
133 }
134 // Repeatable; each value is a directory containing an
135 // extension.json. Resolved to absolute later so paths like
136 // "." survive a later cwd change.
137 a.Exts = append(a.Exts, v)
138 case "--reasoning":
139 v, err := want(&i, arg)
140 if err != nil {
141 return a, err
142 }
143 switch strings.ToLower(v) {
144 case "", "low", "medium", "high":
145 a.Reasoning = strings.ToLower(v)
146 default:
147 return a, fmt.Errorf("--reasoning must be low|medium|high")
148 }
149 case "--session":
150 v, err := want(&i, arg)
151 if err != nil {
152 return a, err
153 }
154 a.Session = v
155 case "--cwd":
156 v, err := want(&i, arg)
157 if err != nil {
158 return a, err
159 }
160 a.CWD = v
161 case "--tools":
162 v, err := want(&i, arg)
163 if err != nil {
164 return a, err
165 }
166 for _, t := range strings.Split(v, ",") {
167 t = strings.TrimSpace(t)
168 if t != "" {
169 a.Tools = append(a.Tools, t)
170 }
171 }
172 case "--max-steps":
173 v, err := want(&i, arg)
174 if err != nil {
175 return a, err
176 }
177 var n int
178 if _, err := fmt.Sscanf(v, "%d", &n); err != nil || n <= 0 {
179 return a, fmt.Errorf("--max-steps must be a positive integer")
180 }
181 a.MaxSteps = n
182 default:
183 if strings.HasPrefix(arg, "-") && arg != "-" {
184 return a, fmt.Errorf("unknown flag %q", arg)
185 }
186 positional = append(positional, arg)
187 }
188 }
189
190 if len(positional) > 0 {
191 a.Prompt = strings.Join(positional, " ")
192 }
193
194 if a.CWD == "" {
195 a.CWD, _ = os.Getwd()
196 }
197 return a, nil
198}
199
200// PrintHelp writes the help text to w (stderr by default).
201func PrintHelp(version string) {
202 fmt.Fprintf(os.Stderr, `zot %s — Yet another coding agent harness.
203
204usage:
205 zot interactive tui
206 zot "prompt" interactive, pre-filled prompt
207 zot -p "prompt" print final text, exit
208 zot --json "prompt" newline-delimited json events, exit
209 zot rpc json-rpc loop on stdin/stdout (see docs/rpc.md)
210 zot telegram-bot setup configure a telegram bot (from BotFather)
211 zot telegram-bot run foreground bridge (ctrl+c to stop)
212 zot telegram-bot start background bridge (detached)
213 zot telegram-bot stop stop the background bridge
214 zot telegram-bot logs [-f] tail the background bridge's log
215 zot telegram-bot status config + running state
216 zot telegram-bot reset forget saved token
217 (short alias: zot tg ...)
218
219flags:
220 --provider anthropic|openai
221 --model model id (see --list-models)
222 --api-key api key for this run (falls back to env and auth.json)
223 --base-url override provider api base url (for testing/self-hosted)
224
225 --system-prompt TEXT replace the default system prompt
226 --append-system-prompt TEXT append to the system prompt (repeatable)
227 --reasoning low|medium|high enable reasoning on supported models
228
229 -c, --continue continue the most recent session for this cwd
230 -r, --resume pick a session to resume
231 --session PATH resume a specific session file
232 --no-session do not read or write a session file
233
234 --cwd PATH treat PATH as the working directory
235 --no-tools disable all tools
236 --tools csv only enable the listed tools
237 -e, --ext PATH load an extension from PATH for this run
238 (repeatable; takes precedence over
239 installed extensions of the same name)
240
241 --max-steps N agent loop iteration cap (default 50)
242 --list-models print known models and exit
243 -h, --help this message
244 -v, --version version info
245`, version)
246}