traw 0.2.7 → 0.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "traw",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "module": "src/index.ts",
5
5
  "type": "module",
6
6
  "bin": {
package/readme.md CHANGED
@@ -35,7 +35,7 @@ bun add -g traw
35
35
  npm i -g traw
36
36
 
37
37
  # auth the traw
38
- bun run traw auth glm
38
+ bun run traw auth
39
39
  # mo server not found. install mo? [Y/n] Y
40
40
  ```
41
41
  <div align="center">
package/src/cli/help.ts CHANGED
@@ -6,41 +6,32 @@ traw v${VERSION} - AI browser agent
6
6
 
7
7
  Usage:
8
8
  traw run "your goal here"
9
- traw auth <provider>
9
+ traw auth
10
10
  traw upd
11
11
 
12
12
  Commands:
13
- run execute browser agent with a goal
14
- auth qwen register qwen account (chat.qwen.ai)
15
- auth glm register glm account (z.ai)
16
- auth list [provider] list tokens (all or by provider)
17
- auth activate <id> activate token by id
18
- upd check for updates
19
-
20
- Models:
21
- qwen: coder-model (default), vision-model (--fast)
22
- glm: GLM-4-Plus, GLM-4-Flash, GLM-4-Air, GLM-4-6-API-V1
13
+ run execute browser agent with a goal
14
+ auth register new account and set as default
15
+ upd check for updates
23
16
 
24
17
  Options:
25
- --fast use fast model (vision-model for qwen, GLM-4-Flash for glm)
18
+ --fast use fast model (glm-4-flash, no thinking)
26
19
  --headless run without visible browser (default)
27
20
  --headed show browser window
28
21
  --video enable video recording
22
+ --vision send screenshots to AI (visual mode)
29
23
  --steps=N max steps (default: 20)
30
24
  --mo=URL mo server url (default: http://localhost:8804)
31
25
  --api=URL custom OpenAI-compatible API url (bypasses mo)
32
26
  --api-key=KEY API key for custom endpoint (or use OPENAI_API_KEY env)
33
- --model=NAME model name (default: coder-model)
27
+ --model=NAME model name (default: glm-4.7)
34
28
  -v, --version show version
35
29
 
36
30
  Examples:
37
- traw auth qwen
38
- traw auth glm
39
- traw auth list
40
- traw auth activate abc123
31
+ traw auth
41
32
  traw run "find the weather in Moscow"
42
- traw run --model=GLM-4-Plus "search for news"
43
33
  traw run --fast "quick search for bun.js"
44
34
  traw run --video "search for documentation"
35
+ traw run --api=https://api.openai.com --model=gpt-4o "search for news"
45
36
  `)
46
37
  }
package/src/cli/index.ts CHANGED
@@ -26,18 +26,11 @@ const cliOptions = {
26
26
  model: { type: "string" as const },
27
27
  }
28
28
 
