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