@rynx-ai/cli 0.1.11-beta.5 → 0.1.11-beta.51

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.
@@ -0,0 +1,58 @@
1
+ import { autostartPlatformLabel, disableAutostart, enableAutostart, inspectAutostart, } from "../autostart.js";
2
+ import { fail } from "./errors.js";
3
+ export async function runAutostartCommand(args) {
4
+ if (process.env.RYNX_DISTRIBUTION === "app") {
5
+ fail("Rynx App manages startup. Use the App's launch-at-login setting.");
6
+ }
7
+ const [action, ...rest] = args;
8
+ if (rest.length > 0)
9
+ fail(`autostart: unexpected argument ${rest[0]}`);
10
+ if (action === "enable") {
11
+ const state = enableAutostart();
12
+ console.log(`Rynx autostart enabled with ${autostartPlatformLabel() ?? state.manager}.`);
13
+ if (state.registrationPath)
14
+ console.log(`Registration: ${state.registrationPath}`);
15
+ console.log("Rynx will start at the next login. Start it now with `rynx start`.");
16
+ printLingerWarning(state);
17
+ return 0;
18
+ }
19
+ if (action === "disable") {
20
+ const state = disableAutostart();
21
+ console.log("Rynx autostart disabled.");
22
+ console.log("The running daemon was not stopped; use `rynx stop` if needed.");
23
+ if (state.registered) {
24
+ console.warn("An autostart registration is still present; run `rynx autostart status`.");
25
+ return 1;
26
+ }
27
+ return 0;
28
+ }
29
+ if (action === "status") {
30
+ printAutostartState(inspectAutostart());
31
+ return 0;
32
+ }
33
+ fail("Usage: rynx autostart <enable|disable|status>");
34
+ }
35
+ function printAutostartState(state) {
36
+ console.log(`manager: ${state.manager}`);
37
+ console.log(`supported: ${state.supported ? "yes" : "no"}`);
38
+ console.log(`registered: ${state.registered ? "yes" : "no"}`);
39
+ if (state.active !== undefined) {
40
+ console.log(`active: ${state.active ? "yes" : "no"}`);
41
+ }
42
+ if (state.lingerEnabled !== undefined) {
43
+ console.log(`linger: ${state.lingerEnabled ? "yes" : "no"}`);
44
+ }
45
+ if (state.registrationPath) {
46
+ console.log(`registration: ${state.registrationPath}`);
47
+ }
48
+ if (state.detail)
49
+ console.log(`detail: ${state.detail}`);
50
+ }
51
+ function printLingerWarning(state) {
52
+ if (state.manager !== "systemd-user" || state.lingerEnabled !== false)
53
+ return;
54
+ console.warn("Linger is disabled; Rynx stops when this user logs out.");
55
+ if (state.lingerEnableCommand) {
56
+ console.warn(`To keep it running across logout and start it before login, run manually: ${state.lingerEnableCommand}`);
57
+ }
58
+ }
@@ -1 +1,5 @@
1
+ import type { RuntimeBrowserRequestHeadersPolicy } from "@rynx-ai/protocol/runtime-browser";
1
2
  export declare function runBrowserCommand(args: readonly string[]): Promise<number>;
3
+ export declare function projectRequestHeadersPolicyForOutput(policy: RuntimeBrowserRequestHeadersPolicy, showValues: boolean): RuntimeBrowserRequestHeadersPolicy & {
4
+ valuesRedacted: boolean;
5
+ };
@@ -1,9 +1,6 @@
1
- import { writeFile } from "node:fs/promises";
2
- import path from "node:path";
3
- import { connectBrowserAutomation, } from "@rynx-ai/browser-cdp";
4
- import WebSocket from "ws";
5
1
  import { parseBrowserCliArgs, resolveBrowserCliTarget, } from "../browser-cli-args.js";
6
- import { callManagedRuntimeBrowser, callResidentRuntime, getResidentRuntimeLocalBrowserAutomationAccess, getResidentRuntimeLocalBrowserEndpoint, readOptionalManagedRuntimeBrowserCredential, } from "../control-client.js";
2
+ import { callManagedRuntimeBrowser, callResidentRuntime, executeResidentBrowserCommand, ResidentBrowserCommandError, getResidentRuntimeLocalBrowserEndpoint, readOptionalManagedRuntimeBrowserCredential, } from "../control-client.js";
3
+ import { createProgressDisplay } from "../progress-display.js";
7
4
  import { fail } from "./errors.js";
