@rynx-ai/cli 0.1.11-beta.1 → 0.1.11-beta.3

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,10 @@
1
+ export interface CliDependencyVersions {
2
+ cliVersion: string;
3
+ daemonVersion: string;
4
+ }
5
+ /** Read the versions in the dependency closure owned by this CLI installation. */
6
+ export declare function resolveCliDependencyVersions(): CliDependencyVersions;
7
+ /** Resolve the CLI-owned process entry used exclusively by Rynx App. */
8
+ export declare function resolveCliAppRuntimeEntry(moduleUrl?: string): string;
9
+ /** Run the App-owned daemon in this dedicated CLI App Runtime process. */
10
+ export declare function runAppRuntimeProcess(): Promise<void>;
@@ -0,0 +1,34 @@
1
+ import path from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ import { installedDaemonVersion } from "@rynx-ai/daemon/entry-path";
4
+ import { installedVersion } from "./version.js";
5
+ /** Read the versions in the dependency closure owned by this CLI installation. */
6
+ export function resolveCliDependencyVersions() {
7
+ return {
8
+ cliVersion: installedVersion(),
9
+ daemonVersion: installedDaemonVersion(),
10
+ };
11
+ }
12
+ /** Resolve the CLI-owned process entry used exclusively by Rynx App. */
13
+ export function resolveCliAppRuntimeEntry(moduleUrl = import.meta.url) {
14
+ return fileURLToPath(moduleUrl);
15
+ }
16
+ /** Run the App-owned daemon in this dedicated CLI App Runtime process. */
17
+ export async function runAppRuntimeProcess() {
18
+ if (process.env.RYNX_DISTRIBUTION !== "app") {
19
+ throw new Error("CLI App Runtime requires RYNX_DISTRIBUTION=app");
20
+ }
21
+ if (process.env.RYNX_DAEMON_LIFECYCLE !== "follow-app" &&
22
+ process.env.RYNX_DAEMON_LIFECYCLE !== "resident") {
23
+ throw new Error("CLI App Runtime requires an App daemon lifecycle");
24
+ }
25
+ const { runDaemonProcess } = await import("@rynx-ai/daemon/internal/process");
26
+ await runDaemonProcess();
27
+ }
28
+ if (process.argv[1] &&
29
+ path.resolve(process.argv[1]) === path.resolve(fileURLToPath(import.meta.url))) {
30
+ runAppRuntimeProcess().catch((error) => {
31
+ console.error(error instanceof Error ? error.stack ?? error.message : String(error));
32
+ process.exitCode = 1;
33
+ });
34
+ }
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { callManagedRuntimeBrowser, callResidentRuntime, cancelResidentPluginInstallation, commitResidentPluginInstallation, cleanResidentBrowserArtifacts, cleanupResidentSessions, createResidentRemoteRuntimePairingOffer, ensureResidentDaemon, forgetResidentRuntimeTarget, getResidentChromeInspectionStatus, getResidentDaemonIdentity, getResidentDaemonRuntimeStatus, getResidentBrowserArtifactVersion, getResidentRuntimeLocalBrowserEndpoint, invokeResidentPluginCommand, installResidentBrowserArtifact, listResidentPlugins, listResidentRemoteRuntimeClients, listResidentRuntimeTargets, pairResidentRuntimeTarget, prepareResidentPluginInstallation, readManagedRuntimeBrowserCredential, readOptionalManagedRuntimeBrowserCredential, reloadResidentPluginRuntime, revokeResidentRemoteRuntimeClient, setResidentPluginEnabled, shutdownResidentDaemonIfIdle, configureResidentChromeInspection, testResidentRuntimeTarget, uninstallResidentPlugin, updateResidentBrowserArtifact, connectResidentDesktopBrowserHost, ResidentRuntimeCallError, type InvokeResidentPluginCommandOptions, type ResidentDaemon, type ResidentDaemonIdentity, type ResidentDesktopBrowserHostCommandRequest, type ResidentDesktopBrowserHostConnectOptions, type ResidentDesktopBrowserHostConnection, type ResidentDesktopBrowserHostFailure, type ResidentPluginCommandResult, type ResidentPluginManagementItem, type ResidentPluginManagementState, type ResidentRemoteRuntimeClientGrant, type ResidentRuntimeCallErrorCode, type ResidentRuntimeCallOutcome, type ResidentRuntimeTargetTestResult, type ResidentRuntimeTargetView, } from "./control-client.js";
1
+ export { callManagedRuntimeBrowser, callResidentRuntime, cancelResidentPluginInstallation, commitResidentPluginInstallation, cleanupResidentSessions, createResidentRemoteRuntimePairingOffer, forgetResidentRuntimeTarget, getResidentChromeInspectionStatus, getResidentDaemonIdentity, getResidentDaemonRuntimeStatus, getResidentRuntimeLocalBrowserEndpoint, invokeResidentPluginCommand, listResidentPlugins, listResidentRemoteRuntimeClients, listResidentRuntimeTargets, pairResidentRuntimeTarget, prepareResidentPluginInstallation, readManagedRuntimeBrowserCredential, readOptionalManagedRuntimeBrowserCredential, revokeResidentRemoteRuntimeClient, setResidentPluginEnabled, shutdownResidentDaemonIfIdle, configureResidentChromeInspection, testResidentRuntimeTarget, uninstallResidentPlugin, connectResidentDesktopBrowserHost, ResidentRuntimeCallError, type InvokeResidentPluginCommandOptions, type ResidentDaemonIdentity, type ResidentDesktopBrowserHostCommandRequest, type ResidentDesktopBrowserHostConnectOptions, type ResidentDesktopBrowserHostConnection, type ResidentDesktopBrowserHostFailure, type ResidentPluginCommandResult, type ResidentPluginManagementItem, type ResidentPluginManagementState, type ResidentRemoteRuntimeClientGrant, type ResidentRuntimeCallErrorCode, type ResidentRuntimeCallOutcome, type ResidentRuntimeTargetTestResult, type ResidentRuntimeTargetView, } from "./control-client.js";
2
2
  export type { DaemonChromeInspectionConfigureInput, DaemonChromeInspectionStatus, } from "@rynx-ai/protocol/control";
