friend-assistant 0.1.6 → 0.1.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/README.md +1 -0
- package/dist/BUILD.json +2 -2
- package/dist/friend.mjs +78 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -89,6 +89,7 @@ Every command starts with `friend`. If you run Friend from the source code, writ
|
|
|
89
89
|
| `friend daemon stop` | Stops the background Friend and the speech engine with it. | Shutting it down. |
|
|
90
90
|
| `friend daemon restart` | Stops it and starts it again. | After changing a setting such as `friend lan on` or a different model. |
|
|
91
91
|
| `friend daemon status` | Says whether the background Friend is running, for how long, and at which address. Exit code 0 when running, 1 when not. | Checking, or in a script. |
|
|
92
|
+
| `friend upgrade` | Updates Friend in one go: checks npm for the newest version, stops the background Friend, installs it, and starts it again. Add `--force` to reinstall the same version. If Friend runs in a terminal instead, it asks you to press Ctrl+C there first. | A new version is out. |
|
|
92
93
|
| `friend lan` (or `friend lan status`) | Shows what Friend listens on and the addresses to open. | Checking, or finding the address for your phone. |
|
|
93
94
|
| `friend lan on` | Lets other devices on your network open Friend. Prints the addresses and the things to know (plain http, no microphone on other devices, firewall prompt). | Using Friend from a phone or another PC. |
|
|
94
95
|
| `friend lan on --https` | The same, with a secure `https://` address (Friend makes its own certificate), so a phone may use the microphone and camera. | Talking to Friend from a phone. |
|
package/dist/BUILD.json
CHANGED
package/dist/friend.mjs
CHANGED
|
@@ -6884,13 +6884,13 @@ function realish(abs) {
|
|
|
6884
6884
|
tail2.unshift(cur.slice(parent.length).replace(/^[\\/]+/, ""));
|
|
6885
6885
|
cur = parent;
|
|
6886
6886
|
}
|
|
6887
|
-
let
|
|
6887
|
+
let real2;
|
|
6888
6888
|
try {
|
|
6889
|
-
|
|
6889
|
+
real2 = realpathSync.native(cur);
|
|
6890
6890
|
} catch {
|
|
6891
6891
|
return UNRESOLVABLE + abs;
|
|
6892
6892
|
}
|
|
6893
|
-
return tail2.length ? resolve3(
|
|
6893
|
+
return tail2.length ? resolve3(real2, ...tail2) : real2;
|
|
6894
6894
|
}
|
|
6895
6895
|
function within(root, target) {
|
|
6896
6896
|
if (target.startsWith(UNRESOLVABLE)) return false;
|
|
@@ -8951,6 +8951,77 @@ async function daemonCommand(args, io2, deps = realDeps) {
|
|
|
8951
8951
|
}
|
|
8952
8952
|
}
|
|
8953
8953
|
|
|
8954
|
+
// ../agent-cli/src/commands/upgrade.ts
|
|
8955
|
+
import crossSpawn5 from "cross-spawn";
|
|
8956
|
+
var PACKAGE = "friend-assistant";
|
|
8957
|
+
var real = {
|
|
8958
|
+
current: () => true ? "0.1.7" : "development",
|
|
8959
|
+
latest: () => new Promise((resolve10) => {
|
|
8960
|
+
const child = crossSpawn5("npm", ["view", PACKAGE, "version", "--prefer-online"], { stdio: ["ignore", "pipe", "ignore"] });
|
|
8961
|
+
let out = "";
|
|
8962
|
+
child.stdout?.on("data", (d) => out += d.toString());
|
|
8963
|
+
child.on("error", () => resolve10(null));
|
|
8964
|
+
child.on("close", (code) => resolve10(code === 0 && /^\d+\.\d+\.\d+/.test(out.trim()) ? out.trim().split(/\s+/)[0] : null));
|
|
8965
|
+
}),
|
|
8966
|
+
install: (version) => new Promise((resolve10) => {
|
|
8967
|
+
const child = crossSpawn5("npm", ["install", "-g", `${PACKAGE}@${version}`, "--prefer-online"], { stdio: "inherit" });
|
|
8968
|
+
child.on("error", () => resolve10(1));
|
|
8969
|
+
child.on("close", (code) => resolve10(code ?? 1));
|
|
8970
|
+
}),
|
|
8971
|
+
startAgain: () => new Promise((resolve10) => {
|
|
8972
|
+
const child = crossSpawn5("friend", ["daemon", "start"], { stdio: "inherit" });
|
|
8973
|
+
child.on("error", () => resolve10(1));
|
|
8974
|
+
child.on("close", (code) => resolve10(code ?? 1));
|
|
8975
|
+
}),
|
|
8976
|
+
daemon: realDeps
|
|
8977
|
+
};
|
|
8978
|
+
var newer = (a, b) => {
|
|
8979
|
+
const n = (v) => v.split(/[.-]/).slice(0, 3).map((x2) => Number(x2) || 0);
|
|
8980
|
+
const [x, y] = [n(a), n(b)];
|
|
8981
|
+
for (let i = 0; i < 3; i++) if ((x[i] ?? 0) !== (y[i] ?? 0)) return (x[i] ?? 0) > (y[i] ?? 0);
|
|
8982
|
+
return false;
|
|
8983
|
+
};
|
|
8984
|
+
async function upgradeCommand(args, io2, deps = real) {
|
|
8985
|
+
const force = args.includes("--force");
|
|
8986
|
+
if (args.some((a) => a !== "--force")) {
|
|
8987
|
+
io2.err("Usage: friend upgrade [--force]");
|
|
8988
|
+
return 1;
|
|
8989
|
+
}
|
|
8990
|
+
const current = deps.current();
|
|
8991
|
+
io2.out(`Installed: ${current}`);
|
|
8992
|
+
const latest = await deps.latest();
|
|
8993
|
+
if (!latest) {
|
|
8994
|
+
io2.err("Could not ask npm for the newest version. Check your internet connection and try again.");
|
|
8995
|
+
return 1;
|
|
8996
|
+
}
|
|
8997
|
+
io2.out(`Newest: ${latest}`);
|
|
8998
|
+
if (!force && !newer(latest, current)) {
|
|
8999
|
+
io2.out("Friend is already up to date.");
|
|
9000
|
+
return 0;
|
|
9001
|
+
}
|
|
9002
|
+
const cfg = loadConfig(io2.dataDir);
|
|
9003
|
+
const wasRunning = running(io2.dataDir, deps.daemon) !== null;
|
|
9004
|
+
if (wasRunning) {
|
|
9005
|
+
io2.out("Stopping the background Friend\u2026");
|
|
9006
|
+
const code2 = await daemonCommand(["stop"], io2, deps.daemon);
|
|
9007
|
+
if (code2 !== 0) return code2;
|
|
9008
|
+
} else if (await deps.daemon.portOpen(cfg.port, 500)) {
|
|
9009
|
+
io2.err(`Friend is running in a terminal (port ${cfg.port} is in use). Press Ctrl+C there to stop it, then run: friend upgrade`);
|
|
9010
|
+
return 1;
|
|
9011
|
+
}
|
|
9012
|
+
io2.out(`Installing ${PACKAGE}@${latest}\u2026`);
|
|
9013
|
+
const code = await deps.install(latest);
|
|
9014
|
+
if (code !== 0) {
|
|
9015
|
+
io2.err("The install failed. If it says EBUSY or EPERM, close whatever is using Friend (a terminal running it, a voice process) and run: friend upgrade");
|
|
9016
|
+
if (wasRunning) await deps.startAgain();
|
|
9017
|
+
return 1;
|
|
9018
|
+
}
|
|
9019
|
+
io2.out(`Upgraded ${current} \u2192 ${latest}.`);
|
|
9020
|
+
if (wasRunning) return deps.startAgain();
|
|
9021
|
+
io2.out("Start it with: friend start (or in the background: friend daemon start)");
|
|
9022
|
+
return 0;
|
|
9023
|
+
}
|
|
9024
|
+
|
|
8954
9025
|
// ../agent-cli/src/commands/claude.ts
|
|
8955
9026
|
async function check2(run2, command) {
|
|
8956
9027
|
const v = await run2(command, ["--version"]);
|
|
@@ -9088,6 +9159,7 @@ var USAGE4 = `Usage: friend <command>
|
|
|
9088
9159
|
setup create the owner account (password, PIN, assistant name)
|
|
9089
9160
|
start run the gateway and a local device node
|
|
9090
9161
|
daemon start|stop|restart|status run Friend in the background (no terminal needed), stop it, or see if it is running
|
|
9162
|
+
upgrade [--force] stop the background Friend, install the newest version, start it again
|
|
9091
9163
|
pair print a one-time code to connect another PC
|
|
9092
9164
|
node --url <ws-url> --code <code> [--roots a,b] [--name pc]
|
|
9093
9165
|
connect this PC to a Friend gateway
|
|
@@ -9114,6 +9186,8 @@ async function run(argv, io2) {
|
|
|
9114
9186
|
return await startCommand(io2);
|
|
9115
9187
|
case "daemon":
|
|
9116
9188
|
return await daemonCommand(rest, io2);
|
|
9189
|
+
case "upgrade":
|
|
9190
|
+
return await upgradeCommand(rest, io2);
|
|
9117
9191
|
case "pair":
|
|
9118
9192
|
return await pairCommand(io2);
|
|
9119
9193
|
case "node":
|
|
@@ -9134,7 +9208,7 @@ async function run(argv, io2) {
|
|
|
9134
9208
|
case "version":
|
|
9135
9209
|
case "--version":
|
|
9136
9210
|
case "-v":
|
|
9137
|
-
io2.out(true ? "0.1.
|
|
9211
|
+
io2.out(true ? "0.1.7" : "development");
|
|
9138
9212
|
return 0;
|
|
9139
9213
|
case "lan":
|
|
9140
9214
|
return await lanCommand(rest, io2);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "friend-assistant",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "A self-hosted personal AI assistant for your own PC: a full-screen stage, voice, tools with your approval, and your Claude subscription or a local model.",
|
|
5
5
|
"keywords": ["ai", "assistant", "jarvis", "voice", "claude", "ollama", "mcp", "self-hosted"],
|
|
6
6
|
"license": "UNLICENSED",
|