@rynx-ai/daemon 0.1.0 → 0.1.10-beta.2
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/app-browser-host-supervisor.d.ts +97 -0
- package/dist/app-browser-host-supervisor.js +529 -0
- package/dist/browser-artifact-management.d.ts +20 -0
- package/dist/browser-artifact-management.js +61 -0
- package/dist/browser-cli-args.d.ts +20 -0
- package/dist/browser-cli-args.js +100 -0
- package/dist/browser-runner-session-context.d.ts +24 -0
- package/dist/browser-runner-session-context.js +113 -0
- package/dist/cdp-keyboard-input.d.ts +6 -0
- package/dist/cdp-keyboard-input.js +209 -0
- package/dist/channel-store.d.ts +0 -6
- package/dist/channel-store.js +2 -18
- package/dist/chrome-for-testing-release-resolver.d.ts +34 -0
- package/dist/chrome-for-testing-release-resolver.js +214 -0
- package/dist/chrome-for-testing-store.d.ts +85 -0
- package/dist/chrome-for-testing-store.js +836 -0
- package/dist/chrome-inspection-gateway.d.ts +58 -0
- package/dist/chrome-inspection-gateway.js +806 -0
- package/dist/chrome-inspection-manager.d.ts +94 -0
- package/dist/chrome-inspection-manager.js +573 -0
- package/dist/cli.js +478 -30
- package/dist/control-client.d.ts +122 -0
- package/dist/control-client.js +855 -0
- package/dist/control-deps.js +37 -6
- package/dist/control-endpoint.d.ts +14 -0
- package/dist/control-endpoint.js +124 -0
- package/dist/control-link-store.d.ts +16 -0
- package/dist/control-link-store.js +53 -0
- package/dist/daemon-build-status.d.ts +8 -0
- package/dist/daemon-build-status.js +18 -0
- package/dist/daemon-owner.d.ts +14 -0
- package/dist/daemon-owner.js +104 -0
- package/dist/daemon-server.d.ts +29 -2
- package/dist/daemon-server.js +1113 -26
- package/dist/db.js +196 -10
- package/dist/desktop-browser-host-client.d.ts +35 -0
- package/dist/desktop-browser-host-client.js +415 -0
- package/dist/direct-runtime-authenticator.d.ts +13 -0
- package/dist/direct-runtime-authenticator.js +132 -0
- package/dist/direct-runtime-config.d.ts +20 -0
- package/dist/direct-runtime-config.js +101 -0
- package/dist/embedded-browser-profile-cleanup.d.ts +58 -0
- package/dist/embedded-browser-profile-cleanup.js +338 -0
- package/dist/headless-browser-host.d.ts +14 -0
- package/dist/headless-browser-host.js +2173 -0
- package/dist/index-daemon.js +55 -5
- package/dist/installation-id.d.ts +33 -0
- package/dist/installation-id.js +692 -0
- package/dist/maintenance-management.d.ts +11 -0
- package/dist/maintenance-management.js +13 -0
- package/dist/migrations/cleanup-legacy-sessions.d.ts +0 -3
- package/dist/migrations/cleanup-legacy-sessions.js +10 -28
- package/dist/plugin-cli.d.ts +30 -0
- package/dist/plugin-cli.js +270 -0
- package/dist/plugin-host-rpc.d.ts +85 -0
- package/dist/plugin-host-rpc.js +878 -0
- package/dist/plugin-install-restart.d.ts +13 -0
- package/dist/plugin-install-restart.js +24 -0
- package/dist/plugin-installer.d.ts +71 -15
- package/dist/plugin-installer.js +521 -155
- package/dist/plugin-management-service.d.ts +58 -0
- package/dist/plugin-management-service.js +240 -0
- package/dist/plugin-package.d.ts +61 -0
- package/dist/plugin-package.js +732 -0
- package/dist/plugin-runtime-control.d.ts +2 -0
- package/dist/plugin-runtime-control.js +37 -0
- package/dist/plugin-store.d.ts +37 -8
- package/dist/plugin-store.js +80 -15
- package/dist/plugin-supervisor.d.ts +160 -0
- package/dist/plugin-supervisor.js +1143 -0
- package/dist/pm2.d.ts +3 -1
- package/dist/pm2.js +92 -18
- package/dist/provider-cli-service.d.ts +46 -0
- package/dist/provider-cli-service.js +510 -0
- package/dist/registry.d.ts +6 -19
- package/dist/registry.js +22 -87
- package/dist/remote-runtime-access-store.d.ts +62 -0
- package/dist/remote-runtime-access-store.js +393 -0
- package/dist/remote-runtime-admin.d.ts +35 -0
- package/dist/remote-runtime-admin.js +110 -0
- package/dist/remote-runtime-connection-manager.d.ts +103 -0
- package/dist/remote-runtime-connection-manager.js +1575 -0
- package/dist/remote-runtime-credential-store.d.ts +45 -0
- package/dist/remote-runtime-credential-store.js +639 -0
- package/dist/remote-runtime-target-control.d.ts +51 -0
- package/dist/remote-runtime-target-control.js +488 -0
- package/dist/remote-runtime-target-store.d.ts +56 -0
- package/dist/remote-runtime-target-store.js +326 -0
- package/dist/runtime-share-addresses.d.ts +21 -0
- package/dist/runtime-share-addresses.js +50 -0
- package/dist/session-browser-capability-store.d.ts +13 -0
- package/dist/session-browser-capability-store.js +58 -0
- package/dist/session-emulator-binding-store.d.ts +10 -0
- package/dist/session-emulator-binding-store.js +61 -0
- package/dist/session-launch-operations.d.ts +41 -0
- package/dist/session-launch-operations.js +124 -0
- package/dist/session-log-store.js +29 -0
- package/dist/session-meta-store.d.ts +3 -2
- package/dist/session-meta-store.js +59 -7
- package/dist/session-pending-message-store.d.ts +2 -0
- package/dist/session-pending-message-store.js +41 -0
- package/dist/session-resource-store.d.ts +32 -0
- package/dist/session-resource-store.js +700 -0
- package/dist/setup.d.ts +16 -0
- package/dist/setup.js +144 -5
- package/dist/skills-catalog.js +8 -4
- package/dist/update.d.ts +11 -2
- package/dist/update.js +0 -27
- package/package.json +23 -10
package/dist/setup.d.ts
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
|
+
type ControlListenMode = "loopback" | "host";
|
|
2
|
+
type ManagedBrowserSetupPlan = {
|
|
3
|
+
kind: "ready";
|
|
4
|
+
} | {
|
|
5
|
+
kind: "unsupported";
|
|
6
|
+
} | {
|
|
7
|
+
kind: "offer";
|
|
8
|
+
installByDefault: boolean;
|
|
9
|
+
};
|
|
10
|
+
export declare function controlListenModeFromHost(host: unknown): ControlListenMode;
|
|
11
|
+
export declare function controlHostForListenMode(mode: ControlListenMode): "127.0.0.1" | "0.0.0.0";
|
|
12
|
+
export declare function managedBrowserSetupPlan(listenMode: ControlListenMode, browser: {
|
|
13
|
+
supported: boolean;
|
|
14
|
+
installed: boolean;
|
|
15
|
+
}): ManagedBrowserSetupPlan;
|
|
1
16
|
/** Walk the user through config.json step by step. Returns a process exit code. */
|
|
2
17
|
export declare function runSetup(): Promise<number>;
|
|
3
18
|
/** Read-only diagnostics. Returns a process exit code (0 ok, 1 on any failure). */
|
|
4
19
|
export declare function runDoctor(): Promise<number>;
|
|
20
|
+
export {};
|
package/dist/setup.js
CHANGED
|
@@ -15,20 +15,45 @@ import { join } from "node:path";
|
|
|
15
15
|
import * as p from "@clack/prompts";
|
|
16
16
|
import { AGENT_RUNTIME_IDS, getRuntimeProfile, listAgentSpecs, loadConfig, resolveRuntimeHome, rynxAgentsDir, rynxConfigFile, rynxHome, } from "@rynx-ai/core";
|
|
17
17
|
import { listChannels } from "./channel-store.js";
|
|
18
|
+
import { resolveChromeForTestingRelease } from "./chrome-for-testing-release-resolver.js";
|
|
19
|
+
import { createChromeForTestingArtifactStore, isChromeForTestingHostSupported, } from "./chrome-for-testing-store.js";
|
|
18
20
|
import { dbPath } from "./db.js";
|
|
19
21
|
import { listInstances } from "./instance-store.js";
|
|
20
|
-
import { listPlugins } from "./plugin-store.js";
|
|
22
|
+
import { isRunnablePluginRecord, listPlugins } from "./plugin-store.js";
|
|
21
23
|
import { formatControlUrl } from "./pm2.js";
|
|
22
24
|
const MIN_NODE_MAJOR = 20;
|
|
25
|
+
export function controlListenModeFromHost(host) {
|
|
26
|
+
const normalized = typeof host === "string" ? host.trim().replace(/^\[|\]$/g, "") : "";
|
|
27
|
+
return normalized === "" ||
|
|
28
|
+
normalized === "127.0.0.1" ||
|
|
29
|
+
normalized === "::1" ||
|
|
30
|
+
normalized.toLowerCase() === "localhost"
|
|
31
|
+
? "loopback"
|
|
32
|
+
: "host";
|
|
33
|
+
}
|
|
34
|
+
export function controlHostForListenMode(mode) {
|
|
35
|
+
return mode === "host" ? "0.0.0.0" : "127.0.0.1";
|
|
36
|
+
}
|
|
37
|
+
export function managedBrowserSetupPlan(listenMode, browser) {
|
|
38
|
+
if (!browser.supported)
|
|
39
|
+
return { kind: "unsupported" };
|
|
40
|
+
if (browser.installed)
|
|
41
|
+
return { kind: "ready" };
|
|
42
|
+
return { kind: "offer", installByDefault: listenMode === "host" };
|
|
43
|
+
}
|
|
23
44
|
// ── rynx setup — interactive wizard ─────────────────────────────────────────
|
|
24
45
|
/** Walk the user through config.json step by step. Returns a process exit code. */
|
|
25
46
|
export async function runSetup() {
|
|
26
47
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
27
48
|
// Non-interactive (CI / piped): never block on a prompt — just ensure defaults.
|
|
28
49
|
if (!existsSync(rynxConfigFile()))
|
|
29
|
-
writeConfig({ HOST: "
|
|
50
|
+
writeConfig({ HOST: "127.0.0.1", PORT: 3000, LOG_LEVEL: "info" });
|
|
51
|
+
const browser = inspectManagedBrowser();
|
|
30
52
|
console.log(`非交互环境:已确保 ${rynxConfigFile()} 存在(默认值)。` +
|
|
31
|
-
"在终端(TTY)下重跑 `rynx setup` 可分步配置,或直接编辑该文件。"
|
|
53
|
+
"在终端(TTY)下重跑 `rynx setup` 可分步配置,或直接编辑该文件。" +
|
|
54
|
+
(browser.supported && !browser.installed
|
|
55
|
+
? "\nSession Browser 尚未安装;需要时运行 `rynx browser install`。"
|
|
56
|
+
: ""));
|
|
32
57
|
return 0;
|
|
33
58
|
}
|
|
34
59
|
p.intro("rynx setup · 配置 ~/.rynx");
|
|
@@ -81,15 +106,89 @@ export async function runSetup() {
|
|
|
81
106
|
if (p.isCancel(port))
|
|
82
107
|
return bail();
|
|
83
108
|
cfg.PORT = Number(port);
|
|
84
|
-
|
|
109
|
+
const listenMode = await p.select({
|
|
110
|
+
message: "控制台访问范围 HOST",
|
|
111
|
+
initialValue: controlListenModeFromHost(cfg.HOST),
|
|
112
|
+
options: [
|
|
113
|
+
{
|
|
114
|
+
value: "loopback",
|
|
115
|
+
label: "仅本机(Loopback,推荐)",
|
|
116
|
+
hint: "绑定 127.0.0.1",
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
value: "host",
|
|
120
|
+
label: "网络访问(Host)",
|
|
121
|
+
hint: "绑定 0.0.0.0,可信网络可通过机器 IP 访问",
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
});
|
|
125
|
+
if (p.isCancel(listenMode))
|
|
126
|
+
return bail();
|
|
127
|
+
cfg.HOST = controlHostForListenMode(listenMode);
|
|
85
128
|
cfg.LOG_LEVEL = cfg.LOG_LEVEL ?? "info";
|
|
129
|
+
const browserBeforeSetup = inspectManagedBrowser();
|
|
130
|
+
const browserPlan = managedBrowserSetupPlan(listenMode, {
|
|
131
|
+
supported: browserBeforeSetup.supported,
|
|
132
|
+
installed: Boolean(browserBeforeSetup.installed),
|
|
133
|
+
});
|
|
134
|
+
let installBrowser = false;
|
|
135
|
+
if (browserPlan.kind === "ready") {
|
|
136
|
+
p.log.success(`Session Browser 已就绪 · Chrome for Testing ${browserBeforeSetup.installed.version}`);
|
|
137
|
+
}
|
|
138
|
+
else if (browserPlan.kind === "unsupported") {
|
|
139
|
+
p.log.info(`当前平台 ${process.platform}-${process.arch} 不支持 managed Chrome for Testing;跳过 Browser 安装。`);
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
p.note([
|
|
143
|
+
"Session Browser 让 agent 在当前 Runtime 上打开和操作网页。",
|
|
144
|
+
listenMode === "host"
|
|
145
|
+
? "网络访问模式下,外部浏览器不能提供 Desktop Browser Host,因此推荐安装无头 Browser。"
|
|
146
|
+
: "桌面 App 可使用内置 Browser;独立 daemon 或远端 Runtime 仍需要无头 Browser。",
|
|
147
|
+
"安装会从 Chrome for Testing 官方源下载浏览器,不会改动系统浏览器。",
|
|
148
|
+
...(process.platform === "linux"
|
|
149
|
+
? ["Linux 的动态库和字体依赖仍需由系统或主机镜像提供。"]
|
|
150
|
+
: []),
|
|
151
|
+
].join("\n"), "Session Browser(可选)");
|
|
152
|
+
const choice = await p.confirm({
|
|
153
|
+
message: "现在安装 managed Chrome for Testing?",
|
|
154
|
+
initialValue: browserPlan.installByDefault,
|
|
155
|
+
});
|
|
156
|
+
if (p.isCancel(choice))
|
|
157
|
+
return bail();
|
|
158
|
+
installBrowser = choice;
|
|
159
|
+
}
|
|
86
160
|
writeConfig(cfg);
|
|
87
161
|
p.log.success(`已写入 ${rynxConfigFile()}(chmod 600)`);
|
|
88
162
|
p.log.message(`HOST=${cfg.HOST} PORT=${cfg.PORT} AGENT_RUNTIME=${cfg.AGENT_RUNTIME ?? "(默认)"}`);
|
|
89
|
-
|
|
163
|
+
let browserReady = browserPlan.kind === "ready";
|
|
164
|
+
if (installBrowser) {
|
|
165
|
+
const spinner = p.spinner();
|
|
166
|
+
spinner.start("准备安装 Stable Chrome for Testing");
|
|
167
|
+
try {
|
|
168
|
+
const release = await resolveChromeForTestingRelease({
|
|
169
|
+
kind: "channel",
|
|
170
|
+
channel: "Stable",
|
|
171
|
+
});
|
|
172
|
+
const installedBrowser = await createChromeForTestingArtifactStore().installResolved(release, { onProgress: (message) => spinner.message(message) });
|
|
173
|
+
browserReady = true;
|
|
174
|
+
spinner.stop(`Session Browser 已就绪 · Chrome for Testing ${installedBrowser.version}`);
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
spinner.error("Session Browser 安装失败");
|
|
178
|
+
p.log.warn(`${error instanceof Error ? error.message : String(error)}\n` +
|
|
179
|
+
"配置已保存;修复网络或系统依赖后运行 `rynx browser install` 重试。");
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
else if (browserPlan.kind === "offer") {
|
|
183
|
+
p.log.info("已跳过 Browser 安装;需要时运行 `rynx browser install`。");
|
|
184
|
+
}
|
|
185
|
+
const url = formatControlUrl(String(cfg.HOST ?? "127.0.0.1"), Number(cfg.PORT ?? 3000));
|
|
90
186
|
p.note([
|
|
91
187
|
`启动常驻服务 rynx start`,
|
|
92
188
|
`打开控制台 ${url}`,
|
|
189
|
+
browserReady
|
|
190
|
+
? "Session Browser 已就绪"
|
|
191
|
+
: "启用 Browser rynx browser install",
|
|
93
192
|
`新建 agent rynx agent add <id>`,
|
|
94
193
|
`随时体检 rynx doctor`,
|
|
95
194
|
].join("\n"), "下一步");
|
|
@@ -146,6 +245,11 @@ export async function runDoctor() {
|
|
|
146
245
|
else {
|
|
147
246
|
const plugins = listPlugins();
|
|
148
247
|
p.log.info(`插件:${plugins.length} 个${plugins.length ? `(${plugins.map((pl) => pl.name).join(", ")})` : ""}`);
|
|
248
|
+
const legacyPlugins = plugins.filter((plugin) => !isRunnablePluginRecord(plugin));
|
|
249
|
+
if (legacyPlugins.length > 0) {
|
|
250
|
+
p.log.warn(`需重新安装的旧插件:${legacyPlugins.map((plugin) => plugin.name).join(", ")}`);
|
|
251
|
+
warn++;
|
|
252
|
+
}
|
|
149
253
|
const channels = listChannels();
|
|
150
254
|
const configured = channels.filter((c) => c.options && Object.keys(c.options).length > 0).length;
|
|
151
255
|
p.log.info(`channel:${channels.length} 个(${configured} 已配置凭据) · instance:${listInstances().length} 个`);
|
|
@@ -153,6 +257,24 @@ export async function runDoctor() {
|
|
|
153
257
|
(p.log.warn("还没有 channel —— 在 Web 控制台新建并授权"), warn++);
|
|
154
258
|
}
|
|
155
259
|
p.log.info(`agent:${(await listAgentSpecs()).length} 个(${rynxAgentsDir()})`);
|
|
260
|
+
const browser = inspectManagedBrowser();
|
|
261
|
+
if (!browser.supported) {
|
|
262
|
+
p.log.info(`Session Browser:当前平台 ${process.platform}-${process.arch} 不受支持`);
|
|
263
|
+
}
|
|
264
|
+
else if (browser.installed) {
|
|
265
|
+
p.log.success(`Session Browser:Chrome for Testing ${browser.installed.version} 已安装`);
|
|
266
|
+
if (process.platform === "linux") {
|
|
267
|
+
p.log.info("Linux Browser 动态库和字体依赖由系统或主机镜像提供");
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
else if (browser.error) {
|
|
271
|
+
p.log.warn(`Session Browser 安装无效:${browser.error} —— 运行 \`rynx browser install\` 修复`);
|
|
272
|
+
warn++;
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
p.log.warn("Session Browser 未安装 —— 运行 `rynx browser install`");
|
|
276
|
+
warn++;
|
|
277
|
+
}
|
|
156
278
|
if (fail > 0) {
|
|
157
279
|
p.outro(`体检发现 ${fail} 个失败项(警告 ${warn})—— 处理后重跑 rynx doctor`);
|
|
158
280
|
return 1;
|
|
@@ -160,6 +282,23 @@ export async function runDoctor() {
|
|
|
160
282
|
p.outro(warn > 0 ? `基本就绪,有 ${warn} 个警告` : "全部通过 ✓");
|
|
161
283
|
return 0;
|
|
162
284
|
}
|
|
285
|
+
function inspectManagedBrowser() {
|
|
286
|
+
if (!isChromeForTestingHostSupported())
|
|
287
|
+
return { supported: false };
|
|
288
|
+
try {
|
|
289
|
+
return {
|
|
290
|
+
supported: true,
|
|
291
|
+
installed: createChromeForTestingArtifactStore().readActive(),
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
catch (error) {
|
|
295
|
+
return {
|
|
296
|
+
supported: true,
|
|
297
|
+
installed: undefined,
|
|
298
|
+
error: error instanceof Error ? error.message : String(error),
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
}
|
|
163
302
|
function runtimeState(id) {
|
|
164
303
|
const profile = getRuntimeProfile(id);
|
|
165
304
|
const installed = onPath(profile.defaultBinary);
|
package/dist/skills-catalog.js
CHANGED
|
@@ -12,7 +12,7 @@ const SKILL_NAME_PATTERN = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
|
12
12
|
/** A single file's contents are capped to keep responses small. */
|
|
13
13
|
const MAX_SKILL_FILE_BYTES = 256 * 1024;
|
|
14
14
|
export function listCatalogSkills() {
|
|
15
|
-
return
|
|
15
|
+
return listMergedSkills();
|
|
16
16
|
}
|
|
17
17
|
/** Install a skill (or a repo's skills) into the catalog per a full install
|
|
18
18
|
* recipe; delegates to the core catalog layer (which also writes each skill's
|
|
@@ -20,7 +20,7 @@ export function listCatalogSkills() {
|
|
|
20
20
|
* the refreshed catalog. */
|
|
21
21
|
export async function installCatalogSkill(recipe) {
|
|
22
22
|
await installIntoCatalog(recipe, rynxSkillsDir());
|
|
23
|
-
return
|
|
23
|
+
return listMergedSkills();
|
|
24
24
|
}
|
|
25
25
|
/** Detail for one catalog skill: its metadata + the file tree under its dir. */
|
|
26
26
|
export async function getCatalogSkill(name) {
|
|
@@ -30,6 +30,7 @@ export async function getCatalogSkill(name) {
|
|
|
30
30
|
const meta = await readSkillMeta(dir);
|
|
31
31
|
if (!meta)
|
|
32
32
|
return null;
|
|
33
|
+
const ref = meta.ref;
|
|
33
34
|
const files = await walkSkillFiles(dir, dir);
|
|
34
35
|
let frontmatter;
|
|
35
36
|
try {
|
|
@@ -41,7 +42,7 @@ export async function getCatalogSkill(name) {
|
|
|
41
42
|
return {
|
|
42
43
|
name: meta.name,
|
|
43
44
|
description: meta.description,
|
|
44
|
-
...(
|
|
45
|
+
...(ref ? { ref } : {}),
|
|
45
46
|
frontmatter,
|
|
46
47
|
totalSize: files.reduce((sum, f) => sum + f.size, 0),
|
|
47
48
|
files,
|
|
@@ -63,7 +64,7 @@ async function walkSkillFiles(root, dir) {
|
|
|
63
64
|
export async function readCatalogSkillFile(name, relPath) {
|
|
64
65
|
if (!SKILL_NAME_PATTERN.test(name))
|
|
65
66
|
throw new Error(`invalid skill name: ${name}`);
|
|
66
|
-
const dir = path.resolve(rynxSkillsDir(), name);
|
|
67
|
+
const dir = path.resolve(path.join(rynxSkillsDir(), name));
|
|
67
68
|
const target = path.resolve(dir, relPath);
|
|
68
69
|
if (target !== dir && !target.startsWith(dir + path.sep)) {
|
|
69
70
|
throw new Error("path escapes the skill directory");
|
|
@@ -78,6 +79,9 @@ export async function readCatalogSkillFile(name, relPath) {
|
|
|
78
79
|
throw new Error("binary file — not viewable");
|
|
79
80
|
return { path: relPath, content: buf.toString("utf8") };
|
|
80
81
|
}
|
|
82
|
+
async function listMergedSkills() {
|
|
83
|
+
return (await scanSkillsDir(rynxSkillsDir())).sort((a, b) => a.name.localeCompare(b.name));
|
|
84
|
+
}
|
|
81
85
|
/** Remove a catalog skill by name. Returns false if it wasn't present. */
|
|
82
86
|
export async function removeCatalogSkill(name) {
|
|
83
87
|
if (!SKILL_NAME_PATTERN.test(name))
|
package/dist/update.d.ts
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
|
-
import { type UpdateCheck } from "@rynx-ai/core";
|
|
2
1
|
export interface UpdateOptions {
|
|
3
2
|
check?: boolean;
|
|
4
3
|
/** With `check`, emit a typed {@link UpdateCheck} as JSON instead of a human line. */
|
|
5
4
|
json?: boolean;
|
|
6
5
|
version?: string;
|
|
7
|
-
resultFile?: string;
|
|
8
6
|
}
|
|
7
|
+
export type UpdateCheck = {
|
|
8
|
+
status: "up_to_date";
|
|
9
|
+
current: string;
|
|
10
|
+
} | {
|
|
11
|
+
status: "behind";
|
|
12
|
+
current: string;
|
|
13
|
+
latest: string;
|
|
14
|
+
} | {
|
|
15
|
+
status: "error";
|
|
16
|
+
detail: string;
|
|
17
|
+
};
|
|
9
18
|
/** Is `latest` a newer release than `current`? Numeric major.minor.patch (prerelease ignored). */
|
|
10
19
|
export declare function isNewer(latest: string, current: string): boolean;
|
|
11
20
|
/** Typed `--check` result a channel consumes via `--check --json`. */
|
package/dist/update.js
CHANGED
|
@@ -7,12 +7,8 @@
|
|
|
7
7
|
* rynx update [version] upgrade (to a version, or latest) + restart
|
|
8
8
|
* rynx update --check report status only (human one-liner)
|
|
9
9
|
* rynx update --check --json report status only (typed UpdateCheck JSON)
|
|
10
|
-
* rynx update --result-file <path> after finishing, write the outcome JSON to
|
|
11
|
-
* <path> (channel-agnostic UpdateOutcome; a
|
|
12
|
-
* plugin reads it post-restart to notify a chat)
|
|
13
10
|
*/
|
|
14
11
|
import { spawnSync } from "node:child_process";
|
|
15
|
-
import { mkdirSync, writeFileSync } from "node:fs";
|
|
16
12
|
import { createRequire } from "node:module";
|
|
17
13
|
import { dirname, sep } from "node:path";
|
|
18
14
|
import { loadConfig } from "@rynx-ai/core";
|
|
@@ -98,19 +94,6 @@ async function verifyHealthy() {
|
|
|
98
94
|
}
|
|
99
95
|
return false;
|
|
100
96
|
}
|
|
101
|
-
/** Write the post-restart outcome to `--result-file` (best-effort; stamps `at`). */
|
|
102
|
-
function writeOutcome(file, outcome) {
|
|
103
|
-
if (!file)
|
|
104
|
-
return;
|
|
105
|
-
try {
|
|
106
|
-
mkdirSync(dirname(file), { recursive: true });
|
|
107
|
-
const full = { ...outcome, at: new Date().toISOString() };
|
|
108
|
-
writeFileSync(file, `${JSON.stringify(full, null, 2)}\n`);
|
|
109
|
-
}
|
|
110
|
-
catch {
|
|
111
|
-
/* best-effort */
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
97
|
/** Run `rynx update`. Returns a process exit code. */
|
|
115
98
|
export async function runUpdate(opts) {
|
|
116
99
|
const { name, version: current } = selfPackage();
|
|
@@ -122,13 +105,11 @@ export async function runUpdate(opts) {
|
|
|
122
105
|
// Never `npm install -g` over a working checkout / linked dev build.
|
|
123
106
|
if (isLocalDevInstall()) {
|
|
124
107
|
console.error(`update: ${name} is a local dev install — update your checkout (e.g. pnpm build), not npm`);
|
|
125
|
-
writeOutcome(opts.resultFile, { status: "fail", from: current, to: current, error: "local dev install" });
|
|
126
108
|
return 1;
|
|
127
109
|
}
|
|
128
110
|
const target = opts.version ?? latest;
|
|
129
111
|
if (!target) {
|
|
130
112
|
console.error(`update: could not resolve a target version for ${name} (registry unreachable?)`);
|
|
131
|
-
writeOutcome(opts.resultFile, { status: "fail", from: current, to: current, error: "could not resolve target version" });
|
|
132
113
|
return 1;
|
|
133
114
|
}
|
|
134
115
|
if (!opts.version && latest && !isNewer(latest, current)) {
|
|
@@ -138,12 +119,6 @@ export async function runUpdate(opts) {
|
|
|
138
119
|
console.log(`Updating ${name}: ${current} → ${target} …`);
|
|
139
120
|
if (!npmInstallGlobal(name, target)) {
|
|
140
121
|
console.error("update: npm install failed");
|
|
141
|
-
writeOutcome(opts.resultFile, { status: "fail", from: current, to: target, error: "npm install failed" });
|
|
142
|
-
// The install failed before any restart, so the channel that spawned us never
|
|
143
|
-
// reboots to drain the outcome. Bounce the daemon (still on the old, healthy
|
|
144
|
-
// version) so its boot-time drain delivers the failure to chat.
|
|
145
|
-
if (opts.resultFile)
|
|
146
|
-
startDaemon({ force: true });
|
|
147
122
|
return 1;
|
|
148
123
|
}
|
|
149
124
|
startDaemon({ force: true });
|
|
@@ -151,10 +126,8 @@ export async function runUpdate(opts) {
|
|
|
151
126
|
console.error(`update: ${name}@${target} did not come back up — rolling back to ${current}`);
|
|
152
127
|
npmInstallGlobal(name, current);
|
|
153
128
|
startDaemon({ force: true });
|
|
154
|
-
writeOutcome(opts.resultFile, { status: "fail", from: current, to: target, error: "did not come up; rolled back" });
|
|
155
129
|
return 1;
|
|
156
130
|
}
|
|
157
131
|
console.log(`Updated ${name} → ${target} and restarted.`);
|
|
158
|
-
writeOutcome(opts.resultFile, { status: "ok", from: current, to: target });
|
|
159
132
|
return 0;
|
|
160
133
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rynx-ai/daemon",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"
|
|
3
|
+
"version": "0.1.10-beta.2",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git+https://github.com/rynx-ai/rynx.git",
|
|
7
|
+
"directory": "packages/daemon"
|
|
8
|
+
},
|
|
9
|
+
"description": "Rynx daemon CLI: supervises the local agent control plane and isolated optional plugin runtimes.",
|
|
5
10
|
"type": "module",
|
|
6
11
|
"publishConfig": {
|
|
7
12
|
"registry": "https://registry.npmjs.org/",
|
|
@@ -15,20 +20,28 @@
|
|
|
15
20
|
},
|
|
16
21
|
"main": "./dist/index-daemon.js",
|
|
17
22
|
"exports": {
|
|
18
|
-
"./
|
|
19
|
-
"types": "./dist/
|
|
20
|
-
"default": "./dist/
|
|
23
|
+
"./client": {
|
|
24
|
+
"types": "./dist/control-client.d.ts",
|
|
25
|
+
"default": "./dist/control-client.js"
|
|
21
26
|
}
|
|
22
27
|
},
|
|
23
28
|
"dependencies": {
|
|
24
29
|
"@clack/prompts": "^1.6.0",
|
|
25
30
|
"better-sqlite3": "^12.11.1",
|
|
31
|
+
"extract-zip": "2.0.1",
|
|
26
32
|
"pm2": "^6.0.0",
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"@rynx-ai/
|
|
30
|
-
"@rynx-ai/
|
|
31
|
-
"@rynx-ai/
|
|
33
|
+
"tar": "^7.5.19",
|
|
34
|
+
"ws": "^8.21.0",
|
|
35
|
+
"@rynx-ai/core": "0.1.10-beta.2",
|
|
36
|
+
"@rynx-ai/emulator": "0.1.10-beta.2",
|
|
37
|
+
"@rynx-ai/plugin-runner": "0.1.10-beta.2",
|
|
38
|
+
"@rynx-ai/plugin-sdk": "0.1.10-beta.2",
|
|
39
|
+
"@rynx-ai/protocol": "0.1.10-beta.2",
|
|
40
|
+
"@rynx-ai/remote-runtime-client": "0.1.10-beta.2",
|
|
41
|
+
"@rynx-ai/server": "0.1.10-beta.2"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/ws": "^8.18.1"
|
|
32
45
|
},
|
|
33
46
|
"scripts": {
|
|
34
47
|
"build": "rm -rf dist && tsc -p tsconfig.json && chmod +x dist/cli.js dist/index-daemon.js",
|