arisa 2.0.5 → 2.0.7

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": "arisa",
3
- "version": "2.0.5",
3
+ "version": "2.0.7",
4
4
  "description": "Arisa - dynamic agent runtime with daemon/core architecture that evolves through user interaction",
5
5
  "preferGlobal": true,
6
6
  "bin": {
@@ -29,8 +29,7 @@
29
29
  "dependencies": {
30
30
  "croner": "^9.0.0",
31
31
  "crypto-js": "^4.2.0",
32
- "deepbase": "^3.4.6",
33
- "deepbase-json": "^3.4.6",
32
+ "deepbase": "^3.4.9",
34
33
  "elevenlabs": "^1.59.0",
35
34
  "grammy": "^1.21.0",
36
35
  "openai": "^6.19.0",
package/src/core/index.ts CHANGED
@@ -49,16 +49,25 @@ function defaultBackend(): "claude" | "codex" {
49
49
  }
50
50
 
51
51
  function getBackend(chatId: string): "claude" | "codex" {
52
+ const deps = checkDeps();
53
+
54
+ const preferInstalled = (candidate: "claude" | "codex"): "claude" | "codex" => {
55
+ if (candidate === "claude" && !deps.claude && deps.codex) return "codex";
56
+ if (candidate === "codex" && !deps.codex && deps.claude) return "claude";
57
+ return candidate;
58
+ };
59
+
52
60
  const current = backendState.get(chatId);
53
- if (current) return current;
61
+ if (current) return preferInstalled(current);
54
62
 
55
63
  const fromHistory = getLastBackend(chatId);
56
64
  if (fromHistory) {
57
- backendState.set(chatId, fromHistory);
58
- return fromHistory;
65
+ const resolved = preferInstalled(fromHistory);
66
+ backendState.set(chatId, resolved);
67
+ return resolved;
59
68
  }
60
69
 
61
- return defaultBackend();
70
+ return preferInstalled(defaultBackend());
62
71
  }
63
72
 
64
73
  // Initialize auth + scheduler + attachments
@@ -329,9 +338,15 @@ ${messageText}`;
329
338
  return Response.json(response);
330
339
  }
331
340
 
341
+ const deps = checkDeps();
342
+ if (!deps.claude && !deps.codex) {
343
+ return Response.json({
344
+ text: "No AI CLI is installed. Install at least one:\n<code>bun add -g @anthropic-ai/claude-code</code>\n<code>bun add -g @openai/codex</code>",
345
+ } as CoreResponse);
346
+ }
347
+
332
348
  // Route based on current backend state
333
349
  const backend = getBackend(msg.chatId);
334
- const deps = checkDeps();
335
350
  const canFallback = backend === "codex" ? deps.claude : deps.codex;
336
351
  let agentResponse: string;
337
352
  let historyResponse: string | null = null;
@@ -363,6 +378,11 @@ ${messageText}`;
363
378
  } else {
364
379
  try {
365
380
  agentResponse = await processWithClaude(enrichedMessage, msg.chatId);
381
+ if (agentResponse.startsWith("Error:") && canFallback) {
382
+ log.warn("Claude failed, falling back to Codex");
383
+ agentResponse = await processWithCodex(enrichedMessage);
384
+ usedBackend = "codex";
385
+ }
366
386
  if (isClaudeRateLimitResponse(agentResponse) && canFallback) {
367
387
  log.warn("Claude credits exhausted, falling back to Codex");
368
388
  const codexResponse = await processWithCodex(enrichedMessage);
@@ -3,10 +3,51 @@
3
3
  * @role Resolve agent CLI binaries and execute them via Bun runtime.
4
4
  */
5
5
 
6
+ import { existsSync } from "fs";
7
+ import { delimiter, dirname, join } from "path";
8
+
6
9
  export type AgentCliName = "claude" | "codex";
7
10
 
11
+ function unique(paths: Array<string | null | undefined>): string[] {
12
+ const seen = new Set<string>();
13
+ const out: string[] = [];
14
+ for (const p of paths) {
15
+ if (!p) continue;
16
+ if (seen.has(p)) continue;
17
+ seen.add(p);
18
+ out.push(p);
19
+ }
20
+ return out;
21
+ }
22
+
23
+ function cliOverrideEnvVar(cli: AgentCliName): string | undefined {
24
+ return cli === "codex" ? process.env.ARISA_CODEX_BIN : process.env.ARISA_CLAUDE_BIN;
25
+ }
26
+
27
+ function candidatePaths(cli: AgentCliName): string[] {
28
+ const bunInstall = process.env.BUN_INSTALL?.trim();
29
+ const bunDir = dirname(process.execPath);
30
+ const fromPath = Bun.which(cli);
31
+ const fromEnvPath = (process.env.PATH || "")
32
+ .split(delimiter)
33
+ .map((entry) => entry.trim())
34
+ .filter(Boolean)
35
+ .map((entry) => join(entry, cli));
36
+
37
+ return unique([
38
+ cliOverrideEnvVar(cli),
39
+ bunInstall ? join(bunInstall, "bin", cli) : null,
40
+ join(bunDir, cli),
41
+ fromPath,
42
+ ...fromEnvPath,
43
+ ]);
44
+ }
45
+
8
46
  export function resolveAgentCliPath(cli: AgentCliName): string | null {
9
- return Bun.which(cli);
47
+ for (const candidate of candidatePaths(cli)) {
48
+ if (existsSync(candidate)) return candidate;
49
+ }
50
+ return null;
10
51
  }
11
52
 
12
53
  export function isAgentCliInstalled(cli: AgentCliName): boolean {
@@ -16,7 +57,7 @@ export function isAgentCliInstalled(cli: AgentCliName): boolean {
16
57
  export function buildBunWrappedAgentCliCommand(cli: AgentCliName, args: string[]): string[] {
17
58
  const cliPath = resolveAgentCliPath(cli);
18
59
  if (!cliPath) {
19
- throw new Error(`${cli} CLI not found in PATH`);
60
+ throw new Error(`${cli} CLI not found`);
20
61
  }
21
62
  return ["bun", "--bun", cliPath, ...args];
22
63
  }