29
- type Provider = "qwen" | "glm"
30
-
31
- const providerModels: Record<Provider, { default: string; fast: string }> = {
32
- qwen: { default: "coder-model", fast: "vision-model" },
33
- glm: { default: "GLM-4-Plus", fast: "GLM-4-Flash" },
34
- }
35
-
36
29
  const defaultConfig: AgentConfig = {
37
30
  moUrl: `http://localhost:${DEFAULT_MO_PORT}`,
38
31
  apiUrl: undefined,
39
32
  apiKey: process.env.OPENAI_API_KEY || process.env.API_KEY,
40
- model: "coder-model",
33
+ model: "glm-4.7",
41
34
  thinking: true,
42
35
  headless: true,
43
36
  recordVideo: false,
@@ -55,10 +48,12 @@ async function prompt(question: string): Promise<string> {
55
48
  }
56
49
 
57
50
  async function ensureMo(moUrl: string): Promise<boolean> {
51
+ // check if mo is already running
58
52
  if (await pingMo(moUrl)) {
59
53
  return true
60
54
  }
61
55
 
56
+ // mo not running, check if installed
62
57
  const installed = await isMoInstalled()
63
58
 
64
59
  if (!installed) {
@@ -76,6 +71,7 @@ async function ensureMo(moUrl: string): Promise<boolean> {
76
71
  }
77
72
  }
78
73
 
74
+ // start mo
79
75
  try {
80
76
  const port = parseInt(new URL(moUrl).port) || DEFAULT_MO_PORT
81
77
  await startMo(port)
@@ -86,13 +82,11 @@ async function ensureMo(moUrl: string): Promise<boolean> {
86
82
  }
87
83
  }
88
84
 
89
- async function registerAccount(moUrl: string, provider: Provider): Promise<void> {
90
- log.info(`registering new ${provider} account...`)
85
+ async function registerAccount(moUrl: string): Promise<void> {
86
+ log.info("registering new account...")
91
87
  log.info("browser will open for captcha solving")
92
88
 
93
- const endpoint = provider === "qwen" ? "/auth/qwen/register" : "/auth/glm/register"
94
-
95
- const resp = await fetch(`${moUrl}${endpoint}`, {
89
+ const resp = await fetch(`${moUrl}/auth/register`, {
96
90
  method: "POST",
97
91
  headers: { "Content-Type": "application/json" },
98
92
  })
@@ -104,7 +98,7 @@ async function registerAccount(moUrl: string, provider: Provider): Promise<void>
104
98
 
105
99
  const data = await resp.json() as {
106
100
  success: boolean
107
- token: { id: string; email: string; is_active: boolean }
101
+ token: { id: string; email: string; active: boolean }
108
102
  }
109
103
 
110
104
  if (!data.success) {
@@ -113,66 +107,9 @@ async function registerAccount(moUrl: string, provider: Provider): Promise<void>
113
107
 
114
108
  log.success(`registered: ${data.token.email}`)
115
109
  log.info(`token id: ${data.token.id}`)
116
- log.info(`provider: ${provider}`)
117
110
  log.info("token is now active and ready to use")
118
111
  }
119
112
 
120
- async function listTokens(moUrl: string, provider: Provider): Promise<void> {
121
- const endpoint = `/auth/${provider}/tokens`
122
-
123
- const resp = await fetch(`${moUrl}${endpoint}`)
124
- if (!resp.ok) {
125
- throw new Error(`failed to list tokens: ${resp.status}`)
126
- }
127
-
128
- const data = await resp.json() as {
129
- tokens: Array<{
130
- id: string
131
- email: string
132
- provider: string
133
- is_active: boolean
134
- created_at: string
135
- }>
136
- }
137
-
138
- if (!data.tokens || data.tokens.length === 0) {
139
- log.info(`no ${provider} tokens found`)
140
- return
141
- }
142
-
143
- console.log()
144
- log.info(`${provider} tokens:`)
145
- for (const t of data.tokens) {
146
- const active = t.is_active ? " [active]" : ""
147
- console.log(` ${t.id} - ${t.email}${active}`)
148
- }
149
- console.log()
150
- }
151
-
152
- async function activateToken(moUrl: string, tokenId: string): Promise<void> {
153
- const providers: Provider[] = ["qwen", "glm"]
154
-
155
- for (const provider of providers) {
156
- const resp = await fetch(`${moUrl}/auth/${provider}/tokens/${tokenId}/activate`, {
157
- method: "POST",
158
- })
159
-
160
- if (resp.ok) {
161
- log.success(`token ${tokenId} activated`)
162
- return
163
- }
164
- }
165
-
166
- throw new Error(`token ${tokenId} not found`)
167
- }
168
-
169
- function detectProviderFromModel(model: string): Provider {
170
- if (model.startsWith("coder-") || model.startsWith("vision-")) {
171
- return "qwen"
172
- }
173
- return "glm"
174
- }
175
-
176
113
  async function main() {
177
114
  const { values, positionals } = parseArgs({
178
115
  args: Bun.argv.slice(2),
@@ -220,40 +157,13 @@ async function main() {
220
157
 
221
158
  if (cmd === "auth") {
222
159
  const moUrl = typeof values.mo === "string" ? values.mo : defaultConfig.moUrl
223
- const subCmd = positionals[1]
224
160
 
225
161
  if (!await ensureMo(moUrl)) {
226
162
  process.exit(1)
227
163
  }
228
164
 
229
165
  try {
230
- if (subCmd === "qwen") {
231
- await registerAccount(moUrl, "qwen")
232
- } else if (subCmd === "glm") {
233
- await registerAccount(moUrl, "glm")
234
- } else if (subCmd === "list") {
235
- const provider = positionals[2] as Provider | undefined
236
- if (provider && (provider === "qwen" || provider === "glm")) {
237
- await listTokens(moUrl, provider)
238
- } else {
239
- await listTokens(moUrl, "qwen")
240
- await listTokens(moUrl, "glm")
241
- }
242
- } else if (subCmd === "activate") {
243
- const tokenId = positionals[2]
244
- if (!tokenId) {
245
- log.error("provide token id: traw auth activate <id>")
246
- process.exit(1)
247
- }
248
- await activateToken(moUrl, tokenId)
249
- } else {
250
- log.error("usage: traw auth <qwen|glm|list|activate>")
251
- log.info(" traw auth qwen - register qwen account")
252
- log.info(" traw auth glm - register glm/z.ai account")
253
- log.info(" traw auth list - list all tokens")
254
- log.info(" traw auth activate <id> - activate token")
255
- process.exit(1)
256
- }
166
+ await registerAccount(moUrl)
257
167
  } catch (err: any) {
258
168
  log.error(err.message)
259
169
  process.exit(1)
@@ -271,15 +181,7 @@ async function main() {
271
181
  const moUrl = typeof values.mo === "string" ? values.mo : defaultConfig.moUrl
272
182
  const apiUrl = typeof values.api === "string" ? values.api : undefined
273
183
  const apiKey = typeof values["api-key"] === "string" ? values["api-key"] : defaultConfig.apiKey
274
-
275
- let model: string
276
- if (typeof values.model === "string") {
277
- model = values.model
278
- } else {
279
- const provider: Provider = "qwen"
280
- model = values.fast ? providerModels[provider].fast : providerModels[provider].default
281
- }
282
-
184
+ const model = typeof values.model === "string" ? values.model : (values.fast ? "0727-106B-API" : defaultConfig.model)
283
185
  const steps = typeof values.steps === "string" ? parseInt(values.steps) : defaultConfig.maxSteps
284
186
 
285
187
  const config: AgentConfig = {
@@ -297,7 +199,7 @@ async function main() {
297
199
 
298
200
  const goal = positionals.slice(1).join(" ")
299
201
  if (!goal) {
300
- log.error("provide a goal: traw run \"your goal\"")
202
+ log.error("provide a goal: bun run traw run \"your goal\"")
301
203
  process.exit(1)
302
204
  }
303
205
 
@@ -315,6 +217,7 @@ async function main() {
315
217
  setSilent(true)
316
218
  }
317
219
 
220
+ // skip mo setup if using custom api
318
221
  if (!config.apiUrl && !await ensureMo(config.moUrl)) {
319
222
  process.exit(1)
320
223
  }