@rynx-ai/cli 0.1.11-beta.12 → 0.1.11-beta.14
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/commands/browser.js +14 -6
- package/dist/commands/setup.js +48 -10
- package/dist/commands/skills.js +2 -2
- package/dist/progress-display.d.ts +7 -0
- package/dist/progress-display.js +78 -0
- package/dist/usage.d.ts +1 -1
- package/dist/usage.js +1 -1
- package/package.json +6 -6
package/dist/commands/browser.js
CHANGED
|
@@ -4,6 +4,7 @@ import { connectBrowserAutomation, } from "@rynx-ai/browser-cdp";
|
|
|
4
4
|
import WebSocket from "ws";
|
|
5
5
|
import { parseBrowserCliArgs, resolveBrowserCliTarget, } from "../browser-cli-args.js";
|
|
6
6
|
import { callManagedRuntimeBrowser, callResidentRuntime, getResidentRuntimeLocalBrowserAutomationAccess, getResidentRuntimeLocalBrowserEndpoint, readOptionalManagedRuntimeBrowserCredential, } from "../control-client.js";
|
|
7
|
+
import { createProgressDisplay } from "../progress-display.js";
|
|
7
8
|
import { fail } from "./errors.js";
|
|
8
9
|
export async function runBrowserCommand(args) {
|
|
9
10
|
let parsed;
|
|
@@ -20,9 +21,18 @@ export async function runBrowserCommand(args) {
|
|
|
20
21
|
const channel = browserReleaseChannel(parsed.channel);
|
|
21
22
|
const { createBrowserArtifactManagementService } = await import("@rynx-ai/daemon/browser-artifacts");
|
|
22
23
|
const artifacts = createBrowserArtifactManagementService();
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
const progress = parsed.json ? undefined : createProgressDisplay();
|
|
25
|
+
progress?.start(parsed.subcommand === "install" ? "正在安装 Rynx Browser" : "正在更新 Rynx Browser");
|
|
26
|
+
let result;
|
|
27
|
+
try {
|
|
28
|
+
result = parsed.subcommand === "install"
|
|
29
|
+
? await artifacts.install(parsed.version ? { version: parsed.version } : { channel }, progress ? { onProgress: (message) => progress.update(message) } : {})
|
|
30
|
+
: await artifacts.update({ channel }, progress ? { onProgress: (message) => progress.update(message) } : {});
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
progress?.clear();
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
26
36
|
if (parsed.json) {
|
|
27
37
|
console.log(JSON.stringify({
|
|
28
38
|
resolved: result.resolved,
|
|
@@ -30,9 +40,7 @@ export async function runBrowserCommand(args) {
|
|
|
30
40
|
}, null, 2));
|
|
31
41
|
}
|
|
32
42
|
else {
|
|
33
|
-
|
|
34
|
-
console.log(message);
|
|
35
|
-
console.log(`Active Browser engine: Chrome for Testing ${result.installed.version}.`);
|
|
43
|
+
progress.succeed(`Rynx Browser 已就绪:Chrome for Testing ${result.installed.version}`);
|
|
36
44
|
}
|
|
37
45
|
return 0;
|
|
38
46
|
}
|
package/dist/commands/setup.js
CHANGED
|
@@ -4,9 +4,11 @@ import path from "node:path";
|
|
|
4
4
|
import * as prompts from "@clack/prompts";
|
|
5
5
|
import { AGENT_RUNTIME_IDS, getRuntimeProfile, loadConfig, rynxConfigFile, } from "@rynx-ai/core";
|
|
6
6
|
import { ensureSystemDependencies, inspectDaemonDiagnostics, inspectSystemDependencies, prepareBundledPlugins, } from "@rynx-ai/daemon/setup-service";
|
|
7
|
+
import { createProgressDisplay } from "../progress-display.js";
|
|
7
8
|
import { fail } from "./errors.js";
|
|
8
9
|
export async function runSetupCommand(args) {
|
|
9
10
|
const options = parseSetupOptions(args);
|
|
11
|
+
const progress = options.json ? undefined : createProgressDisplay();
|
|
10
12
|
const interactive = !options.nonInteractive &&
|
|
11
13
|
!options.hasConfigurationArguments &&
|
|
12
14
|
Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
@@ -53,36 +55,46 @@ export async function runSetupCommand(args) {
|
|
|
53
55
|
},
|
|
54
56
|
};
|
|
55
57
|
let failed = false;
|
|
58
|
+
progress?.start("正在准备 Rynx 内置插件");
|
|
56
59
|
try {
|
|
57
60
|
const plugins = await prepareBundledPlugins();
|
|
58
61
|
result.plugins = {
|
|
59
62
|
status: plugins.status,
|
|
60
63
|
changed: [...plugins.installed, ...plugins.updated],
|
|
61
64
|
};
|
|
65
|
+
progress?.succeed("Rynx 内置插件已就绪");
|
|
62
66
|
}
|
|
63
67
|
catch (error) {
|
|
64
68
|
failed = true;
|
|
69
|
+
progress?.clear();
|
|
70
|
+
const detail = errorMessage(error);
|
|
65
71
|
result.plugins = {
|
|
66
72
|
status: "error",
|
|
67
|
-
detail
|
|
73
|
+
detail,
|
|
68
74
|
};
|
|
75
|
+
console.error(`Rynx 内置插件准备失败:${detail}`);
|
|
69
76
|
}
|
|
77
|
+
progress?.start("正在检查 tmux");
|
|
70
78
|
try {
|
|
71
79
|
result.systemDependencies = await ensureSystemDependencies({
|
|
72
|
-
onProgress: (message) =>
|
|
80
|
+
...(progress ? { onProgress: (message) => progress.update(message) } : {}),
|
|
73
81
|
});
|
|
82
|
+
progress?.succeed("tmux 已就绪");
|
|
74
83
|
}
|
|
75
84
|
catch (error) {
|
|
76
85
|
failed = true;
|
|
86
|
+
progress?.clear();
|
|
77
87
|
const detail = errorMessage(error);
|
|
78
88
|
result.systemDependencies = {
|
|
79
89
|
tmux: { installed: false, detail },
|
|
80
90
|
};
|
|
81
|
-
console.error(`tmux
|
|
91
|
+
console.error(`tmux 准备失败:${detail}`);
|
|
82
92
|
}
|
|
93
|
+
progress?.start("正在检查 Rynx Browser");
|
|
83
94
|
const diagnostics = await inspectDaemonDiagnostics();
|
|
84
95
|
if (!diagnostics.browser.supported) {
|
|
85
96
|
result.browser = { action: options.browser, status: "unsupported" };
|
|
97
|
+
progress?.succeed("当前平台不支持 Rynx Browser");
|
|
86
98
|
}
|
|
87
99
|
else if (diagnostics.browser.installedVersion) {
|
|
88
100
|
result.browser = {
|
|
@@ -90,29 +102,39 @@ export async function runSetupCommand(args) {
|
|
|
90
102
|
status: "ready",
|
|
91
103
|
version: diagnostics.browser.installedVersion,
|
|
92
104
|
};
|
|
105
|
+
progress?.succeed(`Rynx Browser 已就绪:${diagnostics.browser.installedVersion}`);
|
|
93
106
|
}
|
|
94
107
|
else if (options.browser !== "skip") {
|
|
108
|
+
progress?.update("正在安装 Rynx Browser");
|
|
95
109
|
try {
|
|
96
110
|
const { createBrowserArtifactManagementService } = await import("@rynx-ai/daemon/browser-artifacts");
|
|
97
|
-
const installed = await createBrowserArtifactManagementService().install({ channel: "stable" },
|
|
98
|
-
? {}
|
|
99
|
-
: { onProgress: (message) => console.error(message) });
|
|
111
|
+
const installed = await createBrowserArtifactManagementService().install({ channel: "stable" }, progress ? { onProgress: (message) => progress.update(message) } : {});
|
|
100
112
|
result.browser = {
|
|
101
113
|
action: options.browser,
|
|
102
114
|
status: "ready",
|
|
103
115
|
version: installed.installed.version,
|
|
104
116
|
};
|
|
117
|
+
progress?.succeed(`Rynx Browser 已就绪:${installed.installed.version}`);
|
|
105
118
|
}
|
|
106
119
|
catch (error) {
|
|
107
120
|
failed = true;
|
|
121
|
+
progress?.clear();
|
|
122
|
+
const detail = errorMessage(error);
|
|
108
123
|
result.browser = {
|
|
109
124
|
action: options.browser,
|
|
110
125
|
status: "error",
|
|
111
|
-
detail
|
|
126
|
+
detail,
|
|
112
127
|
};
|
|
128
|
+
console.error(`Rynx Browser 安装失败:${detail}`);
|
|
113
129
|
}
|
|
114
130
|
}
|
|
115
|
-
|
|
131
|
+
else {
|
|
132
|
+
progress?.succeed("已跳过 Rynx Browser 安装");
|
|
133
|
+
}
|
|
134
|
+
if (options.resultFile) {
|
|
135
|
+
writeJsonAtomically(options.resultFile, result);
|
|
136
|
+
}
|
|
137
|
+
else if (options.json) {
|
|
116
138
|
console.log(JSON.stringify(result, null, 2));
|
|
117
139
|
}
|
|
118
140
|
else if (interactive) {
|
|
@@ -211,6 +233,17 @@ function parseSetupOptions(args) {
|
|
|
211
233
|
options.nonInteractive = true;
|
|
212
234
|
continue;
|
|
213
235
|
}
|
|
236
|
+
if (arg === "--result-file") {
|
|
237
|
+
if (options.resultFile !== undefined)
|
|
238
|
+
fail("setup: duplicate option --result-file");
|
|
239
|
+
const value = args[index + 1];
|
|
240
|
+
if (!value || value.startsWith("--"))
|
|
241
|
+
fail("setup: --result-file requires a value");
|
|
242
|
+
options.resultFile = path.resolve(value);
|
|
243
|
+
options.nonInteractive = true;
|
|
244
|
+
index += 1;
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
214
247
|
if (arg === "--install-browser" || arg === "--skip-browser") {
|
|
215
248
|
if (options.browser !== "auto")
|
|
216
249
|
fail("setup: choose only one Browser action");
|
|
@@ -250,6 +283,9 @@ function parseSetupOptions(args) {
|
|
|
250
283
|
fail(`setup: unknown option ${arg}`);
|
|
251
284
|
}
|
|
252
285
|
}
|
|
286
|
+
if (options.json && options.resultFile) {
|
|
287
|
+
fail("setup: choose either --json or --result-file");
|
|
288
|
+
}
|
|
253
289
|
return options;
|
|
254
290
|
}
|
|
255
291
|
async function collectInteractiveSetup(config) {
|
|
@@ -315,14 +351,16 @@ function readRawConfig() {
|
|
|
315
351
|
}
|
|
316
352
|
}
|
|
317
353
|
function writeConfigAtomically(config) {
|
|
318
|
-
|
|
354
|
+
writeJsonAtomically(rynxConfigFile(), config);
|
|
355
|
+
}
|
|
356
|
+
function writeJsonAtomically(file, value) {
|
|
319
357
|
const directory = path.dirname(file);
|
|
320
358
|
mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
321
359
|
const temporary = path.join(directory, `.${path.basename(file)}.${process.pid}.tmp`);
|
|
322
360
|
let descriptor;
|
|
323
361
|
try {
|
|
324
362
|
descriptor = openSync(temporary, "wx", 0o600);
|
|
325
|
-
writeFileSync(descriptor, `${JSON.stringify(
|
|
363
|
+
writeFileSync(descriptor, `${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
326
364
|
closeSync(descriptor);
|
|
327
365
|
descriptor = undefined;
|
|
328
366
|
renameSync(temporary, file);
|
package/dist/commands/skills.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { isSkillPathComponent } from "@rynx-ai/core";
|
|
4
5
|
import { fail } from "./errors.js";
|
|
5
|
-
const SKILL_NAME_PATTERN = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
6
6
|
const MAX_SKILL_BYTES = 256 * 1024;
|
|
7
7
|
const BUILTIN_SKILL_NAMES = ["browser", "emulator"];
|
|
8
8
|
export async function runSkillsCommand(args) {
|
|
@@ -55,7 +55,7 @@ export async function listBuiltinSkills() {
|
|
|
55
55
|
return guides.filter((guide) => guide !== null);
|
|
56
56
|
}
|
|
57
57
|
export async function readBuiltinSkill(name, full = false) {
|
|
58
|
-
if (!
|
|
58
|
+
if (!isSkillPathComponent(name))
|
|
59
59
|
return null;
|
|
60
60
|
if (!BUILTIN_SKILL_NAMES.includes(name))
|
|
61
61
|
return null;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import * as prompts from "@clack/prompts";
|
|
2
|
+
const DOWNLOAD_PERCENT_PATTERN = /下载进度:(\d{1,3})%$/u;
|
|
3
|
+
export function createProgressDisplay() {
|
|
4
|
+
if (!prompts.isTTY(process.stdout) || prompts.isCI()) {
|
|
5
|
+
return {
|
|
6
|
+
start: (message) => console.log(message),
|
|
7
|
+
update: (message) => console.log(message),
|
|
8
|
+
succeed: (message) => console.log(message),
|
|
9
|
+
clear: () => undefined,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
const spinner = prompts.spinner({ output: process.stdout });
|
|
13
|
+
const progress = prompts.progress({
|
|
14
|
+
output: process.stdout,
|
|
15
|
+
max: 100,
|
|
16
|
+
size: 28,
|
|
17
|
+
style: "block",
|
|
18
|
+
});
|
|
19
|
+
let spinnerActive = false;
|
|
20
|
+
let progressActive = false;
|
|
21
|
+
let completedPercent = 0;
|
|
22
|
+
const clear = () => {
|
|
23
|
+
if (progressActive)
|
|
24
|
+
progress.clear();
|
|
25
|
+
if (spinnerActive)
|
|
26
|
+
spinner.clear();
|
|
27
|
+
progressActive = false;
|
|
28
|
+
spinnerActive = false;
|
|
29
|
+
completedPercent = 0;
|
|
30
|
+
};
|
|
31
|
+
const finishDownload = () => {
|
|
32
|
+
if (!progressActive)
|
|
33
|
+
return;
|
|
34
|
+
progress.stop("Chrome for Testing 下载完成");
|
|
35
|
+
progressActive = false;
|
|
36
|
+
completedPercent = 0;
|
|
37
|
+
};
|
|
38
|
+
return {
|
|
39
|
+
start(message) {
|
|
40
|
+
clear();
|
|
41
|
+
spinner.start(message);
|
|
42
|
+
spinnerActive = true;
|
|
43
|
+
},
|
|
44
|
+
update(message) {
|
|
45
|
+
const match = DOWNLOAD_PERCENT_PATTERN.exec(message);
|
|
46
|
+
if (match) {
|
|
47
|
+
const percent = Math.min(100, Number(match[1]));
|
|
48
|
+
if (spinnerActive) {
|
|
49
|
+
spinner.clear();
|
|
50
|
+
spinnerActive = false;
|
|
51
|
+
}
|
|
52
|
+
if (!progressActive) {
|
|
53
|
+
progress.start(message);
|
|
54
|
+
progressActive = true;
|
|
55
|
+
}
|
|
56
|
+
progress.advance(percent - completedPercent, message);
|
|
57
|
+
completedPercent = percent;
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
finishDownload();
|
|
61
|
+
if (spinnerActive)
|
|
62
|
+
spinner.message(message);
|
|
63
|
+
else {
|
|
64
|
+
spinner.start(message);
|
|
65
|
+
spinnerActive = true;
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
succeed(message) {
|
|
69
|
+
finishDownload();
|
|
70
|
+
if (spinnerActive)
|
|
71
|
+
spinner.stop(message);
|
|
72
|
+
else
|
|
73
|
+
prompts.log.success(message);
|
|
74
|
+
spinnerActive = false;
|
|
75
|
+
},
|
|
76
|
+
clear,
|
|
77
|
+
};
|
|
78
|
+
}
|
package/dist/usage.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const USAGE = "Usage: rynx <command>\n\nGeneral:\n version [--json] | --version\n print the installed Rynx version\n\nSetup:\n setup [--non-interactive] [--default-runtime <codex|traex|claude>]\n [--host <host>] [--port <port>] [--log-level <level>]\n [--install-browser|--skip-browser] [--json]\n initialize configuration and local dependencies\n doctor read-only health check\n\nLifecycle:\n start | restart | stop | status | logs\n update [version] [--check] [--json]\n\nPlugins:\n market list\n market add <git-or-local-source> [--alias <id>]\n market refresh [market-id]\n market remove <market-id>\n plugin list\n plugin install <source|plugin@market> [--force] [--expect-digest <sha256-...>]\n plugin update <plugin@market> [--expect-digest <sha256-...>]\n plugin enable|disable|uninstall <plugin@market>\n plugin <plugin@market> <command> invoke a plugin-owned command\n\nAgents:\n agent list\n agent show <id>\n agent add <id>\n agent rm <id>\n\nBuiltin Skills:\n skills list [--json]\n skills get <browser|emulator> [--full] [--json]\n\nMaintenance:\n cleanup sessions [--dry-run]\n\nEmulator:\n emulator <args...>\n\nRemote Runtime:\n runtime share --address <host|ws-url> [--label <label>] [--json]\n runtime add --pairing-code <rynx://...> [--name <name>]\n runtime list [--json]\n runtime test <local|daemon-id> [--json]\n runtime forget <daemon-id>\n runtime clients list [--json]\n runtime clients revoke <grant-id>\n\nSessions:\n session fork <session-id> [--title <title>] [--json]\n\nBrowser:\n browser install|update|version|clean [...]\n browser open [url] [--session <id>] [--runtime <local|daemon-id>] [--json]\n browser status|pages|close [--session <id>] [--runtime <local|daemon-id>] [--json]\n browser endpoint [--ensure] [--session <local-id>] [--json]\n browser snapshot [--session <local-id>] [--json]\n browser navigate <url> [--session <local-id>] [--json]\n browser click (--ref <ref>|--selector <css>|--x <n> --y <n>) [--session <local-id>] [--json]\n browser type (--ref <ref>|--selector <css>) --text <text> [--session <local-id>] [--json]\n browser screenshot --output <absolute-path> [--session <local-id>] [--json]\n";
|
|
1
|
+
export declare const USAGE = "Usage: rynx <command>\n\nGeneral:\n version [--json] | --version\n print the installed Rynx version\n\nSetup:\n setup [--non-interactive] [--default-runtime <codex|traex|claude>]\n [--host <host>] [--port <port>] [--log-level <level>]\n [--install-browser|--skip-browser] [--json|--result-file <path>]\n initialize configuration and local dependencies\n doctor read-only health check\n\nLifecycle:\n start | restart | stop | status | logs\n update [version] [--check] [--json]\n\nPlugins:\n market list\n market add <git-or-local-source> [--alias <id>]\n market refresh [market-id]\n market remove <market-id>\n plugin list\n plugin install <source|plugin@market> [--force] [--expect-digest <sha256-...>]\n plugin update <plugin@market> [--expect-digest <sha256-...>]\n plugin enable|disable|uninstall <plugin@market>\n plugin <plugin@market> <command> invoke a plugin-owned command\n\nAgents:\n agent list\n agent show <id>\n agent add <id>\n agent rm <id>\n\nBuiltin Skills:\n skills list [--json]\n skills get <browser|emulator> [--full] [--json]\n\nMaintenance:\n cleanup sessions [--dry-run]\n\nEmulator:\n emulator <args...>\n\nRemote Runtime:\n runtime share --address <host|ws-url> [--label <label>] [--json]\n runtime add --pairing-code <rynx://...> [--name <name>]\n runtime list [--json]\n runtime test <local|daemon-id> [--json]\n runtime forget <daemon-id>\n runtime clients list [--json]\n runtime clients revoke <grant-id>\n\nSessions:\n session fork <session-id> [--title <title>] [--json]\n\nBrowser:\n browser install|update|version|clean [...]\n browser open [url] [--session <id>] [--runtime <local|daemon-id>] [--json]\n browser status|pages|close [--session <id>] [--runtime <local|daemon-id>] [--json]\n browser endpoint [--ensure] [--session <local-id>] [--json]\n browser snapshot [--session <local-id>] [--json]\n browser navigate <url> [--session <local-id>] [--json]\n browser click (--ref <ref>|--selector <css>|--x <n> --y <n>) [--session <local-id>] [--json]\n browser type (--ref <ref>|--selector <css>) --text <text> [--session <local-id>] [--json]\n browser screenshot --output <absolute-path> [--session <local-id>] [--json]\n";
|
package/dist/usage.js
CHANGED
|
@@ -7,7 +7,7 @@ General:
|
|
|
7
7
|
Setup:
|
|
8
8
|
setup [--non-interactive] [--default-runtime <codex|traex|claude>]
|
|
9
9
|
[--host <host>] [--port <port>] [--log-level <level>]
|
|
10
|
-
[--install-browser|--skip-browser] [--json]
|
|
10
|
+
[--install-browser|--skip-browser] [--json|--result-file <path>]
|
|
11
11
|
initialize configuration and local dependencies
|
|
12
12
|
doctor read-only health check
|
|
13
13
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rynx-ai/cli",
|
|
3
|
-
"version": "0.1.11-beta.
|
|
3
|
+
"version": "0.1.11-beta.14",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/rynx-ai/rynx.git",
|
|
@@ -51,11 +51,11 @@
|
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@clack/prompts": "^1.6.0",
|
|
53
53
|
"ws": "^8.21.0",
|
|
54
|
-
"@rynx-ai/browser-cdp": "0.1.11-beta.
|
|
55
|
-
"@rynx-ai/
|
|
56
|
-
"@rynx-ai/
|
|
57
|
-
"@rynx-ai/emulator": "0.1.11-beta.
|
|
58
|
-
"@rynx-ai/protocol": "0.1.11-beta.
|
|
54
|
+
"@rynx-ai/browser-cdp": "0.1.11-beta.14",
|
|
55
|
+
"@rynx-ai/daemon": "0.1.11-beta.14",
|
|
56
|
+
"@rynx-ai/core": "0.1.11-beta.14",
|
|
57
|
+
"@rynx-ai/emulator": "0.1.11-beta.14",
|
|
58
|
+
"@rynx-ai/protocol": "0.1.11-beta.14"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"@types/ws": "^8.18.1"
|