arisa 4.0.24 → 4.1.4

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.
@@ -1,4 +1,5 @@
1
1
  import { mkdir } from "node:fs/promises";
2
+ import crypto from "node:crypto";
2
3
  import os from "node:os";
3
4
  import path from "node:path";
4
5
  import { fileURLToPath } from "node:url";
@@ -9,7 +10,15 @@ export const stateDir = path.join(arisaHomeDir, "state");
9
10
  export const configFile = path.join(stateDir, "config.json");
10
11
  export const servicePidFile = path.join(stateDir, "arisa.pid");
11
12
  export const serviceLogFile = path.join(stateDir, "arisa.log");
12
- export const arisaIpcSocketFile = path.join(stateDir, "arisa.sock");
13
+ export function createIpcSocketPath({ homeDir = arisaHomeDir, platform = process.platform } = {}) {
14
+ if (platform === "win32") {
15
+ const suffix = crypto.createHash("sha256").update(homeDir).digest("hex").slice(0, 16);
16
+ return `\\\\.\\pipe\\arisa-${suffix}`;
17
+ }
18
+ return path.join(homeDir, "state", "arisa.sock");
19
+ }
20
+
21
+ export const arisaIpcSocketFile = createIpcSocketPath();
13
22
  export const tasksFile = path.join(stateDir, "tasks.json");
14
23
  export const toolsDir = path.join(arisaHomeDir, "tools");
15
24
  export const chatsDir = path.join(arisaHomeDir, "chats");
@@ -74,7 +74,8 @@ function buildPrompt({ ctx, artifact, transcript, toolResult }) {
74
74
  parts.push(`Important: pre-reasoning media normalization could not be completed, so you do not have a transcript for this audio/video message.`);
75
75
  }
76
76
 
77
- parts.push(`If you need a CLI tool, use list_tools/tool_help/run_tool.`);
77
+ parts.push(`Use read/write/edit for file work in the active workspace, bash for bash-compatible commands, and system_shell for native system commands such as PowerShell on Windows.`);
78
+ parts.push(`If you need an Arisa modular CLI tool, use list_tools/tool_help/run_tool.`);
78
79
  parts.push(`If a tool config is missing, ask the user naturally and then use set_tool_config.`);
79
80
  parts.push(`If the user wants a generated media reply, use send_media_reply.`);
80
81
  return parts.join("\n");
@@ -130,7 +131,7 @@ async function buildAsyncTaskPrompt({ task, artifactStore, toolRegistry, logger
130
131
  }
131
132
 
132
133
  parts.push("Treat this as a new request for the chat and fulfill it now.");
133
- parts.push("If needed, use tools.");
134
+ parts.push("If needed, use read/write/edit, bash, system_shell, or Arisa modular tools via run_tool.");
134
135
  return parts.filter(Boolean).join("\n");
135
136
  }
136
137
 
@@ -142,7 +143,7 @@ function buildAsyncEventPrompt(task) {
142
143
  task.payload.prompt ? `event: ${task.payload.prompt}` : null,
143
144
  "A polling checker detected this external event. Evaluate it and decide the next action.",
144
145
  "If it warrants no action, you may stay silent.",
145
- "If needed, use tools."
146
+ "If needed, use read/write/edit, bash, system_shell, or Arisa modular tools via run_tool."
146
147
  ].filter(Boolean).join("\n");
147
148
  }
148
149
 
