arisa 2.3.15 → 2.3.17

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/README.md CHANGED
@@ -14,11 +14,9 @@ Arisa can execute actions with operational control over the system where it runs
14
14
 
15
15
  ```bash
16
16
  curl -fsSL https://bun.sh/install | bash # Install Bun https://bun.sh
17
-
18
- bun add -g @anthropic-ai/claude-code # Install Claude CLI (both or one is required)
19
- bun add -g @openai/codex # Install Codex CLI (both or one is required)
20
-
21
17
  bun add -g arisa # Install Arisa CLI
18
+
19
+ # @anthropic-ai/claude-code and @openai/codex (auto-installed if missing)
22
20
  ```
23
21
 
24
22
  ## Commands
package/package.json CHANGED
@@ -1,7 +1,19 @@
1
1
  {
2
2
  "name": "arisa",
3
- "version": "2.3.15",
3
+ "version": "2.3.17",
4
4
  "description": "Arisa - dynamic agent runtime with daemon/core architecture that evolves through user interaction",
5
+ "keywords": [
6
+ "tinyclaw",
7
+ "clawbot",
8
+ "moltbot",
9
+ "openclaw",
10
+ "agent",
11
+ "telegram",
12
+ "jarvis",
13
+ "CLAUDE.md",
14
+ "SOUL.md",
15
+ "clasen"
16
+ ],
5
17
  "preferGlobal": true,
6
18
  "bin": {
7
19
  "arisa": "./bin/arisa.js"
@@ -40,4 +52,4 @@
40
52
  "@types/bun": "latest",
41
53
  "@types/crypto-js": "^4.2.2"
42
54
  }
43
- }
55
+ }
@@ -273,9 +273,26 @@ export function isCodexAuthRequiredResponse(text: string): boolean {
273
273
  }
274
274
 
275
275
  function summarizeError(raw: string): string {
276
- const clean = raw.replace(/\s+/g, " ").trim();
277
- if (!clean) return "process ended without details.";
278
- // Cap at 200 chars for Telegram readability
276
+ if (!raw.trim()) return "process ended without details.";
277
+
278
+ const lines = raw.split("\n");
279
+
280
+ // Filter out Bun stack-trace source code lines (e.g. "3 | import{createRequire...")
281
+ // and caret pointer lines (e.g. " ^")
282
+ const meaningful = lines.filter(
283
+ (l) => !/^\s*\d+\s*\|/.test(l) && !/^\s*\^+\s*$/.test(l)
284
+ );
285
+
286
+ // Look for explicit error lines first (e.g. "error: ...", "TypeError: ...")
287
+ const errorLine = meaningful.find((l) =>
288
+ /^\s*(error|Error|TypeError|ReferenceError|SyntaxError|RangeError|ENOENT|EACCES|fatal)[:]/i.test(l.trim())
289
+ );
290
+
291
+ const summary = errorLine?.trim()
292
+ || meaningful.filter((l) => l.trim()).join(" ").trim()
293
+ || "process ended without details.";
294
+
295
+ const clean = summary.replace(/\s+/g, " ");
279
296
  return clean.length > 200 ? clean.slice(0, 200) + "..." : clean;
280
297
  }
281
298
 