3
3
  export type { PluginInstallCommitInput, PluginInstallCommitResult, PluginInstallPreparation, PluginInstallPrepareInput, } from "@rynx-ai/protocol/plugin-management";
4
4
  export { ensureDaemonControlEndpoint, resolveDaemonControlEndpoint, type DaemonControlEndpoint, type ResolveDaemonControlEndpointOptions, } from "./control-endpoint.js";
package/dist/client.js CHANGED
@@ -1,2 +1,2 @@
1
- export { callManagedRuntimeBrowser, callResidentRuntime, cancelResidentPluginInstallation, commitResidentPluginInstallation, cleanResidentBrowserArtifacts, cleanupResidentSessions, createResidentRemoteRuntimePairingOffer, ensureResidentDaemon, forgetResidentRuntimeTarget, getResidentChromeInspectionStatus, getResidentDaemonIdentity, getResidentDaemonRuntimeStatus, getResidentBrowserArtifactVersion, getResidentRuntimeLocalBrowserEndpoint, invokeResidentPluginCommand, installResidentBrowserArtifact, listResidentPlugins, listResidentRemoteRuntimeClients, listResidentRuntimeTargets, pairResidentRuntimeTarget, prepareResidentPluginInstallation, readManagedRuntimeBrowserCredential, readOptionalManagedRuntimeBrowserCredential, reloadResidentPluginRuntime, revokeResidentRemoteRuntimeClient, setResidentPluginEnabled, shutdownResidentDaemonIfIdle, configureResidentChromeInspection, testResidentRuntimeTarget, uninstallResidentPlugin, updateResidentBrowserArtifact, connectResidentDesktopBrowserHost, ResidentRuntimeCallError, } from "./control-client.js";
1
+ export { callManagedRuntimeBrowser, callResidentRuntime, cancelResidentPluginInstallation, commitResidentPluginInstallation, cleanupResidentSessions, createResidentRemoteRuntimePairingOffer, forgetResidentRuntimeTarget, getResidentChromeInspectionStatus, getResidentDaemonIdentity, getResidentDaemonRuntimeStatus, getResidentRuntimeLocalBrowserEndpoint, invokeResidentPluginCommand, listResidentPlugins, listResidentRemoteRuntimeClients, listResidentRuntimeTargets, pairResidentRuntimeTarget, prepareResidentPluginInstallation, readManagedRuntimeBrowserCredential, readOptionalManagedRuntimeBrowserCredential, revokeResidentRemoteRuntimeClient, setResidentPluginEnabled, shutdownResidentDaemonIfIdle, configureResidentChromeInspection, testResidentRuntimeTarget, uninstallResidentPlugin, connectResidentDesktopBrowserHost, ResidentRuntimeCallError, } from "./control-client.js";
2
2
  export { ensureDaemonControlEndpoint, resolveDaemonControlEndpoint, } from "./control-endpoint.js";
