arisa 2.3.17 → 2.3.19

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/bin/arisa.js CHANGED
@@ -428,7 +428,7 @@ const ARISA_BUN_ENV = 'export BUN_INSTALL=/home/arisa/.bun && export PATH=/home/
428
428
  function provisionArisaUser() {
429
429
  process.stdout.write("Creating user 'arisa' for Claude/Codex CLI execution...\n");
430
430
 
431
- // 1. Create user
431
+ // 1. Create user with sudo access
432
432
  const useradd = spawnSync("useradd", ["-m", "-s", "/bin/bash", "arisa"], { stdio: "pipe" });
433
433
  if (useradd.status !== 0) {
434
434
  step(false, `Failed to create user: ${(useradd.stderr || "").toString().trim()}`);
@@ -436,7 +436,16 @@ function provisionArisaUser() {
436
436
  }
437
437
  step(true, "User arisa created");
438
438
 
439
- // 2. Install bun for arisa (curl lightweight, no bun child process)
439
+ // 2. Grant passwordless sudo (needed for full tool execution in Claude/Codex)
440
+ try {
441
+ writeFileSync("/etc/sudoers.d/arisa", "arisa ALL=(ALL) NOPASSWD: ALL\n", { mode: 0o440 });
442
+ step(true, "Passwordless sudo granted");
443
+ } catch (e) {
444
+ // Not fatal — sudo may not be installed in minimal containers
445
+ step(false, `Sudo setup skipped: ${e.message || e}`);
446
+ }
447
+
448
+ // 3. Install bun for arisa (curl — lightweight, no bun child process)
440
449
  process.stdout.write(" Installing bun for arisa (this may take a minute)...\n");
441
450
  const bunInstall = spawnSync("su", ["-", "arisa", "-c", "curl -fsSL https://bun.sh/install | bash"], {
442
451
  stdio: "inherit",
@@ -448,7 +457,7 @@ function provisionArisaUser() {
448
457
  }
449
458
  step(true, "Bun installed for arisa");
450
459
 
451
- // 3. Write ink-shim for non-TTY execution (prevents Ink setRawMode crash)
460
+ // 4. Write ink-shim for non-TTY execution (prevents Ink setRawMode crash)
452
461
  const shimPath = "/home/arisa/.arisa-ink-shim.js";
453
462
  writeFileSync(shimPath, 'if(process.stdin&&!process.stdin.isTTY){process.stdin.setRawMode=()=>process.stdin;process.stdin.isTTY=true;}\n');
454
463
  spawnSync("chown", ["arisa:arisa", shimPath], { stdio: "ignore" });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arisa",
3
- "version": "2.3.17",
3
+ "version": "2.3.19",
4
4
  "description": "Arisa - dynamic agent runtime with daemon/core architecture that evolves through user interaction",
5
5
  "keywords": [
6
6
  "tinyclaw",
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Diagnostic: prints the exact su/bun commands that Arisa would execute,
4
+ * ready to copy-paste into a terminal.
5
+ */
6
+ import { buildBunWrappedAgentCliCommand } from "../src/shared/ai-cli";
7
+
8
+ function printable(cmd: string[]): string {
9
+ if (cmd[0] === "su") {
10
+ // cmd = ["su", "arisa", "-s", "/bin/bash", "-c", "<bash script>"]
11
+ // Wrap the -c argument in double quotes — safe because shellEscape only uses single quotes
12
+ return `${cmd.slice(0, 5).join(" ")} "${cmd[5]}"`;
13
+ }
14
+ // Non-root: just join, quoting args with spaces
15
+ return cmd.map(c => /[\s']/.test(c) ? `"${c}"` : c).join(" ");
16
+ }
17
+
18
+ const probeArgs = ["-p", "say ok", "--model", "haiku", "--output-format", "text", "--dangerously-skip-permissions"];
19
+ const processorArgs = ["--dangerously-skip-permissions", "--output-format", "text", "--model", "claude-sonnet-4-20250514", "-p", "hello test"];
20
+
21
+ console.log("=== AUTH PROBE (daemon/auto-install.ts) ===\n");
22
+ console.log(printable(buildBunWrappedAgentCliCommand("claude", probeArgs)));
23
+
24
+ console.log("\n\n=== MESSAGE PROCESSOR (core/processor.ts) ===\n");
25
+ console.log(printable(buildBunWrappedAgentCliCommand("claude", processorArgs)));
26
+ console.log();
package/src/core/media.ts CHANGED
@@ -60,7 +60,7 @@ export async function transcribeAudio(base64: string, filename: string): Promise
60
60
  const file = Bun.file(tempPath);
61
61
  const transcription = await client.audio.transcriptions.create({
62
62
  file: file,
63
- model: "whisper-1",
63
+ model: "gpt-4o-mini-transcribe",
64
64
  });
65
65
  log.info(`Transcribed audio: "${transcription.text.substring(0, 80)}..."`);
66
66
  return transcription.text;
@@ -142,10 +142,11 @@ async function runClaude(message: string, chatId: string): Promise<string> {
142
142
  log.info(
143
143
  `Claude send | promptChars: ${prompt.length} | preview: ${previewPrompt(prompt)}`
144
144
  );
145
- log.info(`Claude spawn | cmd: claude --dangerously-skip-permissions --model ${model.model} -p <prompt>`);
145
+ const spawnCmd = buildBunWrappedAgentCliCommand("claude", args);
146
+ log.info(`Claude spawn cmd (${spawnCmd.length} parts):\n${spawnCmd.map((c, i) => ` [${i}] ${c}`).join("\n")}`);
146
147
  log.debug(`Claude prompt >>>>\n${prompt}\n<<<<`);
147
148
 
148
- const proc = Bun.spawn(buildBunWrappedAgentCliCommand("claude", args), {
149
+ const proc = Bun.spawn(spawnCmd, {
149
150
  cwd: config.projectDir,
150
151
  stdin: "pipe",
151
152
  stdout: "pipe",
@@ -212,14 +213,11 @@ export async function processWithCodex(message: string): Promise<string> {
212
213
  log.info(
213
214
  `Codex send | promptChars: ${message.length} | preview: ${previewPrompt(message)}`
214
215
  );
215
- log.info(
216
- `Codex spawn | cmd: codex ${continueFlag
217
- ? "exec resume --last --dangerously-bypass-approvals-and-sandbox <prompt>"
218
- : `exec --dangerously-bypass-approvals-and-sandbox -C ${config.projectDir} <prompt>`}`
219
- );
216
+ const spawnCmd = buildBunWrappedAgentCliCommand("codex", args);
217
+ log.info(`Codex spawn cmd (${spawnCmd.length} parts):\n${spawnCmd.map((c, i) => ` [${i}] ${c}`).join("\n")}`);
220
218
  log.debug(`Codex prompt >>>>\n${message}\n<<<<`);
221
219
 
222
- const proc = Bun.spawn(buildBunWrappedAgentCliCommand("codex", args), {
220
+ const proc = Bun.spawn(spawnCmd, {
223
221
  cwd: config.projectDir,
224
222
  stdout: "pipe",
225
223
  stderr: "pipe",
@@ -10,7 +10,7 @@
10
10
  */
11
11
 
12
12
  import { createLogger } from "../shared/logger";
13
- import { isAgentCliInstalled, buildBunWrappedAgentCliCommand, type AgentCliName } from "../shared/ai-cli";
13
+ import { isAgentCliInstalled, isRunningAsRoot, buildBunWrappedAgentCliCommand, type AgentCliName } from "../shared/ai-cli";
14
14
 
15
15
  const log = createLogger("daemon");
16
16
 
@@ -19,6 +19,7 @@ const CLI_PACKAGES: Record<AgentCliName, string> = {
19
19
  codex: "@openai/codex",
20
20
  };
21
21
 
22
+ const ARISA_BUN_ENV = 'export BUN_INSTALL=/home/arisa/.bun && export PATH=/home/arisa/.bun/bin:$PATH';
22
23
  const INSTALL_TIMEOUT = 120_000; // 2min
23
24
 
24
25
  type NotifyFn = (text: string) => Promise<void>;
@@ -33,7 +34,12 @@ async function installCli(cli: AgentCliName): Promise<boolean> {
33
34
  log.info(`Auto-install: installing ${cli} (${pkg})...`);
34
35
 
35
36
  try {
36
- const proc = Bun.spawn(["bun", "add", "-g", pkg], {
37
+ // When running as root, install into arisa user's bun (consistent with setup.ts)
38
+ const cmd = isRunningAsRoot()
39
+ ? ["su", "-", "arisa", "-c", `${ARISA_BUN_ENV} && bun add -g ${pkg}`]
40
+ : ["bun", "add", "-g", pkg];
41
+
42
+ const proc = Bun.spawn(cmd, {
37
43
  stdout: "pipe",
38
44
  stderr: "pipe",
39
45
  env: { ...process.env },
@@ -119,7 +125,7 @@ export async function probeCliAuth(): Promise<void> {
119
125
  : ["exec", "--dangerously-bypass-approvals-and-sandbox", "echo ok"];
120
126
 
121
127
  const cmd = buildBunWrappedAgentCliCommand(cli, args);
122
- log.info(`Auth probe cmd: ${cmd.map(c => c.length > 80 ? c.slice(0, 80) + "..." : c).join(" ")}`);
128
+ log.info(`Auth probe cmd (${cmd.length} parts):\n${cmd.map((c, i) => ` [${i}] ${c}`).join("\n")}`);
123
129
 
124
130
  const proc = Bun.spawn(cmd, {
125
131
  stdout: "pipe",
@@ -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", "--bun", "--preload", shimPath, cliPath, ...args].map(shellEscape).join(" ");
103
+ const inner = ["bun", "--bun", 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", "--bun", "--preload", INK_SHIM, cliPath, ...args];
114
+ return ["bun", "--bun", INK_SHIM, cliPath, ...args];
115
115
  }