volute 0.8.1 → 0.8.3
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 +1 -1
- package/dist/{chunk-XSJ27WEM.js → chunk-6RDCTVQK.js} +16 -1
- package/dist/{chunk-HZ5LTOEJ.js → chunk-YNNK4QN2.js} +16 -1
- package/dist/cli.js +7 -7
- package/dist/{daemon-restart-CPBLMMRI.js → daemon-restart-IMNCBWFV.js} +7 -2
- package/dist/{down-O4EWZTVA.js → down-4DGRZRJU.js} +1 -1
- package/dist/{package-RJSONENE.js → package-2S7APQBC.js} +1 -1
- package/dist/{service-XCADRKIS.js → service-56CY4S6Z.js} +24 -0
- package/dist/{setup-32KH5KLN.js → setup-7SPMWF2O.js} +22 -0
- package/dist/{up-V6EAA7OZ.js → up-RZJMSVQS.js} +1 -1
- package/dist/{update-EUCZ7XGG.js → update-3TGXUTO2.js} +10 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -245,7 +245,7 @@ npm install -g volute
|
|
|
245
245
|
sudo $(which volute) setup --host 0.0.0.0
|
|
246
246
|
```
|
|
247
247
|
|
|
248
|
-
> **Note:**
|
|
248
|
+
> **Note:** The initial `sudo $(which volute)` is needed because `sudo` resets PATH. After setup completes, a wrapper at `/usr/local/bin/volute` is created so `sudo volute` works normally going forward.
|
|
249
249
|
|
|
250
250
|
This installs a system-level systemd service with data at `/var/lib/volute` and user isolation enabled. Check status with `systemctl status volute`. Uninstall with `sudo volute setup uninstall --force`.
|
|
251
251
|
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "./chunk-DP2DX4WV.js";
|
|
8
8
|
|
|
9
9
|
// src/commands/up.ts
|
|
10
|
-
import { spawn } from "child_process";
|
|
10
|
+
import { execFileSync, spawn } from "child_process";
|
|
11
11
|
import { existsSync, mkdirSync, openSync, readFileSync } from "fs";
|
|
12
12
|
import { dirname, resolve } from "path";
|
|
13
13
|
function readGlobalConfig() {
|
|
@@ -20,12 +20,27 @@ function readGlobalConfig() {
|
|
|
20
20
|
process.exit(1);
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
+
function isSystemdServiceEnabled() {
|
|
24
|
+
try {
|
|
25
|
+
execFileSync("systemctl", ["is-enabled", "--quiet", "volute"]);
|
|
26
|
+
return true;
|
|
27
|
+
} catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
23
31
|
async function run(args) {
|
|
24
32
|
const { flags } = parseArgs(args, {
|
|
25
33
|
port: { type: "number" },
|
|
26
34
|
host: { type: "string" },
|
|
27
35
|
foreground: { type: "boolean" }
|
|
28
36
|
});
|
|
37
|
+
if (!flags.foreground && isSystemdServiceEnabled()) {
|
|
38
|
+
console.error("Volute is managed by a systemd service.");
|
|
39
|
+
console.error("Use: sudo systemctl start volute");
|
|
40
|
+
console.error(" sudo systemctl restart volute");
|
|
41
|
+
console.error(" systemctl status volute");
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
29
44
|
const config = readGlobalConfig();
|
|
30
45
|
const port = flags.port ?? config.port ?? 4200;
|
|
31
46
|
const hostname = flags.host ?? config.hostname ?? "127.0.0.1";
|
|
@@ -4,9 +4,21 @@ import {
|
|
|
4
4
|
} from "./chunk-DP2DX4WV.js";
|
|
5
5
|
|
|
6
6
|
// src/commands/down.ts
|
|
7
|
+
import { execFileSync } from "child_process";
|
|
7
8
|
import { existsSync, readFileSync, unlinkSync } from "fs";
|
|
8
9
|
import { resolve } from "path";
|
|
10
|
+
function isSystemdServiceEnabled() {
|
|
11
|
+
try {
|
|
12
|
+
execFileSync("systemctl", ["is-enabled", "--quiet", "volute"]);
|
|
13
|
+
return true;
|
|
14
|
+
} catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
9
18
|
async function stopDaemon() {
|
|
19
|
+
if (isSystemdServiceEnabled()) {
|
|
20
|
+
return { stopped: false, reason: "systemd" };
|
|
21
|
+
}
|
|
10
22
|
const home = voluteHome();
|
|
11
23
|
const pidPath = resolve(home, "daemon.pid");
|
|
12
24
|
if (!existsSync(pidPath)) {
|
|
@@ -99,7 +111,10 @@ async function stopDaemon() {
|
|
|
99
111
|
async function run(_args) {
|
|
100
112
|
const result = await stopDaemon();
|
|
101
113
|
if (result.stopped) return;
|
|
102
|
-
if (result.reason === "
|
|
114
|
+
if (result.reason === "systemd") {
|
|
115
|
+
console.error("Volute is managed by a systemd service.");
|
|
116
|
+
console.error("Use: sudo systemctl stop volute");
|
|
117
|
+
} else if (result.reason === "orphan") {
|
|
103
118
|
console.error(`Daemon appears to be running on port ${result.port} but PID file is missing.`);
|
|
104
119
|
console.error(`Kill the process manually: lsof -ti :${result.port} | xargs kill`);
|
|
105
120
|
} else if (result.reason === "not-running") {
|
package/dist/cli.js
CHANGED
|
@@ -9,7 +9,7 @@ if (!process.env.VOLUTE_HOME) {
|
|
|
9
9
|
var command = process.argv[2];
|
|
10
10
|
var args = process.argv.slice(3);
|
|
11
11
|
if (command === "--version" || command === "-v") {
|
|
12
|
-
const { default: pkg } = await import("./package-
|
|
12
|
+
const { default: pkg } = await import("./package-2S7APQBC.js");
|
|
13
13
|
console.log(pkg.version);
|
|
14
14
|
process.exit(0);
|
|
15
15
|
}
|
|
@@ -39,22 +39,22 @@ switch (command) {
|
|
|
39
39
|
await import("./env-KMNYGVZ2.js").then((m) => m.run(args));
|
|
40
40
|
break;
|
|
41
41
|
case "up":
|
|
42
|
-
await import("./up-
|
|
42
|
+
await import("./up-RZJMSVQS.js").then((m) => m.run(args));
|
|
43
43
|
break;
|
|
44
44
|
case "down":
|
|
45
|
-
await import("./down-
|
|
45
|
+
await import("./down-4DGRZRJU.js").then((m) => m.run(args));
|
|
46
46
|
break;
|
|
47
47
|
case "restart":
|
|
48
|
-
await import("./daemon-restart-
|
|
48
|
+
await import("./daemon-restart-IMNCBWFV.js").then((m) => m.run(args));
|
|
49
49
|
break;
|
|
50
50
|
case "setup":
|
|
51
|
-
await import("./setup-
|
|
51
|
+
await import("./setup-7SPMWF2O.js").then((m) => m.run(args));
|
|
52
52
|
break;
|
|
53
53
|
case "service":
|
|
54
|
-
await import("./service-
|
|
54
|
+
await import("./service-56CY4S6Z.js").then((m) => m.run(args));
|
|
55
55
|
break;
|
|
56
56
|
case "update":
|
|
57
|
-
await import("./update-
|
|
57
|
+
await import("./update-3TGXUTO2.js").then((m) => m.run(args));
|
|
58
58
|
break;
|
|
59
59
|
case "--help":
|
|
60
60
|
case "-h":
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
run
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-6RDCTVQK.js";
|
|
5
5
|
import {
|
|
6
6
|
stopDaemon
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-YNNK4QN2.js";
|
|
8
8
|
import "./chunk-D424ZQGI.js";
|
|
9
9
|
import "./chunk-DP2DX4WV.js";
|
|
10
10
|
import "./chunk-K3NQKI34.js";
|
|
@@ -12,6 +12,11 @@ import "./chunk-K3NQKI34.js";
|
|
|
12
12
|
// src/commands/daemon-restart.ts
|
|
13
13
|
async function run2(args) {
|
|
14
14
|
const result = await stopDaemon();
|
|
15
|
+
if (!result.stopped && result.reason === "systemd") {
|
|
16
|
+
console.error("Volute is managed by a systemd service.");
|
|
17
|
+
console.error("Use: sudo systemctl restart volute");
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
15
20
|
if (!result.stopped && result.reason === "kill-failed") {
|
|
16
21
|
console.error("Cannot restart: failed to stop the running daemon.");
|
|
17
22
|
process.exit(1);
|
|
@@ -4,7 +4,7 @@ import "./chunk-K3NQKI34.js";
|
|
|
4
4
|
// package.json
|
|
5
5
|
var package_default = {
|
|
6
6
|
name: "volute",
|
|
7
|
-
version: "0.8.
|
|
7
|
+
version: "0.8.3",
|
|
8
8
|
description: "CLI for creating and managing self-modifying AI agents powered by the Claude Agent SDK",
|
|
9
9
|
type: "module",
|
|
10
10
|
license: "MIT",
|
|
@@ -15,6 +15,7 @@ import { resolve } from "path";
|
|
|
15
15
|
import { promisify } from "util";
|
|
16
16
|
var execFileAsync = promisify(execFile);
|
|
17
17
|
var HOST_RE = /^[a-zA-Z0-9.:_-]+$/;
|
|
18
|
+
var SYSTEM_SERVICE_PATH = "/etc/systemd/system/volute.service";
|
|
18
19
|
function validateHost(host) {
|
|
19
20
|
if (!HOST_RE.test(host)) {
|
|
20
21
|
throw new Error(`Invalid host: ${host}`);
|
|
@@ -82,6 +83,12 @@ async function install(port, host) {
|
|
|
82
83
|
await execFileAsync("launchctl", ["load", path]);
|
|
83
84
|
console.log("Service installed and loaded. Volute daemon will start on login.");
|
|
84
85
|
} else if (platform === "linux") {
|
|
86
|
+
if (existsSync(SYSTEM_SERVICE_PATH)) {
|
|
87
|
+
console.error("A system-level Volute service is already installed (via `volute setup`).");
|
|
88
|
+
console.error("Use `systemctl status volute` to check its status.");
|
|
89
|
+
console.error("To remove it first: sudo volute setup uninstall");
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
85
92
|
if (process.getuid?.() === 0) {
|
|
86
93
|
console.error(
|
|
87
94
|
"Error: `volute service install` uses systemd user services, which don't work as root."
|
|
@@ -147,6 +154,23 @@ async function status() {
|
|
|
147
154
|
console.log("Service installed but not currently loaded.");
|
|
148
155
|
}
|
|
149
156
|
} else if (platform === "linux") {
|
|
157
|
+
if (existsSync(SYSTEM_SERVICE_PATH)) {
|
|
158
|
+
try {
|
|
159
|
+
const { stdout } = await execFileAsync("systemctl", ["status", "volute", "--no-pager"]);
|
|
160
|
+
console.log(stdout);
|
|
161
|
+
} catch (err) {
|
|
162
|
+
const e = err;
|
|
163
|
+
if (e.stdout) {
|
|
164
|
+
console.log(e.stdout);
|
|
165
|
+
} else {
|
|
166
|
+
console.error("System service installed but could not retrieve status.");
|
|
167
|
+
if (e.stderr) console.error(e.stderr);
|
|
168
|
+
else if (e.message) console.error(e.message);
|
|
169
|
+
console.error("Try running: systemctl status volute");
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
150
174
|
if (!existsSync(unitPath())) {
|
|
151
175
|
console.log("Service not installed.");
|
|
152
176
|
return;
|
|
@@ -18,6 +18,8 @@ import { homedir } from "os";
|
|
|
18
18
|
import { dirname } from "path";
|
|
19
19
|
var SERVICE_NAME = "volute.service";
|
|
20
20
|
var SERVICE_PATH = `/etc/systemd/system/${SERVICE_NAME}`;
|
|
21
|
+
var PROFILE_PATH = "/etc/profile.d/volute.sh";
|
|
22
|
+
var WRAPPER_PATH = "/usr/local/bin/volute";
|
|
21
23
|
var DATA_DIR = "/var/lib/volute";
|
|
22
24
|
var AGENTS_DIR = "/agents";
|
|
23
25
|
var HOST_RE = /^[a-zA-Z0-9.:_-]+$/;
|
|
@@ -93,6 +95,24 @@ function install(port, host) {
|
|
|
93
95
|
execFileSync("chmod", ["755", DATA_DIR]);
|
|
94
96
|
execFileSync("chmod", ["755", AGENTS_DIR]);
|
|
95
97
|
console.log("Set permissions on directories");
|
|
98
|
+
writeFileSync(
|
|
99
|
+
PROFILE_PATH,
|
|
100
|
+
`export VOLUTE_HOME=${DATA_DIR}
|
|
101
|
+
export VOLUTE_AGENTS_DIR=${AGENTS_DIR}
|
|
102
|
+
`
|
|
103
|
+
);
|
|
104
|
+
console.log(`Wrote ${PROFILE_PATH}`);
|
|
105
|
+
const binDir = dirname(voluteBin);
|
|
106
|
+
if (voluteBin !== WRAPPER_PATH && !voluteBin.startsWith("/usr/bin")) {
|
|
107
|
+
const wrapper = `#!/bin/sh
|
|
108
|
+
export PATH="${binDir}:$PATH"
|
|
109
|
+
export VOLUTE_HOME="${DATA_DIR}"
|
|
110
|
+
export VOLUTE_AGENTS_DIR="${AGENTS_DIR}"
|
|
111
|
+
exec "${voluteBin}" "$@"
|
|
112
|
+
`;
|
|
113
|
+
writeFileSync(WRAPPER_PATH, wrapper, { mode: 493 });
|
|
114
|
+
console.log(`Wrote ${WRAPPER_PATH} (wrapper for ${voluteBin})`);
|
|
115
|
+
}
|
|
96
116
|
writeFileSync(SERVICE_PATH, generateUnit(voluteBin, port, host ?? "0.0.0.0"));
|
|
97
117
|
console.log(`Wrote ${SERVICE_PATH}`);
|
|
98
118
|
try {
|
|
@@ -135,6 +155,8 @@ function uninstall(force) {
|
|
|
135
155
|
console.warn("Warning: failed to disable service (may already be stopped)");
|
|
136
156
|
}
|
|
137
157
|
unlinkSync(SERVICE_PATH);
|
|
158
|
+
if (existsSync(PROFILE_PATH)) unlinkSync(PROFILE_PATH);
|
|
159
|
+
if (existsSync(WRAPPER_PATH)) unlinkSync(WRAPPER_PATH);
|
|
138
160
|
try {
|
|
139
161
|
execFileSync("systemctl", ["daemon-reload"]);
|
|
140
162
|
} catch {
|
|
@@ -12,9 +12,19 @@ import {
|
|
|
12
12
|
import "./chunk-K3NQKI34.js";
|
|
13
13
|
|
|
14
14
|
// src/commands/update.ts
|
|
15
|
+
import { execFileSync } from "child_process";
|
|
15
16
|
import { existsSync, readFileSync, unlinkSync } from "fs";
|
|
16
17
|
import { resolve } from "path";
|
|
17
18
|
async function run(_args) {
|
|
19
|
+
try {
|
|
20
|
+
execFileSync("systemctl", ["is-enabled", "--quiet", "volute"]);
|
|
21
|
+
console.error("Volute is managed by a systemd service.");
|
|
22
|
+
console.error("To update, run:");
|
|
23
|
+
console.error(" sudo npm install -g volute@latest");
|
|
24
|
+
console.error(" sudo systemctl restart volute");
|
|
25
|
+
process.exit(1);
|
|
26
|
+
} catch {
|
|
27
|
+
}
|
|
18
28
|
const result = await checkForUpdate();
|
|
19
29
|
if (result.checkFailed) {
|
|
20
30
|
console.error("Could not reach npm registry. Check your network connection and try again.");
|