@@ -0,0 +1,91 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdtemp, realpath } from "node:fs/promises";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import test from "node:test";
6
+ import { buildPiToolPolicy } from "../src/core/agent/core-tools.js";
7
+ import { createSystemShellTool } from "../src/core/agent/system-shell-tool.js";
8
+ import { applyRuntimeOverrides } from "../src/runtime/create-app.js";
9
+ import { arisaHomeDir } from "../src/runtime/paths.js";
10
+
11
+ test("builds default Pi tool policy for the Arisa home workspace", () => {
12
+ const policy = buildPiToolPolicy({ config: { pi: {} } });
13
+
14
+ assert.equal(policy.workspaceDir, path.resolve(arisaHomeDir));
15
+ assert.equal(policy.tools, undefined);
16
+ assert.equal(policy.excludeTools, undefined);
17
+ assert.deepEqual(
18
+ policy.coreTools.filter((tool) => tool.enabled).map((tool) => tool.name),
19
+ ["read", "bash", "edit", "write"]
20
+ );
21
+ });
22
+
23
+ test("keeps Arisa custom tools available when pi.tools is configured", () => {
24
+ const policy = buildPiToolPolicy({
25
+ config: {
26
+ pi: {
27
+ tools: "read,bash",
28
+ excludeTools: "bash",
29
+ workspaceDir: "~/arisa-workspace",
30
+ shellTimeoutMs: "120000"
31
+ }
32
+ },
33
+ customToolNames: ["run_tool", "system_shell"]
34
+ });
35
+
36
+ assert.deepEqual(policy.tools, ["read", "bash", "run_tool", "system_shell"]);
37
+ assert.deepEqual(policy.excludeTools, ["bash"]);
38
+ assert.equal(policy.shell.timeoutMs, 120000);
39
+ assert.equal(policy.workspaceDir, path.join(os.homedir(), "arisa-workspace"));
40
+ assert.deepEqual(
41
+ policy.coreTools.filter((tool) => tool.enabled).map((tool) => tool.name),
42
+ ["read"]
43
+ );
44
+ });
45
+
46
+ test("applies runtime overrides without dropping persisted Pi config", () => {
47
+ const config = {
48
+ telegram: { token: "token" },
49
+ pi: {
50
+ provider: "openai-codex",
51
+ model: "gpt-5.5",
52
+ apiKey: "persisted"
53
+ }
54
+ };
55
+
56
+ const next = applyRuntimeOverrides(config, {
57
+ pi: {
58
+ model: "anthropic/claude-opus-4-5",
59
+ workspaceDir: "/tmp/arisa",
60
+ tools: "read,bash",
61
+ excludeTools: "write",
62
+ shellTimeoutMs: "90000"
63
+ }
64
+ });
65
+
66
+ assert.equal(next.pi.provider, "anthropic");
67
+ assert.equal(next.pi.model, "claude-opus-4-5");
68
+ assert.equal(next.pi.apiKey, "persisted");
69
+ assert.equal(next.pi.workspaceDir, "/tmp/arisa");
70
+ assert.deepEqual(next.pi.tools, ["read", "bash"]);
71
+ assert.deepEqual(next.pi.excludeTools, ["write"]);
72
+ assert.equal(next.pi.shellTimeoutMs, 90000);
73
+ });
74
+
75
+ test("system_shell runs commands from the configured workspace", async () => {
76
+ const workspaceDir = await mkdtemp(path.join(os.tmpdir(), "arisa-shell-"));
77
+ const tool = createSystemShellTool({
78
+ workspaceDir,
79
+ shell: { timeoutMs: 10_000 }
80
+ });
81
+
82
+ const result = await tool.execute("call-1", {
83
+ command: "node -e \"process.stdout.write(process.cwd())\""
84
+ });
85
+
86
+ const realWorkspaceDir = await realpath(workspaceDir);
87
+ assert.equal(result.isError, false);
88
+ assert.equal(result.details.cwd, workspaceDir);
89
+ assert.equal(result.details.exitCode, 0);
90
+ assert.equal(result.details.stdout, realWorkspaceDir);
91
+ });
@@ -7,6 +7,7 @@ import test from "node:test";
7
7
  import { createArisaClient } from "../src/core/tools/ipc-client.js";
8
8
  import { createArisaCapabilities } from "../src/runtime/arisa-capabilities.js";
9
9
  import { createIpcServer } from "../src/runtime/ipc/ipc-server.js";
10
+ import { createIpcSocketPath } from "../src/runtime/paths.js";
10
11
 
11
12
  function createFakeArtifactStore() {
12
13
  const stores = new Map();
@@ -67,6 +68,15 @@ function createCapabilities(overrides = {}) {
67
68
  });
68
69
  }
69
70
 
71
+ test("uses a Windows named pipe for IPC on Windows", () => {
72
+ const socketPath = createIpcSocketPath({
73
+ homeDir: "C:\\Users\\Arisa\\.arisa",
74
+ platform: "win32"
75
+ });
76
+
77
+ assert.match(socketPath, /^\\\\\.\\pipe\\arisa-[a-f0-9]{16}$/);
78
+ });
79
+
70
80
  function wait(ms) {
71
81
  return new Promise((resolve) => setTimeout(resolve, ms));
72
82
  }