8
5
  export async function runBrowserCommand(args) {
9
6
  let parsed;
@@ -20,9 +17,18 @@ export async function runBrowserCommand(args) {
20
17
  const channel = browserReleaseChannel(parsed.channel);
21
18
  const { createBrowserArtifactManagementService } = await import("@rynx-ai/daemon/browser-artifacts");
22
19
  const artifacts = createBrowserArtifactManagementService();
23
- const result = parsed.subcommand === "install"
24
- ? await artifacts.install(parsed.version ? { version: parsed.version } : { channel }, parsed.json ? {} : { onProgress: (message) => console.error(message) })
25
- : await artifacts.update({ channel }, parsed.json ? {} : { onProgress: (message) => console.error(message) });
20
+ const progress = parsed.json ? undefined : createProgressDisplay();
21
+ progress?.start(parsed.subcommand === "install" ? "正在安装 Rynx Browser" : "正在更新 Rynx Browser");
22
+ let result;
23
+ try {
24
+ result = parsed.subcommand === "install"
25
+ ? await artifacts.install(parsed.version ? { version: parsed.version } : { channel }, progress ? { onProgress: (message) => progress.update(message) } : {})
26
+ : await artifacts.update({ channel }, progress ? { onProgress: (message) => progress.update(message) } : {});
27
+ }
28
+ catch (error) {
29
+ progress?.clear();
30
+ throw error;
31
+ }
26
32
  if (parsed.json) {
27
33
  console.log(JSON.stringify({
28
34
  resolved: result.resolved,
@@ -30,9 +36,7 @@ export async function runBrowserCommand(args) {
30
36
  }, null, 2));
31
37
  }
32
38
  else {
33
- for (const message of result.messages)
34
- console.log(message);
35
- console.log(`Active Browser engine: Chrome for Testing ${result.installed.version}.`);
39
+ progress.succeed(`Rynx Browser 已就绪:Chrome for Testing ${result.installed.version}`);
36
40
  }
37
41
  return 0;
38
42
  }
@@ -75,8 +79,47 @@ export async function runBrowserCommand(args) {
75
79
  return 0;
76
80
  }
77
81
  const target = await resolveBrowserTarget(parsed);
78
- if (isAutomationCommand(parsed.subcommand)) {
79
- return runBrowserAutomation(parsed, target);
82
+ if (parsed.subcommand === "headers") {
83
+ const current = await callBrowserRuntime(target, "browser.request-headers.get", {
84
+ sessionId: target.sessionId,
85
+ });
86
+ if (parsed.headersAction === "get") {
87
+ if (parsed.showHeaderValues && target.credential) {
88
+ fail("browser headers get: --show-values is unavailable inside a managed Session; " +
89
+ "use the Session settings UI");
90
+ }
91
+ printRequestHeadersPolicy(current, parsed.json, parsed.showHeaderValues === true);
92
+ return 0;
93
+ }
94
+ const headers = parsed.clearHeaders
95
+ ? []
96
+ : parsed.headers?.map(parseCliRequestHeader) ?? current.headers;
97
+ const updated = await callBrowserRuntime(target, "browser.request-headers.set", {
98
+ sessionId: target.sessionId,
99
+ expectedRevision: parsed.expectedRevision ?? current.revision,
100
+ enabled: parsed.headersEnabled ?? current.enabled,
101
+ headers,
102
+ });
103
+ printRequestHeadersPolicy(updated, parsed.json, false);
104
+ return 0;
105
+ }
106
+ if (parsed.subcommand === "exec") {
107
+ try {
108
+ const result = await executeResidentBrowserCommand({ argv: parsed.argv, ...(parsed.page ? { pageId: parsed.page } : {}) }, { sessionId: target.sessionId, credential: target.credential });
109
+ if (!parsed.json && typeof result.data?.help === "string")
110
+ console.log(result.data.help);
111
+ else if (!parsed.json && typeof result.data.snapshot === "string")
112
+ console.log(result.data.snapshot);
113
+ else
114
+ console.log(JSON.stringify(result, null, 2));
115
+ return 0;
116
+ }
117
+ catch (error) {
118
+ if (!(error instanceof ResidentBrowserCommandError))
119
+ throw error;
120
+ console.error(parsed.json ? JSON.stringify({ ...error.details, status: error.status }) : error.message);
121
+ return 1;
122
+ }
80
123
  }
81
124
  const sessionId = target.sessionId;
82
125
  if (parsed.subcommand === "open") {
@@ -125,86 +168,6 @@ function browserReleaseChannel(value) {
125
168
  }
126
169
  return normalized;
127
170
  }
128
- async function runBrowserAutomation(parsed, target) {
129
- if (target.runtimeSelector !== "local") {
130
- fail(`browser ${parsed.subcommand}: automation is available only on the local Runtime`);
131
- }
132
- const automationAccess = await getResidentRuntimeLocalBrowserAutomationAccess({
133
- ...(target.credential ? {} : { sessionId: target.sessionId }),
134
- });
135
- const descriptor = automationAccess.descriptor;
136
- let client;
137
- try {
138
- client = await connectBrowserAutomation({
139
- endpoint: descriptor.endpoint,
140
- ...(descriptor.pageTargetId ? { pageTargetId: descriptor.pageTargetId } : {}),
141
- referenceKey: automationAccess.referenceKey,
142
- createWebSocket: (endpoint) => new WebSocket(endpoint),
143
- });
144
- if (parsed.subcommand === "snapshot") {
145
- const snapshot = await client.snapshot();
146
- if (parsed.json) {
147
- console.log(JSON.stringify({
148
- sessionId: descriptor.sessionId,
149
- browserGeneration: descriptor.browserGeneration,
150
- snapshot,
151
- }, null, 2));
152
- }
153
- else {
154
- printAutomationSnapshot(snapshot.nodes);
155
- }
156
- return 0;
157
- }
158
- if (parsed.subcommand === "navigate") {
159
- const navigation = await client.navigate(parsed.url);
160
- printAutomationResult(parsed, descriptor.browserGeneration, navigation);
161
- return 0;
162
- }
163
- if (parsed.subcommand === "click") {
164
- const clickTarget = parsed.ref !== undefined
165
- ? { ref: parsed.ref }
166
- : parsed.selector !== undefined
167
- ? { selector: parsed.selector }
168
- : { x: parsed.x, y: parsed.y };
169
- await client.click(clickTarget);
170
- printAutomationResult(parsed, descriptor.browserGeneration);
171
- return 0;
172
- }
173
- if (parsed.subcommand === "type") {
174
- const typeTarget = parsed.ref !== undefined
175
- ? { ref: parsed.ref }
176
- : { selector: parsed.selector };
177
- await client.type(typeTarget, parsed.text);
178
- printAutomationResult(parsed, descriptor.browserGeneration);
179
- return 0;
180
- }
181
- const screenshot = await client.screenshot({
182
- ...(parsed.format ? { format: parsed.format } : {}),
183
- ...(parsed.quality !== undefined ? { quality: parsed.quality } : {}),
184
- });
185
- const output = path.resolve(parsed.output);
186
- if (!path.isAbsolute(parsed.output)) {
187
- fail("browser screenshot: --output must be an absolute path");
188
- }
189
- await writeFile(output, Buffer.from(screenshot.data, "base64"), { mode: 0o600 });
190
- if (parsed.json) {
191
- console.log(JSON.stringify({
192
- completed: true,
193
- browserGeneration: descriptor.browserGeneration,
194
- output,
195
- format: screenshot.format,
196
- mimeType: screenshot.mimeType,
197
- }, null, 2));
198
- }
199
- else {
200
- console.log(output);
201
- }
202
- return 0;
203
- }
204
- finally {
205
- client?.close();
206
- }
207
- }
208
171
  async function resolveBrowserTarget(args) {
209
172
  const credential = await readOptionalManagedRuntimeBrowserCredential();
210
173
  try {
@@ -244,34 +207,40 @@ function printBrowserPages(state) {
244
207
  console.log(`${marker} ${page.pageId} ${page.url}${title}`);
245
208
  }
246
209
  }
247
- function isAutomationCommand(subcommand) {
248
- return subcommand === "snapshot"
249
- || subcommand === "navigate"
250
- || subcommand === "click"
251
- || subcommand === "type"
252
- || subcommand === "screenshot";
210
+ function parseCliRequestHeader(value) {
211
+ const separator = value.indexOf(":");
212
+ if (separator <= 0) {
213
+ fail("browser headers set: --header must use 'Name: value'");
214
+ }
215
+ const name = value.slice(0, separator).trim();
216
+ const rawValue = value.slice(separator + 1);
217
+ return {
218
+ name,
219
+ value: rawValue.startsWith(" ") ? rawValue.slice(1) : rawValue,
220
+ };
253
221
  }
254
- function printAutomationResult(parsed, browserGeneration, result = {}) {
255
- if (parsed.json) {
256
- console.log(JSON.stringify({
257
- completed: true,
258
- browserGeneration,
259
- ...result,
260
- }, null, 2));
261
- }
262
- else {
263
- console.log(`Browser ${parsed.subcommand} completed.`);
264
- }
265
- }
266
- function printAutomationSnapshot(nodes) {
267
- if (nodes.length === 0) {
268
- console.log("(empty accessibility tree)");
222
+ function printRequestHeadersPolicy(policy, json, showValues) {
223
+ const output = projectRequestHeadersPolicyForOutput(policy, showValues);
224
+ if (json) {
225
+ console.log(JSON.stringify(output, null, 2));
269
226
  return;
270
227
  }
271
- for (const node of nodes) {
272
- const name = node.name ? ` ${JSON.stringify(node.name)}` : "";
273
- const value = node.value ? ` value=${JSON.stringify(node.value)}` : "";
274
- const ref = node.ref ? ` ref=${node.ref}` : "";
275
- console.log(`${node.role}${name}${value}${ref}`);
228
+ console.log(`Browser request headers ${output.enabled ? "enabled" : "disabled"} · revision ${output.revision}`);
229
+ if (output.headers.length === 0) {
230
+ console.log(" (no configured headers)");
231
+ return;
276
232
  }
233
+ for (const header of output.headers)
234
+ console.log(` ${header.name}: ${header.value}`);
235
+ }
236
+ export function projectRequestHeadersPolicyForOutput(policy, showValues) {
237
+ return {
238
+ enabled: policy.enabled,
239
+ revision: policy.revision,
240
+ valuesRedacted: !showValues,
241
+ headers: policy.headers.map((header) => ({
242
+ name: header.name,
243
+ value: showValues ? header.value : "[redacted]",
244
+ })),
245
+ };
277
246
  }
@@ -1 +1,3 @@
1
- export declare function runLifecycleCommand(command: string, args: readonly string[]): Promise<number>;
1
+ export declare function runLifecycleCommand(command: string, args: readonly string[], options?: {
2
+ quiet?: boolean;
3
+ }): Promise<number>;
@@ -1,17 +1,77 @@
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";
4
+ import { assertMacLaunchdInvocation, refreshAutostart } from "../autostart.js";
5
+ import { assertLinuxSystemdInvocation } from "../systemd-service.js";
6
+ import { clearLegacyMaintenanceState } from "../legacy-maintenance.js";
2
7
  import { fail } from "./errors.js";
3
- export async function runLifecycleCommand(command, args) {
4
- if (args.length > 0)
5
- fail(`${command}: unexpected argument ${args[0]}`);
6
- switch (command) {
7
- case "start":
8
+ const SYSTEMD_SERVICE_FLAG = "--systemd-service";
9
+ const LAUNCHD_SERVICE_FLAG = "--launchd-service";
10
+ const IF_IDLE_FLAG = "--if-idle";
11
+ export async function runLifecycleCommand(command, args, options = {}) {
12
+ if (args.length === 1 && args[0] === SYSTEMD_SERVICE_FLAG) {
13
+ assertLinuxSystemdInvocation();
14
+ if (command === "start")
8
15
  return startStandaloneDaemon();
9
- case "restart":
10
- return startStandaloneDaemon({ restart: true });
11
- case "stop":
16
+ if (command === "stop")
12
17
  return stopStandaloneDaemon();
18
+ fail(`${SYSTEMD_SERVICE_FLAG} is only valid for start and stop`);
19
+ }
20
+ if (args.length === 1 && args[0] === LAUNCHD_SERVICE_FLAG) {
21
+ assertMacLaunchdInvocation();
22
+ if (command === "start")
23
+ return startStandaloneDaemon();
24
+ fail(`${LAUNCHD_SERVICE_FLAG} is only valid for start`);
25
+ }
26
+ const stopIfIdle = command === "stop" && args.length === 1 && args[0] === IF_IDLE_FLAG;
27
+ const statusJson = command === "status" && args.length === 1 && args[0] === "--json";
28
+ if (args.length > 0 && !stopIfIdle && !statusJson) {
29
+ fail(`${command}: unexpected argument ${args[0]}`);
30
+ }
31
+ switch (command) {
32
+ case "start": {
33
+ refreshAutostart();
34
+ return startStandaloneDaemon(options.quiet ? { quiet: true } : undefined);
35
+ }
36
+ case "restart": {
37
+ refreshAutostart();
38
+ return startStandaloneDaemon({ restart: true, quiet: options.quiet });
39
+ }
40
+ case "stop": {
41
+ const endpoint = await resolveDaemonControlEndpoint();
42
+ if (endpoint &&
43
+ (endpoint.distribution !== "standalone" || endpoint.daemonLifecycle !== "standalone")) {
44
+ throw new Error("rynx stop supports only the standalone daemon; use the owning App lifecycle");
45
+ }
46
+ if (stopIfIdle && !endpoint) {
47
+ console.error("cannot verify whole-host idle because the standalone daemon is unavailable");
48
+ return 3;
49
+ }
50
+ if (stopIfIdle) {
51
+ let result;
52
+ try {
53
+ result = await shutdownResidentDaemonIfIdle(endpoint);
54
+ }
55
+ catch (error) {
56
+ console.error("cannot complete whole-host idle check: " +
57
+ (error instanceof Error ? error.message : String(error)));
58
+ return 3;
59
+ }
60
+ if (result.outcome === "busy") {
61
+ console.error("rynx is busy: " +
62
+ `runningTurns=${result.activity.runningTurns} ` +
63
+ `pendingInteractions=${result.activity.pendingInteractions}`);
64
+ return 2;
65
+ }
66
+ if (!await waitForResidentDaemonExit(endpoint.pid)) {
67
+ console.error("rynx accepted whole-host idle shutdown but the daemon did not exit within 120 seconds; supervisor was left untouched");
68
+ return 5;
69
+ }
70
+ }
71
+ return stopStandaloneAndThenClearLegacyMaintenance();
72
+ }
13
73
  case "status":
14
- return statusStandaloneDaemon();
74
+ return statusStandaloneDaemon(statusJson ? { json: true } : undefined);
15
75
  case "logs":
16
76
  await streamStandaloneDaemonLogs();
17
77
  return 0;
@@ -19,3 +79,19 @@ export async function runLifecycleCommand(command, args) {
19
79
  fail(`unknown lifecycle command: ${command}`);
20
80
  }
21
81
  }
82
+ async function stopStandaloneAndThenClearLegacyMaintenance() {
83
+ const status = await stopStandaloneDaemon();
84
+ if (status !== 0)
85
+ return 1;
86
+ clearLegacyMaintenanceAfterStop();
87
+ return 0;
88
+ }
89
+ function clearLegacyMaintenanceAfterStop() {
90
+ try {
91
+ clearLegacyMaintenanceState();
92
+ }
93
+ catch (error) {
94
+ console.warn("rynx lifecycle stopped but retired maintenance state could not be removed: " +
95
+ (error instanceof Error ? error.message : String(error)));
96
+ }
97
+ }
@@ -1,14 +1,25 @@
1
1
  import { createInterface } from "node:readline/promises";
2
- import { cancelResidentPluginInstallation, commitResidentPluginInstallation, invokeResidentPluginCommand, listResidentPlugins, prepareResidentPluginInstallation, setResidentPluginEnabled, uninstallResidentPlugin, } from "../control-client.js";
2
+ import { cancelResidentPluginInstallation, commitResidentPluginInstallation, prepareResidentPluginInstallation, setResidentPluginEnabled, uninstallResidentPlugin, } from "../control-client.js";
3
3
  import { fail } from "./errors.js";
4
- const PLUGIN_STDIN_MAX_BYTES = 256 * 1024;
5
4
  const PLUGIN_DIGEST_PATTERN = /^sha256-[A-Za-z0-9+/]{43}={0,2}$/;
6
5
  const CANONICAL_PLUGIN_ID_PATTERN = /^[a-z][a-z0-9-]{0,62}@[a-z0-9][a-z0-9-]{0,62}(?:\/[a-z0-9][a-z0-9._-]{0,99})?$/;
6
+ const PLUGIN_USAGE = `Usage: rynx plugin <command|plugin-id>
7
+
8
+ Management:
9
+ list
10
+ install <source|plugin@market> [--force] [--expect-digest <sha256-...>]
11
+ update <plugin@market> [--expect-digest <sha256-...>]
12
+ enable|disable|uninstall <plugin@market>
13
+
14
+ Plugin commands:
15
+ <plugin-id> <command> [args...]
16
+ <plugin-id> --help`;
7
17
  export async function runPluginManageCommand(args, options = {}) {
8
18
  const [subcommand, pluginId] = args;
9
19
  switch (subcommand) {
10
20
  case "list": {
11
- const plugins = await listResidentPlugins();
21
+ const { listInstalledPlugins } = await import("@rynx-ai/daemon/plugin-cli");
22
+ const plugins = listInstalledPlugins();
12
23
  console.log("Plugins");
13
24
  if (plugins.length === 0) {
14
25
  console.log(" (none)");
@@ -126,23 +137,50 @@ export async function runPluginCommand(args) {
126
137
  const [pluginId, command] = args;
127
138
  if (!pluginId)
128
139
  fail("plugin: missing plugin id");
140
+ if (pluginId === "--help" || pluginId === "-h" || pluginId === "help") {
141
+ console.log(PLUGIN_USAGE);
142
+ return 0;
143
+ }
129
144
  if (["list", "install", "update", "uninstall", "enable", "disable"].includes(pluginId)) {
130
145
  return runPluginManageCommand(args);
131
146
  }
132
147
  if (!command)
133
148
  fail(`plugin ${pluginId}: missing command`);
134
- const stdin = process.stdin.isTTY
135
- ? undefined
136
- : await readStdinBounded(PLUGIN_STDIN_MAX_BYTES);
137
- const result = await invokeResidentPluginCommand(pluginId, args.slice(1), stdin === undefined ? {} : { stdin });
138
- if (result.stdout)
139
- process.stdout.write(result.stdout);
140
- if (result.stderr)
141
- process.stderr.write(result.stderr);
142
- if (result.truncated) {
143
- process.stderr.write("rynx: plugin command output was truncated by the daemon\n");
149
+ const pluginCli = await import("@rynx-ai/daemon/plugin-cli");
150
+ if (command === "--help" || command === "-h") {
151
+ console.log(pluginCli.installedPluginCommandUsage(pluginId));
152
+ return 0;
153
+ }
154
+ return runPluginCliWithForwardedSignals((signal) => pluginCli.runPluginCliCommand(pluginId, args.slice(1), {
155
+ stdio: "inherit",
156
+ signal,
157
+ }));
158
+ }
159
+ async function runPluginCliWithForwardedSignals(run) {
160
+ const controller = new AbortController();
161
+ let interruptedBy;
162
+ const interrupt = (signal) => {
163
+ interruptedBy ??= signal;
164
+ if (!controller.signal.aborted) {
165
+ controller.abort(new Error(`plugin command interrupted by ${signal}`));
166
+ }
167
+ };
168
+ const onSigint = () => interrupt("SIGINT");
169
+ const onSigterm = () => interrupt("SIGTERM");
170
+ process.on("SIGINT", onSigint);
171
+ process.on("SIGTERM", onSigterm);
172
+ try {
173
+ return (await run(controller.signal)).code;
174
+ }
175
+ catch (error) {
176
+ if (interruptedBy)
177
+ return interruptedBy === "SIGINT" ? 130 : 143;
178
+ throw error;
179
+ }
180
+ finally {
181
+ process.off("SIGINT", onSigint);
182
+ process.off("SIGTERM", onSigterm);
144
183
  }
145
- return result.code;
146
184
  }
147
185
  function parseInstallationArgs(operation, args) {
148
186
  const target = args[0];
@@ -219,15 +257,3 @@ async function confirmInTerminal(message) {
219
257
  prompt.close();
220
258
  }
221
259
  }
222
- async function readStdinBounded(maxBytes) {
223
- const chunks = [];
224
- let bytes = 0;
225
- for await (const chunk of process.stdin) {
226
- const value = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
227
- bytes += value.byteLength;
228
- if (bytes > maxBytes)
229
- fail(`plugin stdin exceeds ${maxBytes} bytes`);
230
- chunks.push(value);
231
- }
232
- return Buffer.concat(chunks, bytes).toString("utf8");
233
- }