@rynx-ai/daemon 0.1.11-beta.6 → 0.1.11-beta.8
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/dist/setup-service.d.ts
CHANGED
package/dist/setup-service.js
CHANGED
|
@@ -4,6 +4,7 @@ import { createChromeForTestingArtifactStore, isChromeForTestingHostSupported }
|
|
|
4
4
|
import { ensureBundledOfficialPlugins } from "./bundled-plugins.js";
|
|
5
5
|
import { dbPath } from "./db.js";
|
|
6
6
|
import { listPlugins } from "./plugin-store.js";
|
|
7
|
+
export { ensureSystemDependencies, inspectSystemDependencies, } from "./system-dependencies.js";
|
|
7
8
|
export async function prepareBundledPlugins() {
|
|
8
9
|
return ensureBundledOfficialPlugins();
|
|
9
10
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface SystemDependencyStatus {
|
|
2
|
+
installed: boolean;
|
|
3
|
+
detail?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface SystemDependencySnapshot {
|
|
6
|
+
tmux: SystemDependencyStatus;
|
|
7
|
+
}
|
|
8
|
+
export interface SystemDependencyCommandResult {
|
|
9
|
+
exitCode: number | null;
|
|
10
|
+
stdout: string;
|
|
11
|
+
stderr: string;
|
|
12
|
+
errorCode?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface SystemDependencyCommandOptions {
|
|
15
|
+
timeoutMs: number;
|
|
16
|
+
}
|
|
17
|
+
export type SystemDependencyCommandRunner = (command: string, args: readonly string[], options: SystemDependencyCommandOptions) => Promise<SystemDependencyCommandResult>;
|
|
18
|
+
export interface SystemDependencyOptions {
|
|
19
|
+
platform?: string;
|
|
20
|
+
getuid?: () => number | undefined;
|
|
21
|
+
findSystemExecutable?: (name: string) => Promise<string | undefined>;
|
|
22
|
+
runCommand?: SystemDependencyCommandRunner;
|
|
23
|
+
onProgress?: (message: string) => void;
|
|
24
|
+
}
|
|
25
|
+
export declare function inspectSystemDependencies(options?: Pick<SystemDependencyOptions, "runCommand">): Promise<SystemDependencySnapshot>;
|
|
26
|
+
export declare function ensureSystemDependencies(options?: SystemDependencyOptions): Promise<SystemDependencySnapshot>;
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { constants } from "node:fs";
|
|
3
|
+
import { access } from "node:fs/promises";
|
|
4
|
+
const PROBE_TIMEOUT_MS = 10_000;
|
|
5
|
+
const INSTALL_TIMEOUT_MS = 5 * 60_000;
|
|
6
|
+
const MAX_OUTPUT_BYTES = 1024 * 1024;
|
|
7
|
+
export async function inspectSystemDependencies(options = {}) {
|
|
8
|
+
const runCommand = options.runCommand ?? runSystemDependencyCommand;
|
|
9
|
+
const probe = await probeTmux(runCommand);
|
|
10
|
+
return {
|
|
11
|
+
tmux: probe.installed
|
|
12
|
+
? { installed: true }
|
|
13
|
+
: { installed: false, detail: probe.detail },
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export async function ensureSystemDependencies(options = {}) {
|
|
17
|
+
const runCommand = options.runCommand ?? runSystemDependencyCommand;
|
|
18
|
+
const before = await probeTmux(runCommand);
|
|
19
|
+
if (before.installed)
|
|
20
|
+
return { tmux: { installed: true } };
|
|
21
|
+
if (before.binaryPresent) {
|
|
22
|
+
throw new Error(before.detail);
|
|
23
|
+
}
|
|
24
|
+
const platform = options.platform ?? process.platform;
|
|
25
|
+
const findSystemExecutable = options.findSystemExecutable ?? findSystemCommand;
|
|
26
|
+
const manager = await resolvePackageManager(platform, findSystemExecutable);
|
|
27
|
+
if (!manager) {
|
|
28
|
+
throw new Error(platform === "darwin"
|
|
29
|
+
? "tmux is required for live Sessions, but Homebrew is unavailable; install tmux and retry"
|
|
30
|
+
: "tmux is required for live Sessions, but no supported package manager (apt-get, dnf, or yum) is available");
|
|
31
|
+
}
|
|
32
|
+
const installArgs = manager.family === "apt"
|
|
33
|
+
? ["install", "-y", "--no-install-recommends", "tmux"]
|
|
34
|
+
: manager.family === "brew"
|
|
35
|
+
? ["install", "tmux"]
|
|
36
|
+
: ["install", "-y", "tmux"];
|
|
37
|
+
let command = manager.path;
|
|
38
|
+
let args = installArgs;
|
|
39
|
+
if (manager.family !== "brew") {
|
|
40
|
+
const getuid = options.getuid ?? (() => process.getuid?.());
|
|
41
|
+
if (getuid() !== 0) {
|
|
42
|
+
const sudo = await findSystemExecutable("sudo");
|
|
43
|
+
const sudoReady = sudo
|
|
44
|
+
? await runCommand(sudo, ["-n", "true"], { timeoutMs: PROBE_TIMEOUT_MS })
|
|
45
|
+
: undefined;
|
|
46
|
+
if (!sudo || sudoReady?.exitCode !== 0) {
|
|
47
|
+
throw new Error(`tmux is required for live Sessions; install it as an administrator and retry: ` +
|
|
48
|
+
`${manager.commandForHumans} install -y tmux`);
|
|
49
|
+
}
|
|
50
|
+
command = sudo;
|
|
51
|
+
args = ["-n", manager.path, ...installArgs];
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
options.onProgress?.("installing required system dependency: tmux");
|
|
55
|
+
const installed = await runCommand(command, args, { timeoutMs: INSTALL_TIMEOUT_MS });
|
|
56
|
+
if (installed.exitCode !== 0) {
|
|
57
|
+
throw new Error(`failed to install required system dependency tmux: ${commandFailure(installed)}`);
|
|
58
|
+
}
|
|
59
|
+
const after = await inspectSystemDependencies({ runCommand });
|
|
60
|
+
if (!after.tmux.installed) {
|
|
61
|
+
throw new Error(`tmux installation completed but tmux is still unavailable: ${after.tmux.detail}`);
|
|
62
|
+
}
|
|
63
|
+
options.onProgress?.("verified required system dependency: tmux");
|
|
64
|
+
return after;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* A version probe only proves the binary can start. Live Sessions need tmux to
|
|
68
|
+
* create a server and socket, so exercise that path with a private probe server
|
|
69
|
+
* that cannot interfere with a user's existing tmux sessions.
|
|
70
|
+
*/
|
|
71
|
+
async function probeTmux(runCommand) {
|
|
72
|
+
const version = await runCommand("tmux", ["-V"], { timeoutMs: PROBE_TIMEOUT_MS });
|
|
73
|
+
if (version.exitCode !== 0) {
|
|
74
|
+
return {
|
|
75
|
+
installed: false,
|
|
76
|
+
binaryPresent: version.errorCode !== "ENOENT",
|
|
77
|
+
detail: `tmux -V failed: ${commandFailure(version)}`,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
const socketName = `rynx-setup-probe-${process.pid}-${Date.now()}`;
|
|
81
|
+
const functional = await runCommand("tmux", ["-L", socketName, "new-session", "-d", "-s", "probe", "true"], { timeoutMs: PROBE_TIMEOUT_MS });
|
|
82
|
+
await runCommand("tmux", ["-L", socketName, "kill-server"], {
|
|
83
|
+
timeoutMs: PROBE_TIMEOUT_MS,
|
|
84
|
+
});
|
|
85
|
+
if (functional.exitCode !== 0) {
|
|
86
|
+
return {
|
|
87
|
+
installed: false,
|
|
88
|
+
binaryPresent: true,
|
|
89
|
+
detail: `${version.stdout.trim() || "tmux"} is installed but cannot start a server: ` +
|
|
90
|
+
commandFailure(functional),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
return { installed: true, binaryPresent: true };
|
|
94
|
+
}
|
|
95
|
+
async function resolvePackageManager(platform, findExecutable) {
|
|
96
|
+
if (platform === "darwin") {
|
|
97
|
+
const brew = await findExecutable("brew");
|
|
98
|
+
return brew ? { family: "brew", path: brew, commandForHumans: "brew" } : undefined;
|
|
99
|
+
}
|
|
100
|
+
if (platform !== "linux")
|
|
101
|
+
return undefined;
|
|
102
|
+
const apt = await findExecutable("apt-get");
|
|
103
|
+
if (apt)
|
|
104
|
+
return { family: "apt", path: apt, commandForHumans: "apt-get" };
|
|
105
|
+
const dnf = await findExecutable("dnf");
|
|
106
|
+
if (dnf)
|
|
107
|
+
return { family: "rpm", path: dnf, commandForHumans: "dnf" };
|
|
108
|
+
const yum = await findExecutable("yum");
|
|
109
|
+
return yum ? { family: "rpm", path: yum, commandForHumans: "yum" } : undefined;
|
|
110
|
+
}
|
|
111
|
+
async function findSystemCommand(name) {
|
|
112
|
+
const directories = name === "brew"
|
|
113
|
+
? ["/opt/homebrew/bin", "/usr/local/bin"]
|
|
114
|
+
: ["/usr/bin", "/bin", "/usr/sbin", "/sbin"];
|
|
115
|
+
for (const directory of directories) {
|
|
116
|
+
const candidate = `${directory}/${name}`;
|
|
117
|
+
try {
|
|
118
|
+
await access(candidate, constants.X_OK);
|
|
119
|
+
return candidate;
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
// Try the next standard system directory.
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
function runSystemDependencyCommand(command, args, options) {
|
|
128
|
+
return new Promise((resolveResult) => {
|
|
129
|
+
execFile(command, [...args], {
|
|
130
|
+
encoding: "utf8",
|
|
131
|
+
env: { ...process.env, DEBIAN_FRONTEND: "noninteractive", LC_ALL: "C" },
|
|
132
|
+
maxBuffer: MAX_OUTPUT_BYTES,
|
|
133
|
+
timeout: options.timeoutMs,
|
|
134
|
+
}, (error, stdout, stderr) => {
|
|
135
|
+
resolveResult({
|
|
136
|
+
exitCode: error
|
|
137
|
+
? typeof error.code === "number" ? error.code : null
|
|
138
|
+
: 0,
|
|
139
|
+
stdout,
|
|
140
|
+
stderr,
|
|
141
|
+
...(error && typeof error.code === "string" ? { errorCode: error.code } : {}),
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
function commandFailure(result) {
|
|
147
|
+
const detail = result.stderr.trim() || result.stdout.trim() || result.errorCode;
|
|
148
|
+
return detail ? detail.slice(0, 2_000) : `exit code ${result.exitCode ?? "unknown"}`;
|
|
149
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rynx-ai/daemon",
|
|
3
|
-
"version": "0.1.11-beta.
|
|
3
|
+
"version": "0.1.11-beta.8",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/rynx-ai/rynx.git",
|
|
@@ -47,17 +47,17 @@
|
|
|
47
47
|
"pm2": "^6.0.0",
|
|
48
48
|
"tar": "^7.5.19",
|
|
49
49
|
"ws": "^8.21.0",
|
|
50
|
-
"@rynx-ai/core": "0.1.11-beta.
|
|
51
|
-
"@rynx-ai/emulator": "0.1.11-beta.
|
|
52
|
-
"@rynx-ai/plugin-runner": "0.1.11-beta.
|
|
53
|
-
"@rynx-ai/plugin-sdk": "0.1.11-beta.
|
|
54
|
-
"@rynx-ai/protocol": "0.1.11-beta.
|
|
55
|
-
"@rynx-ai/remote-runtime-client": "0.1.11-beta.
|
|
56
|
-
"@rynx-ai/server": "0.1.11-beta.
|
|
50
|
+
"@rynx-ai/core": "0.1.11-beta.8",
|
|
51
|
+
"@rynx-ai/emulator": "0.1.11-beta.8",
|
|
52
|
+
"@rynx-ai/plugin-runner": "0.1.11-beta.8",
|
|
53
|
+
"@rynx-ai/plugin-sdk": "0.1.11-beta.8",
|
|
54
|
+
"@rynx-ai/protocol": "0.1.11-beta.8",
|
|
55
|
+
"@rynx-ai/remote-runtime-client": "0.1.11-beta.8",
|
|
56
|
+
"@rynx-ai/server": "0.1.11-beta.8"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@types/ws": "^8.18.1",
|
|
60
|
-
"@rynx-ai/plugin-channel-lark": "0.1.11-beta.
|
|
60
|
+
"@rynx-ai/plugin-channel-lark": "0.1.11-beta.8"
|
|
61
61
|
},
|
|
62
62
|
"scripts": {
|
|
63
63
|
"build": "rm -rf dist bundled-plugins && tsc -p tsconfig.json && chmod +x dist/index-daemon.js && node ../../scripts/stage-bundled-plugins.mjs",
|