rird-ai 2.1.221 → 2.1.223

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.
Files changed (3) hide show
  1. package/bin/rird +226 -249
  2. package/package.json +23 -1
  3. package/postinstall.mjs +23 -0
package/bin/rird CHANGED
@@ -1,5 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ import { createRequire } from "module"
4
+ import { fileURLToPath } from "url"
5
+ import { dirname } from "path"
6
+
7
+ const require = createRequire(import.meta.url)
8
+ const __filename = fileURLToPath(import.meta.url)
9
+ const __dirname = dirname(__filename)
10
+
3
11
  const childProcess = require("child_process")
4
12
  const fs = require("fs")
5
13
  const path = require("path")
@@ -41,20 +49,26 @@ if (command === "upgrade" || command === "update") {
41
49
  console.log(" Upgrading to latest version...")
42
50
  console.log("")
43
51
 
44
- const platform = os.platform()
52
+ // Check if npm is available
53
+ let hasNpm = false
54
+ try {
55
+ childProcess.execSync("npm --version", { stdio: "ignore" })
56
+ hasNpm = true
57
+ } catch (e) {}
58
+
45
59
  let result
46
60
 
47
- if (platform === "win32") {
48
- // Windows: Use npm to update (simpler and more reliable)
49
- console.log("Running: npm install -g rird-ai@main")
61
+ if (hasNpm) {
62
+ console.log("Running: npm install -g rird@latest")
50
63
  console.log("")
51
64
  result = childProcess.spawnSync(
52
65
  "npm",
53
- ["install", "-g", "rird-ai@main"],
66
+ ["install", "-g", "rird@latest"],
54
67
  { stdio: "inherit", shell: true }
55
68
  )
56
69
  } else {
57
- // Unix/macOS: Use curl
70
+ // Fallback to curl for Unix/macOS if npm is missing
71
+ console.log("Running: curl -fsSL https://rird.ai/install.sh | bash")
58
72
  result = childProcess.spawnSync(
59
73
  "bash",
60
74
  ["-c", "curl -fsSL https://rird.ai/install.sh | bash"],
@@ -62,291 +76,254 @@ if (command === "upgrade" || command === "update") {
62
76
  )
63
77
  }
64
78
 
65
- if (result.error) {
66
- console.error("Upgrade failed:", result.error.message)
79
+ if (result.error || result.status !== 0) {
80
+ console.error("Upgrade failed. Please try running the install command manually.")
67
81
  process.exit(1)
68
82
  }
69
- process.exit(result.status || 0)
70
- }
71
-
72
- // Branding replacements for output - order matters (specific patterns first)
73
- const REPLACEMENTS = [
74
- // URLs and paths
75
- { from: /sst\/opencode/gi, to: "rird.ai" },
76
- { from: /opencode\.ai/gi, to: "rird.ai" },
77
- { from: /rird\.ai\/desktop/gi, to: "rird.ai" },
78
- { from: /https?:\/\/[^\s]*opencode[^\s]*/gi, to: (match) => match.replace(/opencode/gi, "rird") },
79
- // Known fake/test model names
80
- { from: /OpenCode Zen/gi, to: "RIRD AI" },
81
- { from: /OpenCode\/Zen/gi, to: "RIRD AI" },
82
- { from: /opencode-zen/gi, to: "rird-brain" },
83
- { from: /Big Pickle/gi, to: "RIRD AI" },
84
- { from: /big-pickle/gi, to: "rird-brain" },
85
- { from: /gpt-5-nano/gi, to: "RIRD Brain" },
86
- { from: /GPT-5 Nano/gi, to: "RIRD Brain" },
87
- // Provider/model name patterns (catch OpenCode/anything)
88
- { from: /OpenCode\s*\/\s*(\w+)/gi, to: "RIRD/$1" },
89
- // Generic branding
90
- { from: /OpenCode/g, to: "RIRD" },
91
- { from: /opencode/g, to: "rird" },
92
- ]
93
-
94
- function replaceBranding(data) {
95
- let str = data.toString()
96
- for (const { from, to } of REPLACEMENTS) {
97
- str = str.replace(from, to)
98
- }
99
- return str
83
+ process.exit(0)
100
84
  }
101
85
 
102
- function runWithPty(target, args, env) {
103
- let pty = null
104
- try {
105
- pty = require("bun-pty")
106
- } catch (e1) {
107
- try {
108
- pty = require("node-pty")
109
- } catch (e2) {
110
- return false // PTY not available
111
- }
112
- }
113
-
114
- const cols = process.stdout.columns || 80
115
- const rows = process.stdout.rows || 24
116
- const cwd = env.RIRD_ENGINE_DIR || process.cwd()
117
-
118
- try {
119
- const ptyProcess = pty.spawn(target, args, {
120
- name: "xterm-256color",
121
- cols: cols,
122
- rows: rows,
123
- cwd: cwd,
124
- env: env,
125
- ...(os.platform() === "win32" && {
126
- useConpty: true,
127
- conptyInheritCursor: true,
128
- }),
129
- })
86
+ // Activate - save license key and validate
87
+ if (command === "activate") {
88
+ const key = process.argv[3]
130
89
 
131
- // Handle output with branding replacement
132
- ptyProcess.onData((data) => {
133
- process.stdout.write(replaceBranding(data))
134
- })
90
+ console.log("")
91
+ console.log(" RIRD AI")
92
+ console.log(" Activating license...")
93
+ console.log("")
135
94
 
136
- // Handle input
137
- if (process.stdin.isTTY) {
138
- process.stdin.setRawMode(true)
139
- }
140
- process.stdin.resume()
141
- process.stdin.on("data", (data) => {
142
- ptyProcess.write(data.toString())
143
- })
95
+ if (!key || key.length < 10) {
96
+ console.error(" Error: Invalid license key format")
97
+ console.log("")
98
+ console.log(" Usage: rird activate YOUR_LICENSE_KEY")
99
+ console.log(" Get your key at: https://rird.ai")
100
+ console.log("")
101
+ process.exit(1)
102
+ }
144
103
 
145
- // Handle terminal resize
146
- process.stdout.on("resize", () => {
147
- ptyProcess.resize(
148
- process.stdout.columns || 80,
149
- process.stdout.rows || 24
150
- )
151
- })
104
+ const rirdHome = process.env.RIRD_HOME || path.join(os.homedir(), ".rird")
105
+ const licensePath = path.join(rirdHome, "license.key")
106
+ const cachePath = path.join(rirdHome, "license_cache.json")
152
107
 
153
- // Handle exit
154
- let exited = false
155
- ptyProcess.onExit(({ exitCode }) => {
156
- if (exited) return
157
- exited = true
158
- if (process.stdin.isTTY) {
159
- process.stdin.setRawMode(false)
160
- }
161
- process.stdin.pause()
162
- process.exit(exitCode || 0)
163
- })
108
+ if (!fs.existsSync(rirdHome)) {
109
+ fs.mkdirSync(rirdHome, { recursive: true })
110
+ }
164
111
 
165
- // Handle signals - pass to child, don't exit wrapper
166
- process.on("SIGINT", () => {
167
- if (!exited) ptyProcess.write("\x03") // Send Ctrl+C to PTY
168
- })
169
- process.on("SIGTERM", () => {
170
- if (!exited) ptyProcess.kill()
171
- })
112
+ fs.writeFileSync(licensePath, key.trim())
113
+ console.log(" License key saved")
172
114
 
173
- return true // PTY started successfully
174
- } catch (err) {
175
- return false // PTY failed
115
+ if (fs.existsSync(cachePath)) {
116
+ fs.unlinkSync(cachePath)
176
117
  }
177
- }
178
118
 
179
- function runWithPipes(target, args, env) {
180
- const cwd = env.RIRD_ENGINE_DIR || process.cwd()
181
- const child = childProcess.spawn(target, args, {
182
- env: env,
183
- cwd: cwd,
184
- stdio: ["pipe", "pipe", "pipe"],
185
- })
119
+ console.log(" Validating license...")
186
120
 
187
- let exited = false
121
+ const https = require("https")
122
+ const crypto = require("crypto")
188
123
 
189
- child.stdout.on("data", (data) => {
190
- if (!exited) process.stdout.write(replaceBranding(data))
191
- })
124
+ const parts = [os.hostname(), os.platform(), os.arch(), os.totalmem().toString(), os.cpus().length.toString()]
125
+ const fingerprint = crypto.createHash("sha256").update(parts.join("|")).digest("hex").substring(0, 32)
192
126
 
193
- child.stderr.on("data", (data) => {
194
- if (!exited) process.stderr.write(replaceBranding(data))
127
+ const postData = JSON.stringify({
128
+ license_key: key.trim(),
129
+ device_fingerprint: fingerprint,
130
+ version: require("../package.json").version,
131
+ platform: os.platform()
195
132
  })
196
133
 
197
- process.stdin.pipe(child.stdin)
134
+ const options = {
135
+ hostname: "rird.ai",
136
+ port: 443,
137
+ path: "/api/desktop/validate-license",
138
+ method: "POST",
139
+ headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(postData) }
140
+ }
198
141
 
199
- child.on("exit", (code) => {
200
- if (exited) return
201
- exited = true
202
- process.stdin.unpipe(child.stdin)
203
- process.stdin.pause()
204
- process.exit(code || 0)
142
+ const req = https.request(options, (res) => {
143
+ let data = ""
144
+ res.on("data", (chunk) => data += chunk)
145
+ res.on("end", () => {
146
+ try {
147
+ const result = JSON.parse(data)
148
+ if (res.statusCode === 200 && result.valid) {
149
+ console.log("")
150
+ console.log(" License activated!")
151
+ if (result.user && result.user.email) console.log(" Welcome, " + result.user.email)
152
+ console.log("")
153
+ console.log(" Run 'rird' to get started")
154
+ console.log("")
155
+ fs.writeFileSync(cachePath, JSON.stringify({
156
+ license_key: key.trim(), valid: true,
157
+ email: result.user ? result.user.email : null,
158
+ plan: result.user ? result.user.plan : null,
159
+ cached_at: new Date().toISOString()
160
+ }))
161
+ process.exit(0)
162
+ } else {
163
+ console.error("")
164
+ console.error(" Activation failed: " + (result.error || "Invalid license"))
165
+ console.log(" Check your key and try again")
166
+ console.log("")
167
+ process.exit(1)
168
+ }
169
+ } catch (e) {
170
+ console.error(" Error parsing response:", e.message)
171
+ process.exit(1)
172
+ }
173
+ })
205
174
  })
206
175
 
207
- child.on("error", (err) => {
208
- if (exited) return
209
- exited = true
210
- console.error("Failed to start process:", err.message)
176
+ req.on("error", (e) => {
177
+ console.error("")
178
+ console.error(" Could not reach license server: " + e.message)
179
+ console.log("")
211
180
  process.exit(1)
212
181
  })
213
182
 
214
- process.on("SIGINT", () => {
215
- if (!exited) child.kill("SIGINT")
216
- })
217
- process.on("SIGTERM", () => {
218
- if (!exited) child.kill("SIGTERM")
219
- })
220
- }
183
+ req.write(postData)
184
+ req.end()
185
+ } else if (command === "status") {
186
+ console.log("")
187
+ console.log(" RIRD AI")
188
+ console.log(" Checking license status...")
189
+ console.log("")
221
190
 
222
- function run(target) {
223
- // Set config path to RIRD config
224
191
  const rirdHome = process.env.RIRD_HOME || path.join(os.homedir(), ".rird")
225
- const brainDir = path.join(rirdHome, "brain")
226
- const configPath = path.join(brainDir, "rird.json")
192
+ const licensePath = path.join(rirdHome, "license.key")
193
+ const cachePath = path.join(rirdHome, "license_cache.json")
227
194
 
228
- // Ensure brain directory exists
229
- if (!fs.existsSync(brainDir)) {
230
- fs.mkdirSync(brainDir, { recursive: true })
195
+ if (!fs.existsSync(licensePath)) {
196
+ console.log(" Status: Not activated")
197
+ console.log("")
198
+ console.log(" Run: rird activate YOUR_LICENSE_KEY")
199
+ console.log(" Get your key at: https://rird.ai")
200
+ console.log("")
201
+ process.exit(0)
231
202
  }
232
203
 
233
- // Create default config if it doesn't exist
234
- if (!fs.existsSync(configPath)) {
235
- const defaultConfig = {
236
- name: "RIRD AI",
237
- autoupdate: false,
238
- instructions: [
239
- "You are RIRD AI with browser automation and computer control.",
240
- "Use file tools (Write, Edit) for saving data.",
241
- "Execute tasks autonomously and efficiently."
242
- ],
243
- permission: {
244
- edit: "allow",
245
- bash: "allow",
246
- skill: "allow",
247
- webfetch: "allow",
248
- external_directory: "allow"
204
+ const key = fs.readFileSync(licensePath, "utf-8").trim()
205
+
206
+ if (fs.existsSync(cachePath)) {
207
+ try {
208
+ const cache = JSON.parse(fs.readFileSync(cachePath, "utf-8"))
209
+ if (cache.valid && cache.license_key === key) {
210
+ console.log(" Status: Active")
211
+ if (cache.email) console.log(" Account: " + cache.email)
212
+ if (cache.plan) console.log(" Plan: " + cache.plan)
213
+ console.log("")
214
+ process.exit(0)
249
215
  }
250
- }
251
- fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2))
216
+ } catch (e) {}
252
217
  }
253
218
 
254
- const env = { ...process.env }
255
- env.OPENCODE_CONFIG = configPath
256
- env.RIRD_ENGINE_DIR = brainDir
257
- env.RIRD_DISABLE_AUTOUPDATE = "true"
258
- env.OPENCODE_DISABLE_AUTOUPDATE = "true"
259
- env.OPENCODE_SKIP_UPDATE = "true"
219
+ console.log(" Status: License key found, checking online...")
220
+ console.log("")
221
+ process.exit(0)
222
+ } else {
223
+ // Only run the binary if NOT processing a special command
224
+ const envPath = process.env.RIRD_BIN_PATH
225
+ if (envPath) {
226
+ run(envPath)
227
+ }
260
228
 
261
- const args = process.argv.slice(2)
229
+ const scriptPath = fs.realpathSync(__filename)
230
+ const scriptDir = path.dirname(scriptPath)
262
231
 
263
- // On Windows, use inherited stdio for full TUI support
264
- // (branding replacement happens at source level instead)
265
- if (os.platform() === "win32") {
266
- const child = childProcess.spawn(target, args, {
267
- stdio: "inherit",
268
- env: env,
269
- cwd: env.RIRD_ENGINE_DIR || process.cwd(),
270
- })
271
- child.on("exit", (code) => process.exit(code || 0))
272
- child.on("error", (err) => {
273
- console.error(err.message)
274
- process.exit(1)
275
- })
276
- return
232
+ const platformMap = {
233
+ darwin: "darwin",
234
+ linux: "linux",
235
+ win32: "windows",
236
+ }
237
+ const archMap = {
238
+ x64: "x64",
239
+ arm64: "arm64",
240
+ arm: "arm",
277
241
  }
278
242
 
279
- // Try PTY first for full terminal support with branding replacement
280
- if (runWithPty(target, args, env)) {
281
- return // PTY started successfully
243
+ let platform = platformMap[os.platform()]
244
+ if (!platform) {
245
+ platform = os.platform()
246
+ }
247
+ let arch = archMap[os.arch()]
248
+ if (!arch) {
249
+ arch = os.arch()
250
+ }
251
+ const base = "rird-" + platform + "-" + arch
252
+ const binary = platform === "windows" ? "rird.exe" : "rird"
253
+
254
+ function findBinary(startDir) {
255
+ let current = startDir
256
+ for (;;) {
257
+ const modules = path.join(current, "node_modules")
258
+ if (fs.existsSync(modules)) {
259
+ const entries = fs.readdirSync(modules)
260
+ for (const entry of entries) {
261
+ if (!entry.startsWith(base)) {
262
+ continue
263
+ }
264
+ const candidate = path.join(modules, entry, "bin", binary)
265
+ if (fs.existsSync(candidate)) {
266
+ return candidate
267
+ }
268
+ }
269
+ }
270
+ const parent = path.dirname(current)
271
+ if (parent === current) {
272
+ return
273
+ }
274
+ current = parent
275
+ }
282
276
  }
283
277
 
284
- // Fall back to pipes with branding replacement
285
- runWithPipes(target, args, env)
286
- }
278
+ const rirdHome = process.env.RIRD_HOME || path.join(os.homedir(), ".rird")
279
+ const engineDir = path.join(rirdHome, "engine")
280
+ const brainDir = path.join(rirdHome, "brain")
287
281
 
288
- const envPath = process.env.OPENCODE_BIN_PATH
289
- if (envPath) {
290
- run(envPath)
291
- }
282
+ // Use engine config (from postinstall with MCP) if it exists, otherwise brain
283
+ const engineConfig = path.join(engineDir, "rird.json")
284
+ const brainConfig = path.join(brainDir, "rird.json")
285
+ const configPath = fs.existsSync(engineConfig) ? engineConfig : brainConfig
286
+ const workDir = fs.existsSync(engineConfig) ? engineDir : brainDir
292
287
 
293
- const scriptPath = fs.realpathSync(__filename)
294
- const scriptDir = path.dirname(scriptPath)
288
+ const env = { ...process.env }
289
+ env.RIRD_CONFIG = configPath
290
+ env.RIRD_ENGINE_DIR = workDir
291
+ // Enable RIRD search tools
292
+ env.RIRD_ENABLE_SEARCH = "true"
295
293
 
296
- const platformMap = {
297
- darwin: "darwin",
298
- linux: "linux",
299
- win32: "windows",
300
- }
301
- const archMap = {
302
- x64: "x64",
303
- arm64: "arm64",
304
- arm: "arm",
305
- }
294
+ function run(binPath) {
295
+ const result = childProcess.spawnSync(binPath, args, {
296
+ stdio: "inherit",
297
+ env: env,
298
+ cwd: process.cwd(),
299
+ shell: os.platform() === 'win32'
300
+ })
301
+ process.exit(result.status ?? 0)
302
+ }
306
303
 
307
- let platform = platformMap[os.platform()]
308
- if (!platform) {
309
- platform = os.platform()
310
- }
311
- let arch = archMap[os.arch()]
312
- if (!arch) {
313
- arch = os.arch()
314
- }
315
- const base = "rird-" + platform + "-" + arch
316
- const binary = platform === "windows" ? "opencode.exe" : "opencode"
317
-
318
- function findBinary(startDir) {
319
- let current = startDir
320
- for (;;) {
321
- const modules = path.join(current, "node_modules")
322
- if (fs.existsSync(modules)) {
323
- const entries = fs.readdirSync(modules)
324
- for (const entry of entries) {
325
- if (!entry.startsWith(base)) {
326
- continue
327
- }
328
- const candidate = path.join(modules, entry, "bin", binary)
329
- if (fs.existsSync(candidate)) {
330
- return candidate
331
- }
332
- }
333
- }
334
- const parent = path.dirname(current)
335
- if (parent === current) {
336
- return
304
+ const args = process.argv.slice(2)
305
+
306
+ const resolved = findBinary(scriptDir)
307
+ if (!resolved) {
308
+ // FALLBACK: If binary not found, try to run from source if in dev tree
309
+ const sourceIndex = path.join(scriptDir, "..", "src", "index.ts")
310
+ if (fs.existsSync(sourceIndex)) {
311
+ childProcess.spawnSync("bun", ["run", "--conditions=browser", sourceIndex, ...args], {
312
+ stdio: "inherit",
313
+ env: env,
314
+ cwd: env.RIRD_ENGINE_DIR || process.cwd(),
315
+ shell: true
316
+ })
317
+ process.exit(0)
337
318
  }
338
- current = parent
319
+
320
+ console.error(
321
+ 'It seems that your package manager failed to install the right version of the RIRD CLI for your platform. You can try manually installing the "' +
322
+ base +
323
+ '" package',
324
+ )
325
+ process.exit(1)
339
326
  }
340
- }
341
327
 
342
- const resolved = findBinary(scriptDir)
343
- if (!resolved) {
344
- console.error(
345
- 'It seems that your package manager failed to install the right version of the RIRD CLI for your platform. You can try manually installing the "' +
346
- base +
347
- '" package',
348
- )
349
- process.exit(1)
328
+ run(resolved)
350
329
  }
351
-
352
- run(resolved)
package/package.json CHANGED
@@ -1 +1,23 @@
1
- {"name":"rird-ai","version":"2.1.221","bin":{"rird":"./bin/rird"},"scripts":{"postinstall":"node ./postinstall.mjs"},"optionalDependencies":{"rird-windows-x64":"0.0.0-main-202601012037"}}
1
+ {
2
+ "name": "rird-ai",
3
+ "bin": {
4
+ "rird": "./bin/rird"
5
+ },
6
+ "scripts": {
7
+ "postinstall": "bun ./postinstall.mjs || node ./postinstall.mjs"
8
+ },
9
+ "version": "2.1.223",
10
+ "optionalDependencies": {
11
+ "rird-linux-arm64": "2.1.223",
12
+ "rird-linux-x64": "2.1.223",
13
+ "rird-linux-x64-baseline": "2.1.223",
14
+ "rird-linux-arm64-musl": "2.1.223",
15
+ "rird-linux-x64-musl": "2.1.223",
16
+ "rird-linux-x64-baseline-musl": "2.1.223",
17
+ "rird-darwin-arm64": "2.1.223",
18
+ "rird-darwin-x64": "2.1.223",
19
+ "rird-darwin-x64-baseline": "2.1.223",
20
+ "rird-windows-x64": "2.1.223",
21
+ "rird-windows-x64-baseline": "2.1.223"
22
+ }
23
+ }
package/postinstall.mjs CHANGED
@@ -309,6 +309,16 @@ function createConfig(pythonCmd) {
309
309
  "- Launch and interact with desktop applications",
310
310
  "- Take screenshots and analyze what's on screen",
311
311
  "",
312
+ "=== RESEARCH STRATEGY ===",
313
+ "For ANY task that asks to 'find URLs', 'output URLs', 'list profiles', or 'get X items':",
314
+ "1. ALWAYS START with websearch - it is instant and bypasses detection.",
315
+ "2. Only fall back to browser automation if websearch fails or task requires interaction (login, forms).",
316
+ "",
317
+ "=== TOOL PRIORITY ===",
318
+ "1. websearch: Use for finding URLs, profiles, and public info.",
319
+ "2. Browser (stealth-browser): Use for interaction, scrolling, and map searching.",
320
+ "3. Computer Use: Use for desktop applications when enabled.",
321
+ "",
312
322
  "=== HOW I WORK ===",
313
323
  "1. WEB SEARCH:",
314
324
  " - Finding URLs, quick facts, lists of companies or profiles",
@@ -334,6 +344,15 @@ function createConfig(pythonCmd) {
334
344
  "- Extract data from websites",
335
345
  "- Read and write files on your computer",
336
346
  "",
347
+ "=== RESEARCH STRATEGY ===",
348
+ "For ANY task that asks to 'find URLs', 'output URLs', 'list profiles', or 'get X items':",
349
+ "1. ALWAYS START with websearch - it is instant and bypasses detection.",
350
+ "2. Only fall back to browser automation if websearch fails or task requires interaction (login, forms).",
351
+ "",
352
+ "=== TOOL PRIORITY ===",
353
+ "1. websearch: Use for finding URLs, profiles, and public info.",
354
+ "2. Browser (stealth-browser): Use for interaction, scrolling, and map searching.",
355
+ "",
337
356
  "=== HOW I WORK ===",
338
357
  "1. WEB SEARCH:",
339
358
  " - Finding URLs, quick facts, lists of companies or profiles",
@@ -408,6 +427,10 @@ function createConfig(pythonCmd) {
408
427
  webfetch: "allow",
409
428
  external_directory: "allow"
410
429
  },
430
+ tools: {
431
+ websearch: true,
432
+ codesearch: true
433
+ },
411
434
  autoupdate: false,
412
435
  $schema: "https://rird.ai/config.json"
413
436
  }