@@ -255,52 +255,81 @@ async function runInteractiveLogin(cli: AgentCliName, vars: Record<string, strin
255
255
  console.log(`Starting ${cli} login...`);
256
256
 
257
257
  try {
258
- // For claude: run setup-token with full stdio, then read token from credentials or prompt
258
+ // For claude: capture stdout to extract OAuth token while still showing output
259
259
  if (cli === "claude") {
260
- // Run with inherited stdio — user interacts directly, no output capture
261
260
  const proc = Bun.spawn(buildBunWrappedAgentCliCommand(cli, args), {
262
261
  stdin: "inherit",
263
- stdout: "inherit",
262
+ stdout: "pipe",
264
263
  stderr: "inherit",
265
264
  });
266
265
 
267
- const exitCode = await proc.exited;
268
- if (exitCode !== 0) {
269
- console.log(` ✗ claude login failed (exit ${exitCode})`);
270
- return false;
266
+ let output = "";
267
+ const reader = (proc.stdout as ReadableStream<Uint8Array>).getReader();
268
+ const decoder = new TextDecoder();
269
+ while (true) {
270
+ const { done, value } = await reader.read();
271
+ if (done) break;
272
+ const chunk = decoder.decode(value, { stream: true });
273
+ process.stdout.write(chunk);
274
+ output += chunk;
271
275
  }
272
276
 
273
- // Try to read token from Claude's credentials file
274
- const claudeDir = isRunningAsRoot() ? "/home/arisa/.claude" : join(process.env.HOME || "~", ".claude");
275
- const credsPath = join(claudeDir, ".credentials.json");
276
- let token = "";
277
-
278
- if (existsSync(credsPath)) {
279
- try {
280
- const creds = JSON.parse(readFileSync(credsPath, "utf8"));
281
- token = creds?.claudeAiOauth?.accessToken || "";
282
- if (token) console.log(` ✓ token read from ${credsPath}`);
283
- } catch {}
284
- }
277
+ const exitCode = await proc.exited;
278
+ if (exitCode === 0) {
279
+ // Strip ANSI with a state machine (regex can't handle all Ink sequences)
280
+ function stripAnsi(s: string): string {
281
+ let out = "";
282
+ for (let i = 0; i < s.length; i++) {
283
+ if (s.charCodeAt(i) === 0x1b) {
284
+ i++;
285
+ if (i >= s.length) break;
286
+ if (s[i] === "[") {
287
+ // CSI: ESC [ <params 0x20-0x3F>* <final 0x40-0x7E>
288
+ i++;
289
+ while (i < s.length && s.charCodeAt(i) < 0x40) i++;
290
+ // i now on final byte, loop will i++
291
+ } else if (s[i] === "]") {
292
+ // OSC: ESC ] ... BEL(0x07) or ST(ESC \)
293
+ i++;
294
+ while (i < s.length && s.charCodeAt(i) !== 0x07 && s[i] !== "\x1b") i++;
295
+ } else if (s[i] === "(" || s[i] === ")" || s[i] === "#") {
296
+ i++; // skip designator byte
297
+ }
298
+ // else: 2-byte Fe sequence, already skipped
299
+ } else if (s.charCodeAt(i) < 0x20 && s[i] !== "\n" && s[i] !== "\r") {
300
+ // skip control chars
301
+ } else {
302
+ out += s[i];
303
+ }
304
+ }
305
+ return out;
306
+ }
285
307
 
286
- // If no credentials file, ask user to paste the token
287
- if (!token) {
288
- console.log("\n The token was displayed above. Please paste it here:");
289
- const pasted = await readLine(" CLAUDE_CODE_OAUTH_TOKEN: ");
290
- token = pasted.replace(/\s+/g, "").trim();
291
- }
308
+ const clean = stripAnsi(output);
309
+ const startIdx = clean.indexOf("sk-ant-");
310
+ let token = "";
292
311
 
293
- if (token && token.startsWith("sk-ant-")) {
294
- console.log(` [token] ${token.slice(0, 20)}...${token.slice(-6)} (${token.length} chars)`);
295
- vars.CLAUDE_CODE_OAUTH_TOKEN = token;
296
- process.env.CLAUDE_CODE_OAUTH_TOKEN = token;
297
- saveEnv(vars);
298
- console.log(" ✓ claude token saved to .env");
312
+ if (startIdx >= 0) {
313
+ let endIdx = clean.indexOf("Store", startIdx);
314
+ if (endIdx < 0) endIdx = clean.indexOf("Use this", startIdx);
315
+ if (endIdx < 0) endIdx = startIdx + 200;
299
316
 
300
- // Also write credentials file for arisa user if it doesn't exist
301
- if (!existsSync(credsPath)) {
317
+ const tokenArea = clean.substring(startIdx, endIdx);
318
+ token = tokenArea.replace(/[^A-Za-z0-9_-]/g, "");
319
+ }
320
+
321
+ if (token && token.startsWith("sk-ant-") && token.length > 50 && token.length < 150) {
322
+ console.log(` [token] ${token.slice(0, 20)}...${token.slice(-6)} (${token.length} chars)`);
323
+ vars.CLAUDE_CODE_OAUTH_TOKEN = token;
324
+ process.env.CLAUDE_CODE_OAUTH_TOKEN = token;
325
+ saveEnv(vars);
326
+ console.log(" ✓ claude token saved to .env");
327
+
328
+ // Also write credentials file for arisa user (belt + suspenders)
329
+ const claudeDir = isRunningAsRoot() ? "/home/arisa/.claude" : join(process.env.HOME || "~", ".claude");
302
330
  try {
303
331
  if (!existsSync(claudeDir)) mkdirSync(claudeDir, { recursive: true });
332
+ const credsPath = join(claudeDir, ".credentials.json");
304
333
  const creds = {
305
334
  claudeAiOauth: {
306
335
  accessToken: token,
@@ -316,13 +345,18 @@ async function runInteractiveLogin(cli: AgentCliName, vars: Record<string, strin
316
345
  } catch (e) {
317
346
  console.log(` ⚠ could not write credentials file: ${e}`);
318
347
  }
348
+ } else {
349
+ console.log(` ⚠ token extraction failed (indexOf=${startIdx}, len=${token.length})`);
350
+ if (startIdx >= 0) {
351
+ console.log(` [clean] ${clean.substring(startIdx, startIdx + 150).replace(/\n/g, "\\n")}`);
352
+ }
319
353
  }
354
+ console.log(` ✓ claude login successful`);
355
+ return true;
320
356
  } else {
321
- console.log(" no valid token provided");
357
+ console.log(` claude login failed (exit ${exitCode})`);
358
+ return false;
322
359
  }
323
-
324
- console.log(` ✓ claude login successful`);
325
- return true;
326
360
  }
327
361
 
328
362
  // For codex and others: inherit all stdio
@@ -100,7 +100,7 @@ export function buildBunWrappedAgentCliCommand(cli: AgentCliName, args: string[]
100
100
  // Run as arisa user — Claude CLI refuses to run as root
101
101
  const cliPath = resolveAgentCliPath(cli) || join(ARISA_USER_BUN, cli);
102
102
  const shimPath = existsSync(ARISA_INK_SHIM) ? ARISA_INK_SHIM : INK_SHIM;
103
- const inner = ["bun", "--preload", shimPath, cliPath, ...args].map(shellEscape).join(" ");
103
+ const inner = ["bun", "--bun", "--preload", shimPath, cliPath, ...args].map(shellEscape).join(" ");
104
104
  // su without "-" preserves parent env (tokens, keys); explicit HOME/PATH for arisa
105
105
  return ["su", "arisa", "-s", "/bin/bash", "-c", `${ARISA_BUN_ENV} && ${buildEnvExports()}${inner}`];
106
106
  }
@@ -111,5 +111,5 @@ export function buildBunWrappedAgentCliCommand(cli: AgentCliName, args: string[]
111
111
  }
112
112
  // Preload shim that patches process.stdin.setRawMode to prevent Ink crash
113
113
  // when running without a TTY (systemd, su -c, etc.)
114
- return ["bun", "--preload", INK_SHIM, cliPath, ...args];
114
+ return ["bun", "--bun", "--preload", INK_SHIM, cliPath, ...args];
115
115
  }