@rynx-ai/cli 0.1.11-beta.43 → 0.1.11-beta.45

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.
@@ -1,8 +1,12 @@
1
1
  import { startStandaloneDaemon, statusStandaloneDaemon, stopStandaloneDaemon, streamStandaloneDaemonLogs, } from "../standalone.js";
2
+ import { shutdownResidentDaemonIfIdle, waitForResidentDaemonExit, } from "../control-client.js";
3
+ import { resolveDaemonControlEndpoint } from "../control-endpoint.js";
2
4
  import { refreshAutostart } from "../autostart.js";
3
- import { assertLinuxSystemdInvocation, stopLinuxServiceIfActive, } from "../systemd-service.js";
5
+ import { assertLinuxSystemdInvocation } from "../systemd-service.js";
6
+ import { clearLegacyMaintenanceState } from "../legacy-maintenance.js";
4
7
  import { fail } from "./errors.js";
5
8
  const SYSTEMD_SERVICE_FLAG = "--systemd-service";
9
+ const IF_IDLE_FLAG = "--if-idle";
6
10
  export async function runLifecycleCommand(command, args, options = {}) {
7
11
  if (args.length === 1 && args[0] === SYSTEMD_SERVICE_FLAG) {
8
12
  assertLinuxSystemdInvocation();
@@ -12,8 +16,11 @@ export async function runLifecycleCommand(command, args, options = {}) {
12
16
  return stopStandaloneDaemon();
13
17
  fail(`${SYSTEMD_SERVICE_FLAG} is only valid for start and stop`);
14
18
  }
15
- if (args.length > 0)
19
+ const stopIfIdle = command === "stop" && args.length === 1 && args[0] === IF_IDLE_FLAG;
20
+ const statusJson = command === "status" && args.length === 1 && args[0] === "--json";
21
+ if (args.length > 0 && !stopIfIdle && !statusJson) {
16
22
  fail(`${command}: unexpected argument ${args[0]}`);
23
+ }
17
24
  switch (command) {
18
25
  case "start": {
19
26
  refreshAutostart();
@@ -23,12 +30,41 @@ export async function runLifecycleCommand(command, args, options = {}) {
23
30
  refreshAutostart();
24
31
  return startStandaloneDaemon({ restart: true, quiet: options.quiet });
25
32
  }
26
- case "stop":
27
- if (stopLinuxServiceIfActive())
28
- return 0;
29
- return stopStandaloneDaemon();
33
+ case "stop": {
34
+ const endpoint = await resolveDaemonControlEndpoint();
35
+ if (endpoint &&
36
+ (endpoint.distribution !== "standalone" || endpoint.daemonLifecycle !== "standalone")) {
37
+ throw new Error("rynx stop supports only the standalone daemon; use the owning App lifecycle");
38
+ }
39
+ if (stopIfIdle && !endpoint) {
40
+ console.error("cannot verify whole-host idle because the standalone daemon is unavailable");
41
+ return 3;
42
+ }
43
+ if (stopIfIdle) {
44
+ let result;
45
+ try {
46
+ result = await shutdownResidentDaemonIfIdle(endpoint);
47
+ }
48
+ catch (error) {
49
+ console.error("cannot complete whole-host idle check: " +
50
+ (error instanceof Error ? error.message : String(error)));
51
+ return 3;
52
+ }
53
+ if (result.outcome === "busy") {
54
+ console.error("rynx is busy: " +
55
+ `runningTurns=${result.activity.runningTurns} ` +
56
+ `pendingInteractions=${result.activity.pendingInteractions}`);
57
+ return 2;
58
+ }
59
+ if (!await waitForResidentDaemonExit(endpoint.pid)) {
60
+ console.error("rynx accepted whole-host idle shutdown but the daemon did not exit within 120 seconds; supervisor was left untouched");
61
+ return 5;
62
+ }
63
+ }
64
+ return stopStandaloneAndThenClearLegacyMaintenance();
65
+ }
30
66
  case "status":
31
- return statusStandaloneDaemon();
67
+ return statusStandaloneDaemon(statusJson ? { json: true } : undefined);
32
68
  case "logs":
33
69
  await streamStandaloneDaemonLogs();
34
70
  return 0;
@@ -36,3 +72,19 @@ export async function runLifecycleCommand(command, args, options = {}) {
36
72
  fail(`unknown lifecycle command: ${command}`);
37
73
  }
38
74
  }
75
+ async function stopStandaloneAndThenClearLegacyMaintenance() {
76
+ const status = await stopStandaloneDaemon();
77
+ if (status !== 0)
78
+ return 1;
79
+ clearLegacyMaintenanceAfterStop();
80
+ return 0;
81
+ }
82
+ function clearLegacyMaintenanceAfterStop() {
83
+ try {
84
+ clearLegacyMaintenanceState();
85
+ }
86
+ catch (error) {
87
+ console.warn("rynx lifecycle stopped but retired maintenance state could not be removed: " +
88
+ (error instanceof Error ? error.message : String(error)));
89
+ }
90
+ }
@@ -4,6 +4,7 @@ import { type RemoteRuntimeRpcMethod, type RemoteRuntimeRpcParams, type RemoteRu
4
4
  import { type PairingOffer } from "@rynx-ai/protocol/direct-runtime";
5
5
  import { type RuntimeBrowserBootstrapCredential, type RuntimeBrowserEndpointDescriptor } from "@rynx-ai/protocol/runtime-browser-bootstrap";
6
6
  import { type PluginInstallCommitInput, type PluginInstallCommitResult, type PluginInstallPreparation, type PluginInstallPrepareInput, type PluginManagementItem, type PluginManagementState, type PluginMarketplaceAddInput, type PluginMarketplaceItem } from "@rynx-ai/protocol/plugin-management";
7
+ import { type DaemonControlEndpoint } from "./control-endpoint.js";
7
8
  export { connectResidentDesktopBrowserHost, type ResidentDesktopBrowserHostConnection, type ResidentDesktopBrowserHostCommandRequest, type ResidentDesktopBrowserHostConnectOptions, type ResidentDesktopBrowserHostFailure, } from "./desktop-browser-host-client.js";
8
9
  export interface ResidentDaemonIdentity {
9
10
  installationId: string;
@@ -65,7 +66,9 @@ export declare function getResidentDaemonRuntimeStatus(): Promise<DaemonStatus>;
65
66
  * when idle. Busy is a normal result so the caller can ask the user to resolve
66
67
  * the listed work and explicitly retry.
67
68
  */
68
- export declare function shutdownResidentDaemonIfIdle(): Promise<DaemonShutdownIfIdleResult>;
69
+ export declare function shutdownResidentDaemonIfIdle(endpoint?: DaemonControlEndpoint): Promise<DaemonShutdownIfIdleResult>;
70
+ /** Wait for accepted graceful shutdown before the lifecycle owner is stopped. */
71
+ export declare function waitForResidentDaemonExit(pid: number, timeoutMs?: number): Promise<boolean>;
69
72
  export declare function getResidentChromeInspectionStatus(): Promise<DaemonChromeInspectionStatus>;
70
73
  export declare function configureResidentChromeInspection(input: DaemonChromeInspectionConfigureInput): Promise<DaemonChromeInspectionStatus>;
71
74
  export declare function cleanupResidentSessions(input?: DaemonCleanupSessionsInput): Promise<DaemonCleanupSessionsResult>;
@@ -7,7 +7,7 @@ import { parsePairingOffer, } from "@rynx-ai/protocol/direct-runtime";
7
7
  import { RUNTIME_BROWSER_BOOTSTRAP_PATH, RUNTIME_BROWSER_CAPABILITY_ENV, RUNTIME_BROWSER_CAPABILITY_HEADER, RUNTIME_BROWSER_CONTEXT_FILE_ENV, RUNTIME_BROWSER_MANAGEMENT_PATH_PREFIX, RUNTIME_BROWSER_RPC_PATH, RUNTIME_BROWSER_SESSION_ID_ENV, RUNTIME_BROWSER_SESSION_ID_HEADER, parseRuntimeBrowserBootstrapCredential, parseRuntimeBrowserEndpointDescriptor, } from "@rynx-ai/protocol/runtime-browser-bootstrap";
8
8
  import { parseRuntimeBrowserStateGetParams } from "@rynx-ai/protocol/runtime-browser";
9
9
  import { PLUGIN_INSTALL_PREPARATIONS_PATH, PLUGIN_MARKETPLACES_PATH, parsePluginInstallCommitInput, parsePluginInstallCommitResult, parsePluginInstallPreparation, parsePluginInstallPrepareInput, parsePluginManagementItem, parsePluginMarketplaceAddInput, parsePluginMarketplaceItem, pluginInstallCommitPath, pluginInstallPreparationPath, } from "@rynx-ai/protocol/plugin-management";
10
- import { ensureDaemonControlEndpoint } from "./control-endpoint.js";
10
+ import { ensureDaemonControlEndpoint, } from "./control-endpoint.js";
11
11
  export { connectResidentDesktopBrowserHost, } from "./desktop-browser-host-client.js";
12
12
  const IDENTITY_TIMEOUT_MS = 5_000;
13
13
  const RUNTIME_STATUS_TIMEOUT_MS = 5_000;
@@ -108,15 +108,36 @@ export async function getResidentDaemonRuntimeStatus() {
108
108
  * when idle. Busy is a normal result so the caller can ask the user to resolve
109
109
  * the listed work and explicitly retry.
110
110
  */
111
- export async function shutdownResidentDaemonIfIdle() {
112
- const endpoint = await ensureDaemonControlEndpoint();
113
- assertLoopbackOrigin(endpoint.origin);
114
- const response = await fetch(`${endpoint.origin}${DAEMON_SHUTDOWN_IF_IDLE_PATH}`, {
115
- method: "POST",
116
- headers: managementHeaders(endpoint.managementToken),
117
- signal: AbortSignal.timeout(DAEMON_SHUTDOWN_TIMEOUT_MS),
118
- });
119
- const body = await readBoundedResponse(response, DAEMON_SHUTDOWN_RESPONSE_MAX_BYTES);
111
+ export async function shutdownResidentDaemonIfIdle(endpoint) {
112
+ const resident = endpoint ?? await ensureDaemonControlEndpoint();
113
+ assertLoopbackOrigin(resident.origin);
114
+ let response;
115
+ try {
116
+ response = await fetch(`${resident.origin}${DAEMON_SHUTDOWN_IF_IDLE_PATH}`, {
117
+ method: "POST",
118
+ headers: managementHeaders(resident.managementToken),
119
+ signal: AbortSignal.timeout(DAEMON_SHUTDOWN_TIMEOUT_MS),
120
+ });
121
+ }
122
+ catch (error) {
123
+ // The daemon may close its listener before the 202 reaches the client.
124
+ // The original PID exiting proves that the requested lifecycle boundary
125
+ // completed, so the caller can continue with supervisor cleanup.
126
+ if (await waitForResidentDaemonExit(resident.pid)) {
127
+ return { outcome: "accepted" };
128
+ }
129
+ throw error;
130
+ }
131
+ let body;
132
+ try {
133
+ body = await readBoundedResponse(response, DAEMON_SHUTDOWN_RESPONSE_MAX_BYTES);
134
+ }
135
+ catch (error) {
136
+ if (response.status === 202 && await waitForResidentDaemonExit(resident.pid)) {
137
+ return { outcome: "accepted" };
138
+ }
139
+ throw error;
140
+ }
120
141
  if (response.status !== 202 && response.status !== 409) {
121
142
  throw daemonRequestError("daemon shutdown-if-idle request", response.status, body);
122
143
  }
@@ -125,6 +146,9 @@ export async function shutdownResidentDaemonIfIdle() {
125
146
  result = parseDaemonShutdownIfIdleResult(JSON.parse(body));
126
147
  }
127
148
  catch (error) {
149
+ if (response.status === 202 && await waitForResidentDaemonExit(resident.pid)) {
150
+ return { outcome: "accepted" };
151
+ }
128
152
  throw new Error(`daemon returned an invalid shutdown-if-idle response: ${messageOf(error)}`);
129
153
  }
130
154
  if (response.status === 202 && result.outcome !== "accepted" ||
@@ -133,6 +157,25 @@ export async function shutdownResidentDaemonIfIdle() {
133
157
  }
134
158
  return result;
135
159
  }
160
+ /** Wait for accepted graceful shutdown before the lifecycle owner is stopped. */
161
+ export async function waitForResidentDaemonExit(pid, timeoutMs = 120_000) {
162
+ const deadline = Date.now() + timeoutMs;
163
+ while (Date.now() <= deadline) {
164
+ if (!processIsAlive(pid))
165
+ return true;
166
+ await new Promise((resolve) => setTimeout(resolve, 100));
167
+ }
168
+ return !processIsAlive(pid);
169
+ }
170
+ function processIsAlive(pid) {
171
+ try {
172
+ process.kill(pid, 0);
173
+ return true;
174
+ }
175
+ catch (error) {
176
+ return error.code === "EPERM";
177
+ }
178
+ }
136
179
  export async function getResidentChromeInspectionStatus() {
137
180
  const result = await localManagementJsonRequest(DAEMON_CHROME_INSPECTION_PATH, {
138
181
  method: "GET",
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Remove the retired cross-process replacement fence.
3
+ *
4
+ * Older daemons may have left this file behind after an updater crash. The
5
+ * standalone stop path makes a best-effort attempt once lifecycle ownership is
6
+ * gone. This compatibility detail is not part of the public lifecycle result.
7
+ */
8
+ export declare function clearLegacyMaintenanceState(): void;
@@ -0,0 +1,13 @@
1
+ import { rmSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { rynxHome } from "@rynx-ai/core";
4
+ /**
5
+ * Remove the retired cross-process replacement fence.
6
+ *
7
+ * Older daemons may have left this file behind after an updater crash. The
8
+ * standalone stop path makes a best-effort attempt once lifecycle ownership is
9
+ * gone. This compatibility detail is not part of the public lifecycle result.
10
+ */
11
+ export function clearLegacyMaintenanceState() {
12
+ rmSync(join(rynxHome(), "maintenance-lease.json"), { force: true });
13
+ }
@@ -9,5 +9,7 @@ export declare function ensureStandaloneDaemon(): Promise<{
9
9
  origin: string;
10
10
  }>;
11
11
  export declare function stopStandaloneDaemon(): Promise<number>;
12
- export declare function statusStandaloneDaemon(): Promise<number>;
12
+ export declare function statusStandaloneDaemon(options?: {
13
+ json?: boolean;
14
+ }): Promise<number>;
13
15
  export declare function streamStandaloneDaemonLogs(): Promise<void>;
@@ -47,7 +47,23 @@ export async function stopStandaloneDaemon() {
47
47
  const { stopDaemon } = await import("@rynx-ai/daemon/lifecycle");
48
48
  return stopDaemon();
49
49
  }
50
- export async function statusStandaloneDaemon() {
50
+ export async function statusStandaloneDaemon(options = {}) {
51
+ if (options.json) {
52
+ const endpoint = await resolveDaemonControlEndpoint();
53
+ const status = endpoint
54
+ ? {
55
+ state: "running",
56
+ pid: endpoint.pid,
57
+ distribution: endpoint.distribution ?? "unknown",
58
+ lifecycle: endpoint.daemonLifecycle ?? "unknown",
59
+ version: endpoint.productVersion,
60
+ buildId: endpoint.buildId,
61
+ origin: endpoint.origin,
62
+ }
63
+ : { state: "stopped" };
64
+ console.log(JSON.stringify(status));
65
+ return endpoint ? 0 : 1;
66
+ }
51
67
  const { statusDaemon } = await import("@rynx-ai/daemon/lifecycle");
52
68
  return statusDaemon();
53
69
  }
@@ -46,12 +46,6 @@ export declare function disableLinuxAutostart(): void;
46
46
  /** Refresh an existing autostart unit without changing enablement. */
47
47
  export declare function refreshLinuxServiceIfPresent(): boolean;
48
48
  export declare function assertLinuxSystemdInvocation(): void;
49
- /**
50
- * Stop through systemd while the oneshot unit owns the lifecycle state. PM2
51
- * owns its own process tree; systemd only records whether its start hook has
52
- * completed and provides the matching synchronous ExecStop boundary.
53
- */
54
- export declare function stopLinuxServiceIfActive(): boolean;
55
49
  export declare function parseLinuxSystemdShow(output: string): LinuxSystemdServiceState;
56
50
  export declare function inspectLinuxPm2GodProcesses(home: string, deps?: LinuxPm2InspectionDeps): LinuxPm2GodInspection;
57
51
  export declare function scanLinuxPm2GodPids(home: string, deps?: LinuxPm2InspectionDeps): number[];
@@ -8,7 +8,6 @@ export const RYNX_SYSTEMD_SERVICE = "rynx.service";
8
8
  export const RYNX_SYSTEMD_SERVICE_ENV = "RYNX_SYSTEMD_SERVICE";
9
9
  export const RYNX_SERVICE_ENV_KEYS = "RYNX_SERVICE_ENV_KEYS";
10
10
  const COMMAND_TIMEOUT_MS = 5_000;
11
- const STOP_COMMAND_TIMEOUT_MS = 50_000;
12
11
  const AUTOMATIC_SERVICE_ENVIRONMENT = new Set([
13
12
  "ALL_PROXY",
14
13
  "AWS_CA_BUNDLE",
@@ -185,62 +184,6 @@ export function assertLinuxSystemdInvocation() {
185
184
  throw new Error(`--systemd-service requires the ${RYNX_SYSTEMD_SERVICE} cgroup`);
186
185
  }
187
186
  }
188
- /**
189
- * Stop through systemd while the oneshot unit owns the lifecycle state. PM2
190
- * owns its own process tree; systemd only records whether its start hook has
191
- * completed and provides the matching synchronous ExecStop boundary.
192
- */
193
- export function stopLinuxServiceIfActive() {
194
- if (process.platform !== "linux")
195
- return false;
196
- const context = currentContext();
197
- const inspection = inspectLinuxPm2GodProcesses(context.pm2Home);
198
- assertSingleGod(inspection);
199
- if (!linuxUserSystemdAvailable()) {
200
- const unitMode = installedLinuxUnitMode(context);
201
- if (unitMode === "legacy-or-unknown" ||
202
- (unitMode === "absent" && (inspection.kind === "service-cgroup" ||
203
- currentProcessHasLinuxServiceEvidence()))) {
204
- throw new Error(`cannot safely stop a legacy or still-loaded ${RYNX_SYSTEMD_SERVICE} without user systemd; ` +
205
- "retry from a login session where systemctl --user is available");
206
- }
207
- return false;
208
- }
209
- const state = inspectLinuxSystemdService();
210
- if (linuxSystemdServiceIsSettledInactive(state))
211
- return false;
212
- stopLinuxSystemdServiceAndVerify(context);
213
- return true;
214
- }
215
- function stopLinuxSystemdServiceAndVerify(context) {
216
- requireSuccess(run("systemctl", ["--user", "stop", RYNX_SYSTEMD_SERVICE], STOP_COMMAND_TIMEOUT_MS), `systemctl --user stop ${RYNX_SYSTEMD_SERVICE}`);
217
- const remaining = inspectLinuxPm2GodProcesses(context.pm2Home);
218
- if (remaining.kind !== "absent") {
219
- throw new Error(`${RYNX_SYSTEMD_SERVICE} stop completed but the PM2 supervisor is still running: ` +
220
- describeInspection(remaining));
221
- }
222
- }
223
- function linuxSystemdServiceIsSettledInactive(state) {
224
- return state.activeState === "inactive" || state.activeState === "failed";
225
- }
226
- function installedLinuxUnitMode(context) {
227
- if (!existsSync(context.unitPath))
228
- return "absent";
229
- const content = readFileSync(context.unitPath, "utf8");
230
- const type = /^\s*Type\s*=\s*([^\s#]+)\s*$/mi.exec(content)?.[1]?.toLowerCase();
231
- const remains = /^\s*RemainAfterExit\s*=\s*yes\s*$/mi.test(content);
232
- return type === "oneshot" && remains ? "oneshot" : "legacy-or-unknown";
233
- }
234
- function currentProcessHasLinuxServiceEvidence() {
235
- if (process.env[RYNX_SYSTEMD_SERVICE_ENV] === RYNX_SYSTEMD_SERVICE)
236
- return true;
237
- try {
238
- return cgroupHasService(linuxSystemdCgroupForPid(process.pid));
239
- }
240
- catch {
241
- return false;
242
- }
243
- }
244
187
  export function parseLinuxSystemdShow(output) {
245
188
  const values = new Map();
246
189
  for (const line of output.split(/\r?\n/)) {
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|--result-file <path>]\n initialize configuration and local dependencies\n doctor read-only health check\n\nLifecycle:\n start | restart | stop | status | logs\n autostart enable|disable|status\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 [--if-idle] | status [--json] | logs\n autostart enable|disable|status\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
@@ -12,7 +12,7 @@ Setup:
12
12
  doctor read-only health check
13
13
 
14
14
  Lifecycle:
15
- start | restart | stop | status | logs
15
+ start | restart | stop [--if-idle] | status [--json] | logs
16
16
  autostart enable|disable|status
17
17
  update [version] [--check] [--json]
18
18
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rynx-ai/cli",
3
- "version": "0.1.11-beta.43",
3
+ "version": "0.1.11-beta.45",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/rynx-ai/rynx.git",
@@ -51,12 +51,12 @@
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.43",
55
- "@rynx-ai/core": "0.1.11-beta.43",
56
- "@rynx-ai/daemon": "0.1.11-beta.43",
57
- "@rynx-ai/emulator": "0.1.11-beta.43",
58
- "@rynx-ai/protocol": "0.1.11-beta.43",
59
- "@rynx-ai/tmux": "0.1.11-beta.43"
54
+ "@rynx-ai/core": "0.1.11-beta.45",
55
+ "@rynx-ai/daemon": "0.1.11-beta.45",
56
+ "@rynx-ai/browser-cdp": "0.1.11-beta.45",
57
+ "@rynx-ai/emulator": "0.1.11-beta.45",
58
+ "@rynx-ai/protocol": "0.1.11-beta.45",
59
+ "@rynx-ai/tmux": "0.1.11-beta.45"
60
60
  },
61
61
  "devDependencies": {
62
62
  "@types/ws": "^8.18.1"