feral-agent 2026.7.19 → 2026.8.1
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/feral.js +90 -14
- package/package.json +6 -6
package/bin/feral.js
CHANGED
|
@@ -15,33 +15,109 @@
|
|
|
15
15
|
import { spawnSync } from "node:child_process";
|
|
16
16
|
import { createRequire } from "node:module";
|
|
17
17
|
import { join, dirname } from "node:path";
|
|
18
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
18
|
+
import { accessSync, constants, existsSync, readFileSync } from "node:fs";
|
|
19
19
|
import { fileURLToPath } from "node:url";
|
|
20
20
|
|
|
21
21
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
22
22
|
const require = createRequire(import.meta.url);
|
|
23
23
|
const ext = process.platform === "win32" ? ".exe" : "";
|
|
24
24
|
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
// `feral update` is handled HERE and never reaches the Rust binary. Two reasons,
|
|
26
|
+
// both fatal if we delegated: on Windows npm cannot overwrite a running .exe, and
|
|
27
|
+
// a half-installed machine (platform package missing) has no Rust binary to run —
|
|
28
|
+
// which is exactly when you most want to re-install. This shim is the one file in
|
|
29
|
+
// the install that is never locked.
|
|
30
|
+
if (process.argv[2] === "update") {
|
|
31
|
+
const win = process.platform === "win32";
|
|
32
|
+
// Was a gateway serving before the update? If so it is running the OLD binary,
|
|
33
|
+
// and a Discord/Slack connector keeps running it until something restarts it.
|
|
34
|
+
// Checked BEFORE the install so we never start a daemon the user didn't have.
|
|
35
|
+
const old = exeFor();
|
|
36
|
+
const wasOnline =
|
|
37
|
+
!!old && spawnSync(old, ["gateway", "status"], { stdio: "ignore" }).status === 0;
|
|
38
|
+
|
|
39
|
+
const install = spawnSync(win ? "npm.cmd" : "npm", ["install", "-g", "feral-agent@latest"], {
|
|
40
|
+
stdio: "inherit",
|
|
41
|
+
shell: win, // npm.cmd is a batch file; Node needs a shell to exec it
|
|
42
|
+
});
|
|
43
|
+
if (install.error || install.status !== 0) {
|
|
44
|
+
process.stderr.write(`feral: update failed.\n${updateFailureHint(win)}`);
|
|
45
|
+
process.exit(install.status ?? 1);
|
|
46
|
+
}
|
|
47
|
+
if (!wasOnline) {
|
|
48
|
+
process.stdout.write("feral: updated. Start it with: feral gateway start\n");
|
|
49
|
+
process.exit(0);
|
|
50
|
+
}
|
|
51
|
+
// Re-run THIS file — npm has just replaced it with the new version, so the
|
|
52
|
+
// restart is driven by the new shim and starts the new binary.
|
|
53
|
+
process.stdout.write("feral: updated — restarting the gateway…\n");
|
|
54
|
+
const restart = spawnSync(
|
|
55
|
+
process.execPath,
|
|
56
|
+
[fileURLToPath(import.meta.url), "gateway", "restart"],
|
|
57
|
+
{ stdio: "inherit" },
|
|
58
|
+
);
|
|
59
|
+
process.exit(restart.status ?? 1);
|
|
32
60
|
}
|
|
33
61
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
62
|
+
/**
|
|
63
|
+
* What to print when `npm install -g` fails. NOT "run the command that just
|
|
64
|
+
* failed": the common Unix failure is EACCES on a root-owned global prefix, and
|
|
65
|
+
* repeating it there fails identically forever — which is how a working update
|
|
66
|
+
* path reads as a broken product.
|
|
67
|
+
*
|
|
68
|
+
* The cause is diagnosed, not guessed: ask npm where its global prefix is and
|
|
69
|
+
* test whether we can write to it. Guessing from uid instead would tell every
|
|
70
|
+
* nvm/homebrew user to `sudo`, and `sudo npm -g` on those installs is the one
|
|
71
|
+
* thing that actually breaks them.
|
|
72
|
+
*/
|
|
73
|
+
function updateFailureHint(win) {
|
|
74
|
+
const manual = "Install manually with:\n npm install -g feral-agent@latest\n";
|
|
75
|
+
if (win) return manual; // no EACCES-on-prefix equivalent worth guessing at
|
|
76
|
+
|
|
77
|
+
const prefix = spawnSync("npm", ["prefix", "-g"], { encoding: "utf8" });
|
|
78
|
+
if (prefix.error || prefix.status !== 0) return manual;
|
|
79
|
+
const root = prefix.stdout.trim();
|
|
80
|
+
// Global packages land in <prefix>/lib/node_modules; fall back outward for
|
|
81
|
+
// layouts that differ, and give up rather than invent a diagnosis.
|
|
82
|
+
const target = [join(root, "lib", "node_modules"), join(root, "lib"), root].find(existsSync);
|
|
83
|
+
if (!target) return manual;
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
accessSync(target, constants.W_OK);
|
|
87
|
+
} catch {
|
|
88
|
+
return (
|
|
89
|
+
`No write access to npm's global directory (${target}).\n` +
|
|
90
|
+
"Either install as root:\n" +
|
|
91
|
+
" sudo npm install -g feral-agent@latest\n" +
|
|
92
|
+
"or point npm at a prefix you own — this also makes every future\n" +
|
|
93
|
+
"`feral update` work without sudo:\n" +
|
|
94
|
+
" npm config set prefix ~/.npm-global\n" +
|
|
95
|
+
" export PATH=~/.npm-global/bin:$PATH # add this to your shell rc\n" +
|
|
96
|
+
" npm install -g feral-agent@latest\n"
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
return manual;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Resolve the platform binary, or null when this install has none. */
|
|
103
|
+
function exeFor() {
|
|
104
|
+
const pkg = `@bloommedia/feral-agent-${process.platform}-${process.arch}`;
|
|
105
|
+
try {
|
|
106
|
+
const p = require.resolve(`${pkg}/feral-cli${ext}`);
|
|
107
|
+
if (existsSync(p)) return p;
|
|
108
|
+
} catch {
|
|
109
|
+
/* fall through to the dev path */
|
|
110
|
+
}
|
|
37
111
|
const local = join(here, "..", "vendor", `feral-cli${ext}`);
|
|
38
|
-
|
|
112
|
+
return existsSync(local) ? local : null;
|
|
39
113
|
}
|
|
40
114
|
|
|
41
|
-
|
|
115
|
+
const exe = exeFor();
|
|
116
|
+
|
|
117
|
+
if (!exe) {
|
|
42
118
|
process.stderr.write(
|
|
43
119
|
`Feral could not find its runtime for ${process.platform}-${process.arch}.\n` +
|
|
44
|
-
`The matching package
|
|
120
|
+
`The matching package \`@bloommedia/feral-agent-${process.platform}-${process.arch}\` may have failed to install ` +
|
|
45
121
|
"(a blocked optional dependency, an unsupported platform, or " +
|
|
46
122
|
"`--ignore-optional`).\n" +
|
|
47
123
|
"Reinstall with: npm install -g feral-agent\n" +
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "feral-agent",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.8.1",
|
|
4
4
|
"description": "Feral Agent — proactive, portable AI agent with a native security sandbox",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "src/index.ts",
|
|
@@ -46,10 +46,10 @@
|
|
|
46
46
|
"package:win": "node scripts/package-win.mjs"
|
|
47
47
|
},
|
|
48
48
|
"optionalDependencies": {
|
|
49
|
-
"@bloommedia/feral-agent-win32-x64": "2026.
|
|
50
|
-
"@bloommedia/feral-agent-darwin-arm64": "2026.
|
|
51
|
-
"@bloommedia/feral-agent-darwin-x64": "2026.
|
|
52
|
-
"@bloommedia/feral-agent-linux-x64": "2026.
|
|
49
|
+
"@bloommedia/feral-agent-win32-x64": "2026.8.1",
|
|
50
|
+
"@bloommedia/feral-agent-darwin-arm64": "2026.8.1",
|
|
51
|
+
"@bloommedia/feral-agent-darwin-x64": "2026.8.1",
|
|
52
|
+
"@bloommedia/feral-agent-linux-x64": "2026.8.1"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@slack/socket-mode": "^2.0.7",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"discord.js": "^14.26.4",
|
|
62
62
|
"gpt-tokenizer": "^3.4.0",
|
|
63
63
|
"qrcode-terminal": "^0.12.0",
|
|
64
|
-
"typescript": "^
|
|
64
|
+
"typescript": "^7.0.0"
|
|
65
65
|
},
|
|
66
66
|
"overrides": {
|
|
67
67
|
"undici": ">=6.27.0"
|