@@ -1,6 +1,6 @@
1
1
  export declare function shouldUseAppDistributionCommand(command: string | undefined, env?: NodeJS.ProcessEnv): boolean;
2
2
  /**
3
- * Prevent the App launcher from falling through to the compatibility daemon
4
- * CLI and accidentally creating or inspecting a PM2-owned second lifecycle.
3
+ * Prevent the App launcher from falling through to standalone lifecycle
4
+ * commands and accidentally creating or inspecting a PM2-owned second owner.
5
5
  */
6
6
  export declare function runAppDistributionCommand(command: string, args: readonly string[]): Promise<number>;
@@ -4,7 +4,6 @@ import { rynxHome } from "@rynx-ai/core";
4
4
  import { resolveDaemonControlEndpoint } from "../control-endpoint.js";
5
5
  import { fail } from "./errors.js";
6
6
  const APP_ONLY_COMMANDS = new Set([
7
- "setup",
8
7
  "update",
9
8
  "start",
10
9
  "restart",
@@ -19,8 +18,8 @@ export function shouldUseAppDistributionCommand(command, env = process.env) {
19
18
  && env.RYNX_DISTRIBUTION === "app";
20
19
  }
21
20
  /**
22
- * Prevent the App launcher from falling through to the compatibility daemon
23
- * CLI and accidentally creating or inspecting a PM2-owned second lifecycle.
21
+ * Prevent the App launcher from falling through to standalone lifecycle
22
+ * commands and accidentally creating or inspecting a PM2-owned second owner.
24
23
  */
25
24
  export async function runAppDistributionCommand(command, args) {
26
25
  const json = args.includes("--json");
@@ -44,9 +43,6 @@ export async function runAppDistributionCommand(command, args) {
44
43
  printRecentDaemonLogs();
45
44
  return 0;
46
45
  }
47
- if (command === "setup") {
48
- fail("Rynx App setup is completed in its onboarding and Desktop Settings.");
49
- }
50
46
  if (command === "update") {
51
47
  fail("Rynx App updates are managed from Rynx > Check for Updates.");
52
48
  }
@@ -3,7 +3,7 @@ import path from "node:path";
3
3
  import { connectBrowserAutomation, } from "@rynx-ai/browser-cdp";
4
4
  import WebSocket from "ws";
5
5
  import { parseBrowserCliArgs, resolveBrowserCliTarget, } from "../browser-cli-args.js";
6
- import { callManagedRuntimeBrowser, callResidentRuntime, cleanResidentBrowserArtifacts, getResidentBrowserArtifactVersion, getResidentRuntimeLocalBrowserAutomationAccess, getResidentRuntimeLocalBrowserEndpoint, installResidentBrowserArtifact, readOptionalManagedRuntimeBrowserCredential, updateResidentBrowserArtifact, } from "../control-client.js";
6
+ import { callManagedRuntimeBrowser, callResidentRuntime, getResidentRuntimeLocalBrowserAutomationAccess, getResidentRuntimeLocalBrowserEndpoint, readOptionalManagedRuntimeBrowserCredential, } from "../control-client.js";
7
7
  import { fail } from "./errors.js";
8
8
  export async function runBrowserCommand(args) {
9
9
  let parsed;
@@ -18,9 +18,11 @@ export async function runBrowserCommand(args) {
18
18
  fail("browser install: choose either --version or --channel");
19
19
  }
20
20
  const channel = browserReleaseChannel(parsed.channel);
21
+ const { createBrowserArtifactManagementService } = await import("@rynx-ai/daemon/browser-artifacts");
22
+ const artifacts = createBrowserArtifactManagementService();
21
23
  const result = parsed.subcommand === "install"
22
- ? await installResidentBrowserArtifact(parsed.version ? { version: parsed.version } : { channel })
23
- : await updateResidentBrowserArtifact({ channel });
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) });
24
26
  if (parsed.json) {
25
27
  console.log(JSON.stringify({
26
28
  resolved: result.resolved,
@@ -35,7 +37,8 @@ export async function runBrowserCommand(args) {
35
37
  return 0;
36
38
  }
37
39
  if (parsed.subcommand === "version") {
38
- const { installed } = await getResidentBrowserArtifactVersion();
40
+ const { createBrowserArtifactManagementService } = await import("@rynx-ai/daemon/browser-artifacts");
41
+ const { installed } = createBrowserArtifactManagementService().version();
39
42
  if (parsed.json)
40
43
  console.log(JSON.stringify({ installed }, null, 2));
41
44
  else if (installed) {
@@ -47,7 +50,8 @@ export async function runBrowserCommand(args) {
47
50
  return 0;
48
51
  }
49
52
  if (parsed.subcommand === "clean") {
50
- const result = await cleanResidentBrowserArtifacts();
53
+ const { createBrowserArtifactManagementService } = await import("@rynx-ai/daemon/browser-artifacts");
54
+ const result = createBrowserArtifactManagementService().clean();
51
55
  if (parsed.json)
52
56
  console.log(JSON.stringify(result, null, 2));
53
57
  else if (result.removedBuilds.length === 0) {
@@ -5,5 +5,7 @@ export { runCleanupCommand } from "./cleanup.js";
5
5
  export { runEmulatorCommand } from "./emulator.js";
6
6
  export { CliUsageError } from "./errors.js";
7
7
  export { type PluginManageCommandOptions, runPluginCommand, runPluginManageCommand, } from "./plugin.js";
8
+ export { runMarketCommand } from "./market.js";
8
9
  export { runRuntimeCommand } from "./runtime.js";
9
- export { builtinSkillsDirectory, listBuiltinSkills, readBuiltinSkill, runSkillsCommand, } from "./skills.js";
10
+ export { runSessionCommand } from "./session.js";
11
+ export { builtinSkillGuidesDirectory, listBuiltinSkills, readBuiltinSkill, runSkillsCommand, } from "./skills.js";
@@ -5,5 +5,7 @@ export { runCleanupCommand } from "./cleanup.js";
5
5
  export { runEmulatorCommand } from "./emulator.js";
6
6
  export { CliUsageError } from "./errors.js";
7
7
  export { runPluginCommand, runPluginManageCommand, } from "./plugin.js";
8
+ export { runMarketCommand } from "./market.js";
8
9
  export { runRuntimeCommand } from "./runtime.js";
9
- export { builtinSkillsDirectory, listBuiltinSkills, readBuiltinSkill, runSkillsCommand, } from "./skills.js";
10
+ export { runSessionCommand } from "./session.js";
11
+ export { builtinSkillGuidesDirectory, listBuiltinSkills, readBuiltinSkill, runSkillsCommand, } from "./skills.js";
@@ -0,0 +1 @@
1
+ export declare function runLifecycleCommand(command: string, args: readonly string[]): Promise<number>;
@@ -0,0 +1,21 @@
1
+ import { startStandaloneDaemon, statusStandaloneDaemon, stopStandaloneDaemon, streamStandaloneDaemonLogs, } from "../standalone.js";
2
+ 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
+ return startStandaloneDaemon();
9
+ case "restart":
10
+ return startStandaloneDaemon({ restart: true });
11
+ case "stop":
12
+ return stopStandaloneDaemon();
13
+ case "status":
14
+ return statusStandaloneDaemon();
15
+ case "logs":
16
+ await streamStandaloneDaemonLogs();
17
+ return 0;
18
+ default:
19
+ fail(`unknown lifecycle command: ${command}`);
20
+ }
21
+ }
@@ -0,0 +1 @@
1
+ export declare function runMarketCommand(args: readonly string[]): Promise<number>;
@@ -0,0 +1,71 @@
1
+ import { addResidentPluginMarketplace, listResidentPluginMarketplaces, refreshResidentPluginMarketplace, removeResidentPluginMarketplace, } from "../control-client.js";
2
+ import { fail } from "./errors.js";
3
+ export async function runMarketCommand(args) {
4
+ const [command, target, ...rest] = args;
5
+ switch (command) {
6
+ case "list": {
7
+ rejectExtra(rest, "market list");
8
+ const markets = await listResidentPluginMarketplaces();
9
+ console.log("Markets");
10
+ if (markets.length === 0) {
11
+ console.log(" (none)");
12
+ return 0;
13
+ }
14
+ for (const market of markets) {
15
+ const source = market.builtIn ? "built-in" : market.source;
16
+ const revision = market.builtIn ? "bundled with Rynx" : market.resolvedRevision;
17
+ console.log(` ${market.id.padEnd(24)} ${source.padEnd(8)} ` +
18
+ `${String(market.plugins.length).padStart(3)} plugins ${revision}`);
19
+ }
20
+ return 0;
21
+ }
22
+ case "add": {
23
+ if (!target || target.startsWith("--"))
24
+ fail("market add: missing Git/local source");
25
+ let alias;
26
+ for (let index = 0; index < rest.length; index += 1) {
27
+ const arg = rest[index];
28
+ if (arg !== "--alias" || alias !== undefined)
29
+ fail(`market add: unexpected option ${arg}`);
30
+ const value = rest[index + 1];
31
+ if (!value || value.startsWith("--"))
32
+ fail("market add: --alias requires a value");
33
+ alias = value;
34
+ index += 1;
35
+ }
36
+ const market = await addResidentPluginMarketplace({
37
+ source: target,
38
+ ...(alias ? { alias } : {}),
39
+ });
40
+ console.log(`Market "${market.id}" added with ${market.plugins.length} plugin(s).`);
41
+ return 0;
42
+ }
43
+ case "refresh": {
44
+ rejectExtra(rest, "market refresh");
45
+ const ids = target
46
+ ? [target]
47
+ : (await listResidentPluginMarketplaces()).map((market) => market.id);
48
+ for (const id of ids) {
49
+ const market = await refreshResidentPluginMarketplace(id);
50
+ console.log(`Market "${market.id}" refreshed at ${market.resolvedRevision}.`);
51
+ }
52
+ if (ids.length === 0)
53
+ console.log("No Markets to refresh.");
54
+ return 0;
55
+ }
56
+ case "remove": {
57
+ if (!target)
58
+ fail("market remove: missing market id");
59
+ rejectExtra(rest, "market remove");
60
+ await removeResidentPluginMarketplace(target);
61
+ console.log(`Market "${target}" removed.`);
62
+ return 0;
63
+ }
64
+ default:
65
+ fail("market: expected list, add, refresh, or remove");
66
+ }
67
+ }
68
+ function rejectExtra(args, command) {
69
+ if (args.length > 0)
70
+ fail(`${command}: unexpected argument ${args[0]}`);
71
+ }
@@ -1,8 +1,9 @@
1
1
  import { createInterface } from "node:readline/promises";
2
- import { cancelResidentPluginInstallation, commitResidentPluginInstallation, invokeResidentPluginCommand, listResidentPlugins, prepareResidentPluginInstallation, reloadResidentPluginRuntime, setResidentPluginEnabled, uninstallResidentPlugin, } from "../control-client.js";
2
+ import { cancelResidentPluginInstallation, commitResidentPluginInstallation, invokeResidentPluginCommand, listResidentPlugins, prepareResidentPluginInstallation, setResidentPluginEnabled, uninstallResidentPlugin, } from "../control-client.js";
3
3
  import { fail } from "./errors.js";
4
4
  const PLUGIN_STDIN_MAX_BYTES = 256 * 1024;
5
5
  const PLUGIN_DIGEST_PATTERN = /^sha256-[A-Za-z0-9+/]{43}={0,2}$/;
6
+ 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
7
  export async function runPluginManageCommand(args, options = {}) {
7
8
  const [subcommand, pluginId] = args;
8
9
  switch (subcommand) {
@@ -22,16 +23,16 @@ export async function runPluginManageCommand(args, options = {}) {
22
23
  case "enable":
23
24
  case "disable": {
24
25
  if (!pluginId)
25
- fail(`plugin manage ${subcommand}: missing plugin id`);
26
+ fail(`plugin ${subcommand}: missing canonical plugin id`);
26
27
  await setResidentPluginEnabled(pluginId, subcommand === "enable");
27
- console.log(`Plugin "${pluginId}" ${subcommand}d. Run \`rynx restart\` to apply.`);
28
+ console.log(`Plugin "${pluginId}" ${subcommand}d.`);
28
29
  return 0;
29
30
  }
30
31
  case "uninstall": {
31
32
  if (!pluginId)
32
- fail("plugin manage uninstall: missing plugin id");
33
+ fail("plugin uninstall: missing canonical plugin id");
33
34
  await uninstallResidentPlugin(pluginId);
34
- console.log(`Plugin "${pluginId}" uninstalled. Run \`rynx restart\` to apply.`);
35
+ console.log(`Plugin "${pluginId}" uninstalled.`);
35
36
  return 0;
36
37
  }
37
38
  case "install":
@@ -40,9 +41,10 @@ export async function runPluginManageCommand(args, options = {}) {
40
41
  const preparation = await prepareResidentPluginInstallation({
41
42
  operation: subcommand,
42
43
  ...(subcommand === "install"
43
- ? { spec: parsed.target }
44
+ ? CANONICAL_PLUGIN_ID_PATTERN.test(parsed.target)
45
+ ? { marketplacePlugin: parsed.target }
46
+ : { spec: parsed.target }
44
47
  : { pluginId: parsed.target }),
45
- allowScripts: parsed.allowScripts,
46
48
  });
47
49
  let committed = false;
48
50
  try {
@@ -56,26 +58,24 @@ export async function runPluginManageCommand(args, options = {}) {
56
58
  fail(`prepared plugin digest ${preparation.artifact.digest} does not match ` +
57
59
  `--expect-digest ${parsed.expectedDigest}`);
58
60
  }
61
+ if (subcommand === "update" && preparation.unchanged) {
62
+ if (parsed.json) {
63
+ console.log(JSON.stringify({
64
+ preparation: publicPreparation(preparation),
65
+ unchanged: true,
66
+ }, null, 2));
67
+ }
68
+ else {
69
+ console.log(`Plugin "${preparation.artifact.id}" is already up to date.`);
70
+ }
71
+ return 0;
72
+ }
59
73
  if ((!interactive || parsed.json) &&
60
- (parsed.force || parsed.grantAll || parsed.allowScripts) &&
74
+ parsed.force &&
61
75
  parsed.expectedDigest === undefined) {
62
- fail("non-interactive --force/--grant-all/--allow-scripts approval must be bound to the " +
76
+ fail("non-interactive --force confirmation must be bound to the " +
63
77
  `prepared artifact; re-run with --expect-digest ${preparation.artifact.digest}`);
64
78
  }
65
- if (preparation.artifact.requiresBuildScripts && !parsed.allowScripts) {
66
- fail(`plugin "${preparation.artifact.id}" requires package build scripts; ` +
67
- `review digest ${preparation.artifact.digest} and re-run with ` +
68
- `--allow-scripts --expect-digest ${preparation.artifact.digest}`);
69
- }
70
- if (preparation.artifact.requiresBuildScripts &&
71
- parsed.allowScripts &&
72
- parsed.expectedDigest === undefined) {
73
- const approved = await confirm(`Run declared build scripts from digest ${preparation.artifact.digest}?`);
74
- if (!approved) {
75
- console.log("Plugin installation cancelled; build scripts were not run.");
76
- return 0;
77
- }
78
- }
79
79
  let overwrite = subcommand === "update";
80
80
  if (subcommand === "install" && preparation.existing) {
81
81
  overwrite = parsed.force;
@@ -92,49 +92,15 @@ export async function runPluginManageCommand(args, options = {}) {
92
92
  }
93
93
  }
94
94
  }
95
- let grants = [...preparation.capabilityDiff.retained];
96
- if (preparation.capabilityDiff.added.length > 0) {
97
- if (parsed.grantAll) {
98
- grants = [...preparation.artifact.requestedCapabilities];
99
- }
100
- else {
101
- if (!interactive || parsed.json) {
102
- fail(`plugin "${preparation.artifact.id}" requests new capabilities ` +
103
- `(${preparation.capabilityDiff.added.join(", ")}); inspect digest ` +
104
- `${preparation.artifact.digest} and re-run with ` +
105
- `--grant-all --expect-digest ${preparation.artifact.digest}`);
106
- }
107
- const approved = await confirm(`Grant ${preparation.capabilityDiff.added.length} new capability(s) ` +
108
- `to "${preparation.artifact.id}"?`);
109
- if (!approved) {
110
- console.log("Plugin installation cancelled; no changes were made.");
111
- return 0;
112
- }
113
- grants = [...preparation.artifact.requestedCapabilities];
114
- }
115
- }
116
95
  const result = await commitResidentPluginInstallation(preparation.token, {
117
- grants,
118
96
  overwrite,
119
97
  expectedDigest: preparation.artifact.digest,
120
98
  });
121
99
  committed = true;
122
- let runtimeReloaded = false;
123
- if (parsed.restart) {
124
- try {
125
- await reloadResidentPluginRuntime(result.plugin.id);
126
- runtimeReloaded = true;
127
- }
128
- catch (error) {
129
- throw new Error(`Plugin "${result.plugin.id}" was committed, but its runtime did not reload: ` +
130
- `${messageOf(error)}`, { cause: error });
131
- }
132
- }
133
100
  if (parsed.json) {
134
101
  console.log(JSON.stringify({
135
102
  preparation: publicPreparation(preparation),
136
103
  plugin: result.plugin,
137
- runtimeReloaded,
138
104
  }, null, 2));
139
105
  }
140
106
  else {
@@ -142,9 +108,7 @@ export async function runPluginManageCommand(args, options = {}) {
142
108
  console.log(`Plugin "${result.plugin.id}"${result.plugin.version
143
109
  ? ` @${result.plugin.version}`
144
110
  : ""} ${action}.`);
145
- console.log(parsed.restart
146
- ? `Plugin "${result.plugin.id}" runtime is ready.`
147
- : "Use --restart to reload the plugin runtime now.");
111
+ console.log(`Runtime state: ${result.plugin.runtimeState}.`);
148
112
  }
149
113
  return 0;
150
114
  }
@@ -155,15 +119,15 @@ export async function runPluginManageCommand(args, options = {}) {
155
119
  }
156
120
  }
157
121
  default:
158
- fail("plugin manage: expected list, install, update, uninstall, enable, or disable");
122
+ fail("plugin: expected list, install, update, uninstall, enable, or disable");
159
123
  }
160
124
  }
161
125
  export async function runPluginCommand(args) {
162
126
  const [pluginId, command] = args;
163
127
  if (!pluginId)
164
128
  fail("plugin: missing plugin id");
165
- if (pluginId === "manage") {
166
- return runPluginManageCommand(args.slice(1));
129
+ if (["list", "install", "update", "uninstall", "enable", "disable"].includes(pluginId)) {
130
+ return runPluginManageCommand(args);
167
131
  }
168
132
  if (!command)
169
133
  fail(`plugin ${pluginId}: missing command`);
@@ -184,15 +148,12 @@ function parseInstallationArgs(operation, args) {
184
148
  const target = args[0];
185
149
  if (!target || target.startsWith("--")) {
186
150
  fail(operation === "install"
187
- ? "plugin manage install: missing npm/path/git/url source"
188
- : "plugin manage update: missing plugin id");
151
+ ? "plugin install: missing Git/local source or market plugin identity"
152
+ : "plugin update: missing canonical plugin id");
189
153
  }
190
154
  const flags = new Set();
191
155
  const allowedFlags = new Set([
192
156
  "--force",
193
- "--grant-all",
194
- "--allow-scripts",
195
- "--restart",
196
157
  "--json",
197
158
  ]);
198
159
  let expectedDigest;
@@ -200,36 +161,33 @@ function parseInstallationArgs(operation, args) {
200
161
  const arg = args[index];
201
162
  if (arg === "--expect-digest" || arg === "--expected-digest") {
202
163
  if (expectedDigest !== undefined) {
203
- fail(`plugin manage ${operation}: duplicate digest expectation`);
164
+ fail(`plugin ${operation}: duplicate digest expectation`);
204
165
  }
205
166
  const value = args[index + 1];
206
167
  if (!value || value.startsWith("--")) {
207
- fail(`plugin manage ${operation}: ${arg} requires a value`);
168
+ fail(`plugin ${operation}: ${arg} requires a value`);
208
169
  }
209
170
  if (!PLUGIN_DIGEST_PATTERN.test(value)) {
210
- fail(`plugin manage ${operation}: ${arg} must be a sha256 digest`);
171
+ fail(`plugin ${operation}: ${arg} must be a sha256 digest`);
211
172
  }
212
173
  expectedDigest = value;
213
174
  index += 1;
214
175
  continue;
215
176
  }
216
177
  if (!arg.startsWith("--")) {
217
- fail(`plugin manage ${operation}: unexpected argument ${arg}`);
178
+ fail(`plugin ${operation}: unexpected argument ${arg}`);
218
179
  }
219
180
  if (!allowedFlags.has(arg)) {
220
- fail(`plugin manage ${operation}: unknown option ${arg}`);
181
+ fail(`plugin ${operation}: unknown option ${arg}`);
221
182
  }
222
183
  if (flags.has(arg)) {
223
- fail(`plugin manage ${operation}: duplicate option ${arg}`);
184
+ fail(`plugin ${operation}: duplicate option ${arg}`);
224
185
  }
225
186
  flags.add(arg);
226
187
  }
227
188
  return {
228
189
  target,
229
190
  force: flags.has("--force"),
230
- grantAll: flags.has("--grant-all"),
231
- allowScripts: flags.has("--allow-scripts"),
232
- restart: flags.has("--restart"),
233
191
  json: flags.has("--json"),
234
192
  ...(expectedDigest ? { expectedDigest } : {}),
235
193
  };
@@ -240,19 +198,8 @@ function printPreparation(preparation) {
240
198
  : "";
241
199
  console.log(`Prepared plugin "${preparation.artifact.id}"${version}.`);
242
200
  console.log(`Artifact digest: ${preparation.artifact.digest}`);
243
- if (preparation.artifact.requiresBuildScripts) {
244
- console.log("Package build scripts: required and explicitly enabled.");
245
- }
246
- printCapabilities("New capabilities", preparation.capabilityDiff.added);
247
- printCapabilities("Retained capabilities", preparation.capabilityDiff.retained);
248
- printCapabilities("Removed capabilities", preparation.capabilityDiff.removed);
249
- }
250
- function printCapabilities(label, capabilities) {
251
- if (capabilities.length === 0)
252
- return;
253
- console.log(`${label}:`);
254
- for (const capability of capabilities)
255
- console.log(` - ${capability}`);
201
+ console.log(`Source: ${preparation.artifact.source}`);
202
+ console.log(`Runtime: ${preparation.artifact.hasRuntime ? "declared" : "none"}`);
256
203
  }
257
204
  function publicPreparation(preparation) {
258
205
  const { token: _token, ...publicFields } = preparation;
@@ -272,9 +219,6 @@ async function confirmInTerminal(message) {
272
219
  prompt.close();
273
220
  }
274
221
  }
275
- function messageOf(error) {
276
- return error instanceof Error ? error.message : String(error);
277
- }
278
222
  async function readStdinBounded(maxBytes) {
279
223
  const chunks = [];
280
224
  let bytes = 0;
@@ -0,0 +1 @@
1
+ export declare function runSessionCommand(args: readonly string[]): Promise<number>;
@@ -0,0 +1,38 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { callResidentRuntime } from "../control-client.js";
3
+ import { fail } from "./errors.js";
4
+ export async function runSessionCommand(args) {
5
+ const [command, sourceSessionId, ...options] = args;
6
+ if (command !== "fork" || !sourceSessionId) {
7
+ fail("Usage: rynx session fork <session-id> [--title <title>] [--json]");
8
+ }
9
+ let title;
10
+ let json = false;
11
+ for (let index = 0; index < options.length; index += 1) {
12
+ const option = options[index];
13
+ if (option === "--json") {
14
+ if (json)
15
+ fail("session fork: duplicate option --json");
16
+ json = true;
17
+ continue;
18
+ }
19
+ if (option === "--title") {
20
+ if (title !== undefined)
21
+ fail("session fork: duplicate option --title");
22
+ title = options[++index];
23
+ if (!title?.trim())
24
+ fail("session fork: --title requires a value");
25
+ continue;
26
+ }
27
+ fail(`session fork: unknown option ${option}`);
28
+ }
29
+ const result = await callResidentRuntime("local", "session.fork", {
30
+ sourceSessionId,
31
+ operationId: `cli_${randomUUID()}`,
32
+ ...(title ? { title: title.trim() } : {}),
33
+ });
34
+ console.log(json
35
+ ? JSON.stringify(result)
36
+ : result.sessionId);
37
+ return 0;
38
+ }
@@ -0,0 +1,2 @@
1
+ export declare function runSetupCommand(args: readonly string[]): Promise<number>;
2
+ export declare function runDoctorCommand(args: readonly string[]): Promise<number>;