@phreshos/cli 0.1.48 → 0.1.50

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/README.md CHANGED
@@ -1,11 +1,21 @@
1
1
  # `@phreshos/cli`
2
2
 
3
- The `phresh` command for creating and operating Programs and managing the
4
- PhreshOS System on the current machine.
3
+ The `phresh` command for Program projects, runtime operations, and PhreshOS
4
+ System management.
5
5
 
6
- The CLI uses the same public System interface as the Node and Server SDKs. It
7
- adds command parsing, terminal presentation, project workflows, packaging, and
8
- native service management.
6
+ [Documentation](https://docs.phreshos.com/sdks/cli) ·
7
+ [Installation](https://docs.phreshos.com/installation) ·
8
+ [Source](https://github.com/PhreshOS/cli)
9
+
10
+ ## Role
11
+
12
+ The CLI presents public Project and System operations as human-facing commands.
13
+ It owns command parsing, terminal output, packaging presentation, System release
14
+ acquisition, and native service management.
15
+
16
+ The CLI owns its command contract. Runtime command executors use
17
+ `@phreshos/node` and its shared System domain handles; the CLI does not define a
18
+ second System interface or transport request language.
9
19
 
10
20
  ## Installation
11
21
 
@@ -18,61 +28,18 @@ native service management.
18
28
 
19
29
  Node.js 20.10 or newer is required.
20
30
 
21
- ## Program projects
22
-
23
31
  ```sh
24
32
  phresh create
25
- phresh init
26
33
  phresh dev
27
- phresh start
28
34
  phresh install
29
- phresh uninstall
30
- phresh pack
31
- ```
32
-
33
- `create` produces the official starter Program. The remaining commands operate
34
- on the current Program project through the Node Project contract and present
35
- its build, development, installation, and runtime lifecycles.
36
-
37
- ## System
38
-
39
- ```sh
40
- phresh system install
41
35
  phresh system status
42
- phresh system start
43
- phresh system stop
44
- phresh system enable
45
- phresh system disable
46
- phresh system uninstall
47
- ```
48
-
49
- System installation acquires and verifies the official release archive and
50
- configures the native per-user service. Starting and stopping control current
51
- execution; enabling and disabling control automatic startup.
52
-
53
- ## Runtime
54
-
55
- ```sh
56
36
  phresh program list
57
- phresh process list --program my-program
58
- phresh endpoint inspect \
59
- --program my-program \
60
- --process main \
61
- --endpoint server
62
- phresh window inspect --program my-program --process main
63
- ```
64
-
65
- The command hierarchy follows the runtime ownership hierarchy. Unknown
66
- commands, flags, and malformed values reject rather than being guessed.
67
-
68
- ```sh
69
- phresh describe
70
- phresh describe program
71
- phresh describe process list
72
37
  ```
73
38
 
74
- `describe` exposes the command tree and exact options as machine-readable
75
- contracts.
39
+ Use `phresh describe` to inspect a command, or `phresh describe --all --json`
40
+ to read the complete machine-discoverable contract. See the
41
+ [CLI documentation](https://docs.phreshos.com/sdks/cli) for Program project,
42
+ System, and runtime commands.
76
43
 
77
44
  ## Development
78
45
 
@@ -84,15 +51,20 @@ bun run verify
84
51
  `verify` checks the scripts, builds the CLI and bundled starter, runs the
85
52
  command tests, and validates the package artifact.
86
53
 
87
- See the [CLI documentation](https://github.com/PhreshOS/docs/blob/main/content/docs/sdks/cli.mdx)
88
- for the command model.
54
+ ## Related repositories
89
55
 
90
- ## Repository boundary
56
+ - [`@phreshos/node`](https://github.com/PhreshOS/node) owns the Project and
57
+ external System APIs composed by the CLI.
58
+ - [`@phreshos/core`](https://github.com/PhreshOS/core) owns the shared System
59
+ domain contracts used by the Node SDK.
60
+ - [PhreshOS System](https://github.com/PhreshOS/system) provides the managed
61
+ runtime and official release artifact.
62
+ - [Phresh Program](https://github.com/PhreshOS/phresh-program) is the starter
63
+ bundled by `phresh create`.
64
+ - [PhreshOS Install](https://github.com/PhreshOS/install) bootstraps this CLI on
65
+ clean machines.
91
66
 
92
- This repository owns terminal interaction, command routing, System acquisition,
93
- and host service integration. Node owns the external JavaScript interface and
94
- Project workflows, Core owns shared contracts, and the System owns authoritative
95
- state.
67
+ ## Contributing
96
68
 
97
69
  See [CONTRIBUTING.md](CONTRIBUTING.md) for the repository workflow and
98
70
  [SECURITY.md](SECURITY.md) for private vulnerability reporting.
package/dist/cli.js CHANGED
@@ -1,138 +1,42 @@
1
1
  #!/usr/bin/env node
2
- import { Command, Option } from "commander";
2
+ import { Command } from "commander";
3
3
  import { createRequire } from "node:module";
4
+ import accessCommands from "./commands/access.js";
5
+ import describeCommands from "./commands/describe.js";
6
+ import projectCommands from "./commands/project.js";
7
+ import { assertCommandContracts, attachCommandContract } from "./contract/command.js";
4
8
  import { PromptCancelled, ReportedFailure } from "./prompts.js";
5
- import create from "./create.js";
6
- import install from "./install.js";
7
- import launch from "./launch.js";
8
- import init from "./init.js";
9
- import pack from "./pack.js";
10
- import uninstall from "./uninstall.js";
11
- import systemCommands from "./system/command.js";
12
- import controlCommands from "./control/command.js";
13
- import describeCommands from "./describe-command.js";
14
- import { commandContract } from "./command-contract.js";
15
9
  import { blank, failure } from "./style.js";
10
+ import systemCommands from "./system/command.js";
16
11
  const metadata = createRequire(import.meta.url)("../package.json");
17
- const { version } = metadata;
18
- const coreRange = metadata.dependencies["@phreshos/core"];
19
- const runOptionPrefix = "--run-option-";
20
12
  const program = new Command()
21
13
  .name("phresh")
22
- .description("Create Programs and manage PhreshOS")
23
- .version(version, "-v, --version")
14
+ .version(metadata.version, "-v, --version")
24
15
  .showHelpAfterError()
25
16
  .showSuggestionAfterError()
26
17
  .configureOutput({
27
18
  writeOut: value => process.stdout.write(spaced(value)),
28
19
  writeErr: value => process.stderr.write(spaced(value))
29
20
  });
30
- commandContract(program);
31
- program.addHelpText("after", "\nRun phresh <command> --help for detailed command guidance.\n");
32
- describe(program.command("create")
33
- .description("create a new Program project")
34
- .argument("[directory]", "directory for the new Program")
35
- .option("--name <name>", "human-readable Program name")
36
- .addOption(new Option("--package-manager <manager>", "package manager used to install dependencies").choices(["bun", "npm", "pnpm", "yarn"]))
37
- .option("--no-install", "create files without installing dependencies")
38
- .action(async function (directory, options) {
39
- await create({
40
- directory,
41
- name: options.name,
42
- packageManager: options.packageManager,
43
- install: options.install
44
- });
45
- }), [
46
- "Creates a complete Server and Client project from the maintained",
47
- "Phresh Program template bundled with this CLI.",
48
- "",
49
- "In a terminal, omitted values are collected interactively. Automation",
50
- "supplies the directory and optional choices through named options."
51
- ]);
52
- describe(program.command("init")
53
- .description("initialize an existing Program project")
54
- .option("--name <name>", "human-readable Program name")
55
- .option("--build-command <command>", "prepare production files before use")
56
- .option("--server", "include a Server endpoint")
57
- .option("--server-location <path>", "production Server directory")
58
- .option("--server-start-command <command>", "production Server command")
59
- .option("--server-entry-file <path>", "production Server worker entry")
60
- .option("--server-development-start-command <command>", "development Server command")
61
- .option("--server-development-entry-file <path>", "development Server worker entry")
62
- .option("--client", "include a Client endpoint")
63
- .option("--client-location <path>", "production Client directory")
64
- .option("--client-development-url <url>", "fixed or external development Client URL")
65
- .option("--client-development-start-command <command>", "development Client command")
66
- .option("--force", "replace an existing phresh.config.ts")
67
- .action(async function (options) {
68
- await init({
69
- name: options.name,
70
- buildCommand: options.buildCommand,
71
- server: options.server === true || options.serverLocation !== undefined || options.serverStartCommand !== undefined || options.serverEntryFile !== undefined,
72
- serverLocation: options.serverLocation,
73
- serverStartCommand: options.serverStartCommand,
74
- serverEntryFile: options.serverEntryFile,
75
- serverDevelopmentStartCommand: options.serverDevelopmentStartCommand,
76
- serverDevelopmentEntryFile: options.serverDevelopmentEntryFile,
77
- client: options.client === true
78
- || options.clientLocation !== undefined
79
- || options.clientDevelopmentUrl !== undefined
80
- || options.clientDevelopmentStartCommand !== undefined,
81
- clientLocation: options.clientLocation,
82
- clientDevelopmentUrl: options.clientDevelopmentUrl,
83
- clientDevelopmentStartCommand: options.clientDevelopmentStartCommand,
84
- force: options.force === true
85
- }, process.cwd(), coreRange);
86
- }), [
87
- "Reads identity, version, and description from package.json, then writes",
88
- "phresh.config.ts. A terminal asks only for values the project cannot",
89
- "provide. Without a terminal, declare at least one endpoint with options."
90
- ]);
91
- describe(program.command("pack")
92
- .description("build and package this Program")
93
- .action(async function () {
94
- await pack();
95
- }), [
96
- "Runs an optional buildCommand, then packages the production files",
97
- "declared for each endpoint."
98
- ]);
99
- describe(program.command("install")
100
- .description("install a local or official Program")
101
- .argument("[name]", "name of an official Program")
102
- .option("--run", "run the installed Program now")
103
- .action(async function (name, options) {
104
- await install({ name, run: options.run === true });
105
- }), [
106
- "Without a name, builds and installs the Program declared by this project.",
107
- "A name installs its verified official production release. --run launches",
108
- "the installed Program now."
109
- ]);
110
- describe(program.command("uninstall")
111
- .description("uninstall a local or installed Program")
112
- .argument("[name]", "name of an installed Program")
113
- .option("--everything", "also remove Processes, data, and runtime state")
114
- .action(async function (name, options) {
115
- await uninstall({ name, everything: options.everything === true });
116
- }), [
117
- "Without a name, uses the Program declared by this project. Removes its",
118
- "installed files while preserving its Processes, data,",
119
- "and runtime Program. --everything removes all system-owned state."
120
- ]);
121
- attached("start", "run the production Program without installing", [
122
- "Runs this Program attached to the terminal. Output arrives here, and",
123
- "ending this command stops the Program. An optional buildCommand runs",
124
- "before launch, and the Program's exit status becomes this command's status."
125
- ], "production");
126
- attached("dev", "run the development Program without installing", [
127
- "Runs the same attached lifecycle as start using the development",
128
- "declarations. A Client URL must respond within 15 seconds before launch."
129
- ], "development");
21
+ attachCommandContract(program, {
22
+ name: "phresh",
23
+ description: "create Programs and manage PhreshOS",
24
+ options: [{ flags: "-v, --version", description: "display the CLI version" }],
25
+ guidance: ["Run phresh <command> --help for human guidance, or phresh describe for the machine-readable command contract."],
26
+ examples: ["phresh create", "phresh describe --all --json"]
27
+ });
28
+ const coreRange = metadata.dependencies["@phreshos/core"];
29
+ if (!coreRange)
30
+ throw new Error("The CLI package does not declare @phreshos/core");
31
+ projectCommands(program, coreRange);
130
32
  systemCommands(program);
131
- controlCommands(program);
33
+ accessCommands(program);
132
34
  describeCommands(program);
35
+ assertCommandContracts(program);
133
36
  // Every command begins with the same breathing room. Keep this at the entry
134
- // point so individual commands never need to manufacture their own opening.
135
- blank();
37
+ // point so individual commands never manufacture their own opening.
38
+ if (!process.argv.includes("--json"))
39
+ blank();
136
40
  if (process.argv.length === 2)
137
41
  program.help();
138
42
  try {
@@ -153,33 +57,3 @@ function spaced(value) {
153
57
  return value;
154
58
  return value.endsWith("\n") ? `${value}\n` : `${value}\n\n`;
155
59
  }
156
- function attached(name, summary, detail, mode) {
157
- describe(program.command(name)
158
- .description(summary)
159
- .argument("[run-options...]", "--run-option-<name>=<value> values passed to the Program")
160
- .allowUnknownOption()
161
- .action(async function (args) {
162
- await launch(mode, process.cwd(), runOptions(name, args));
163
- }), detail);
164
- }
165
- function describe(command, paragraphs) {
166
- command.addHelpText("after", `\n${paragraphs.map(line => line ? ` ${line}` : "").join("\n")}\n`);
167
- commandContract(command, { guidance: paragraphs.filter(Boolean) });
168
- return command;
169
- }
170
- function runOptions(command, args) {
171
- const options = {};
172
- for (const argument of args) {
173
- if (!argument.startsWith(runOptionPrefix))
174
- throw new Error(`${command} accepts Program options only as ${runOptionPrefix}<name>=<value>; received "${argument}"`);
175
- const said = argument.slice(runOptionPrefix.length);
176
- const at = said.indexOf("=");
177
- if (at < 1)
178
- throw new Error(`"${argument}" says no value — write ${runOptionPrefix}<name>=<value>, and end with = for an empty value`);
179
- const name = said.slice(0, at);
180
- if (Object.hasOwn(options, name))
181
- throw new Error(`The run option "${name}" was given more than once`);
182
- options[name] = said.slice(at + 1);
183
- }
184
- return options;
185
- }
@@ -1,10 +1,10 @@
1
1
  import endpointCommands from "./endpoint.js";
2
2
  import processCommands from "./process.js";
3
3
  import programCommands from "./program.js";
4
- import { connectSystem } from "./shared.js";
4
+ import { connectSystem } from "./connection.js";
5
5
  import windowCommands from "./window.js";
6
- /** Expose the shared System handles as explicit CLI commands. */
7
- export default function controlCommands(program, connect = connectSystem) {
6
+ /** Expose the shared System domains through explicit Node SDK executors. */
7
+ export default function accessCommands(program, connect = connectSystem) {
8
8
  programCommands(program, connect);
9
9
  processCommands(program, connect);
10
10
  endpointCommands(program, connect);
@@ -0,0 +1,26 @@
1
+ import { System } from "@phreshos/node";
2
+ export const connectSystem = () => System.connect();
3
+ /** Give one command exclusive ownership of one Node SDK System connection. */
4
+ export async function connected(connect, action) {
5
+ const system = await connect();
6
+ try {
7
+ return await action(system);
8
+ }
9
+ finally {
10
+ await system.disconnect();
11
+ }
12
+ }
13
+ export async function requireProgram(system, identity) {
14
+ const program = await system.program.find(identity);
15
+ if (!program)
16
+ throw new Error(`Unknown Program "${identity}"`);
17
+ return program;
18
+ }
19
+ export async function requireProcess(system, identity, programIdentity) {
20
+ const process = programIdentity
21
+ ? await (await requireProgram(system, programIdentity)).process.find(identity)
22
+ : await system.process.find(identity);
23
+ if (!process)
24
+ throw new Error(`Unknown Process "${identity}"`);
25
+ return process;
26
+ }
@@ -0,0 +1,75 @@
1
+ import { defineCommand, readCommandContract } from "../contract/command.js";
2
+ import { value } from "../contract/schema.js";
3
+ import { jsonOption, option } from "./options.js";
4
+ import { jsonOutput } from "./schemas.js";
5
+ /** Expose the authoritative CLI contract without contacting the System. */
6
+ export default function describeCommands(root) {
7
+ defineCommand(root, {
8
+ name: "describe",
9
+ description: "describe Phresh commands as machine-readable data",
10
+ arguments: [{ syntax: "[path...]", description: "command path to describe" }],
11
+ options: [
12
+ option("--all", "include every descendant beneath the selected path"),
13
+ jsonOption
14
+ ],
15
+ guidance: ["Omit the path to start at the CLI root. Add --all to retrieve the complete selected contract tree."],
16
+ examples: ["phresh describe", "phresh describe process create", "phresh describe --all --json"],
17
+ output: jsonOutput(value.any("one command contract or a complete contract tree"), "CLI command contract")
18
+ }, ({ arguments: [path], options }) => {
19
+ const command = resolveCommand(root, path);
20
+ return options.all ? describeTree(command, path) : describe(command, path);
21
+ });
22
+ }
23
+ function resolveCommand(root, path) {
24
+ let command = root;
25
+ for (const name of path) {
26
+ const child = command.commands.find(candidate => {
27
+ const contract = readCommandContract(candidate);
28
+ return candidate.name() === name || contract?.aliases?.includes(name);
29
+ });
30
+ if (!child)
31
+ throw new Error(`Unknown command path "${path.join(" ")}"`);
32
+ command = child;
33
+ }
34
+ return command;
35
+ }
36
+ function describeTree(command, path) {
37
+ return {
38
+ ...describe(command, path),
39
+ commands: command.commands.map(child => describeTree(child, [...path, child.name()]))
40
+ };
41
+ }
42
+ function describe(command, path) {
43
+ const contract = readCommandContract(command);
44
+ if (!contract)
45
+ throw new Error(`Command "${path.join(" ") || command.name()}" has no CLI contract`);
46
+ return {
47
+ path,
48
+ name: contract.name,
49
+ aliases: contract.aliases ?? [],
50
+ description: contract.description,
51
+ arguments: contract.arguments ?? [],
52
+ options: (contract.options ?? []).map(publicOption),
53
+ guidance: contract.guidance ?? [],
54
+ examples: contract.examples ?? [],
55
+ requiresSystem: contract.requiresSystem === true,
56
+ output: contract.output ?? null,
57
+ commands: command.commands.map(child => {
58
+ const childContract = readCommandContract(child);
59
+ if (!childContract)
60
+ throw new Error(`Command "${[...path, child.name()].join(" ")}" has no CLI contract`);
61
+ return { name: childContract.name, aliases: childContract.aliases ?? [], description: childContract.description };
62
+ })
63
+ };
64
+ }
65
+ function publicOption(option) {
66
+ return {
67
+ flags: option.flags,
68
+ description: option.description,
69
+ mandatory: option.mandatory === true,
70
+ value: option.flags.includes("<") ? "required" : option.flags.includes("[") ? "optional" : "none",
71
+ repeatable: option.repeatable === true,
72
+ choices: option.choices ?? [],
73
+ ...(Object.hasOwn(option, "default") ? { default: option.default } : {})
74
+ };
75
+ }
@@ -0,0 +1,134 @@
1
+ import { defineCommand } from "../contract/command.js";
2
+ import { value } from "../contract/schema.js";
3
+ import { clientOverrideOptions, endpointOptions, option, serverOverrideOptions, timeoutOption, withJson } from "./options.js";
4
+ import { endpointOutput, eventOutput, jsonOutput } from "./schemas.js";
5
+ import { connected, requireProcess } from "./connection.js";
6
+ import { bounded, clientLaunch, payload, serverLaunch } from "./input.js";
7
+ import { wait } from "./observation.js";
8
+ import { endpoint, endpointView } from "./projection.js";
9
+ export default function endpointCommands(root, connect) {
10
+ const endpoints = defineCommand(root, {
11
+ name: "endpoint",
12
+ description: "inspect, control, and communicate with Process Endpoints",
13
+ guidance: ["Select the exact Process and either its server or client Endpoint."]
14
+ });
15
+ defineCommand(endpoints, {
16
+ name: "inspect",
17
+ description: "read whether one Endpoint is declared and running",
18
+ requiresSystem: true,
19
+ options: withJson(...endpointOptions),
20
+ output: jsonOutput(endpointOutput, "The selected Endpoint"),
21
+ examples: ["phresh endpoint inspect --process main --program terminal --endpoint server"]
22
+ }, async ({ options }) => withEndpoint(connect, options, async (process, name) => {
23
+ return await endpointView(process, name);
24
+ }));
25
+ defineCommand(endpoints, {
26
+ name: "start",
27
+ description: "start a fresh Endpoint incarnation",
28
+ requiresSystem: true,
29
+ options: withJson(...endpointOptions, ...clientOverrideOptions, ...serverOverrideOptions),
30
+ output: jsonOutput(endpointOutput, "The started Endpoint"),
31
+ examples: ["phresh endpoint start --process main --program terminal --endpoint server --server-service"]
32
+ }, async ({ options }) => withEndpoint(connect, options, async (process, name) => {
33
+ const client = clientLaunch(options);
34
+ const server = serverLaunch(options);
35
+ if (name === "server" && client !== undefined)
36
+ throw new Error("Client overrides require --endpoint client");
37
+ if (name === "client" && server !== undefined)
38
+ throw new Error("Server overrides require --endpoint server");
39
+ if (name === "client")
40
+ await process.client.start(typeof client === "object" ? client : undefined);
41
+ else
42
+ await process.server.start(typeof server === "object" ? server : undefined);
43
+ return await endpointView(process, name);
44
+ }));
45
+ defineCommand(endpoints, {
46
+ name: "stop",
47
+ description: "stop one Endpoint",
48
+ requiresSystem: true,
49
+ options: withJson(...endpointOptions),
50
+ output: jsonOutput(endpointOutput, "The stopped Endpoint"),
51
+ examples: ["phresh endpoint stop --process main --program terminal --endpoint client"]
52
+ }, async ({ options }) => withEndpoint(connect, options, async (process, name) => {
53
+ await endpoint(process, name).stop();
54
+ return await endpointView(process, name);
55
+ }));
56
+ defineCommand(endpoints, {
57
+ name: "waitReady",
58
+ aliases: ["wait-ready"],
59
+ description: "wait until the Server Endpoint reports readiness",
60
+ requiresSystem: true,
61
+ options: withJson(...endpointOptions, timeoutOption),
62
+ output: jsonOutput(endpointOutput, "The ready Server Endpoint"),
63
+ examples: ["phresh endpoint wait-ready --process main --program terminal --endpoint server --timeout 30000"]
64
+ }, async ({ options }) => withEndpoint(connect, options, async (process, name) => {
65
+ if (name !== "server")
66
+ throw new Error("waitReady requires --endpoint server");
67
+ await process.server.waitReady(timeout(options.timeout));
68
+ return await endpointView(process, "server");
69
+ }));
70
+ defineCommand(endpoints, {
71
+ name: "waitLifecycle",
72
+ aliases: ["wait-lifecycle"],
73
+ description: "wait for one lifecycle transition of an exact Endpoint",
74
+ requiresSystem: true,
75
+ options: withJson(...endpointOptions, option("--event <event>", "Endpoint lifecycle event", { mandatory: true, choices: ["start", "stop"] }), timeoutOption),
76
+ output: jsonOutput(value.object({
77
+ scope: value.string("Endpoint lifecycle subscription scope"),
78
+ event: value.enumeration(["start", "stop"], "observed lifecycle event")
79
+ }, ["scope", "event"], "Endpoint lifecycle event"), "One Endpoint lifecycle event"),
80
+ examples: ["phresh endpoint wait-lifecycle --process main --program terminal --endpoint server --event start"]
81
+ }, async ({ options }) => withEndpoint(connect, options, async (process, name) => {
82
+ await wait(endpoint(process, name).lifecycle, options.event, timeout(options.timeout));
83
+ return { scope: `endpoint:${process.identity}:${name}:lifecycle`, event: options.event };
84
+ }));
85
+ defineCommand(endpoints, {
86
+ name: "ask",
87
+ description: "ask a Server event and return its answer",
88
+ requiresSystem: true,
89
+ options: withJson(...endpointOptions, option("--event <event>", "event name", { mandatory: true }), option("--payload <json>", "arbitrary event payload as JSON"), timeoutOption),
90
+ output: jsonOutput(value.any("answer returned by the Server event contract"), "The Server answer"),
91
+ examples: ["phresh endpoint ask --process main --program terminal --endpoint server --event status --json"]
92
+ }, async ({ options }) => withEndpoint(connect, options, async (process, name) => {
93
+ if (name !== "server")
94
+ throw new Error("ask requires --endpoint server");
95
+ const input = payload(options.payload);
96
+ const answer = options.timeout === undefined
97
+ ? await process.server.ask(options.event, input)
98
+ : await process.server.timeout(timeout(options.timeout)).ask(options.event, input);
99
+ return answer;
100
+ }));
101
+ defineCommand(endpoints, {
102
+ name: "publish",
103
+ description: "publish one event without waiting for an answer",
104
+ requiresSystem: true,
105
+ options: withJson(...endpointOptions, option("--event <event>", "event name", { mandatory: true }), option("--payload <json>", "arbitrary event payload as JSON")),
106
+ output: jsonOutput(endpointOutput, "The Endpoint after publishing"),
107
+ examples: ["phresh endpoint publish --process main --program terminal --endpoint client --event changed --payload '{\"value\":1}'"]
108
+ }, async ({ options }) => withEndpoint(connect, options, async (process, name) => {
109
+ endpoint(process, name).publish(options.event, payload(options.payload));
110
+ return await endpointView(process, name);
111
+ }));
112
+ defineCommand(endpoints, {
113
+ name: "wait",
114
+ description: "wait for the next event emitted by one live Endpoint",
115
+ requiresSystem: true,
116
+ options: withJson(...endpointOptions, option("--event <event>", "event name", { mandatory: true }), timeoutOption),
117
+ output: jsonOutput(eventOutput("The observed Endpoint event"), "One Endpoint event"),
118
+ examples: ["phresh endpoint wait --process main --program terminal --endpoint client --event changed --json"]
119
+ }, async ({ options }) => withEndpoint(connect, options, async (process, name) => {
120
+ return {
121
+ scope: `endpoint:${process.identity}:${name}`,
122
+ event: options.event,
123
+ payload: await wait(endpoint(process, name), options.event, timeout(options.timeout))
124
+ };
125
+ }));
126
+ }
127
+ async function withEndpoint(connect, options, action) {
128
+ return await connected(connect, async (system) => {
129
+ return await action(await requireProcess(system, options.process, options.program), options.endpoint);
130
+ });
131
+ }
132
+ function timeout(value) {
133
+ return value === undefined ? undefined : bounded(value, "--timeout", 1);
134
+ }
@@ -1,89 +1,3 @@
1
- import { System } from "@phreshos/node";
2
- import { blank } from "../style.js";
3
- export const connectSystem = () => System.connect();
4
- export async function connected(connect, action) {
5
- const system = await connect();
6
- try {
7
- return await action(system);
8
- }
9
- finally {
10
- await system.disconnect();
11
- }
12
- }
13
- export async function requireProgram(system, identity) {
14
- const program = await system.program.find(identity);
15
- if (!program)
16
- throw new Error(`Unknown Program "${identity}"`);
17
- return program;
18
- }
19
- export async function requireProcess(system, identity, programIdentity) {
20
- const process = programIdentity
21
- ? await (await requireProgram(system, programIdentity)).process.find(identity)
22
- : await system.process.find(identity);
23
- if (!process)
24
- throw new Error(`Unknown Process "${identity}"`);
25
- return process;
26
- }
27
- export function endpoint(process, name) {
28
- return name === "server" ? process.server : process.client;
29
- }
30
- export async function programView(program) {
31
- return {
32
- identity: program.identity,
33
- assetId: program.assetId,
34
- name: program.name,
35
- version: program.version,
36
- description: program.description,
37
- installed: await program.installed(),
38
- hasAgent: program.hasAgent,
39
- server: program.server,
40
- client: program.client
41
- };
42
- }
43
- export async function processView(process) {
44
- const [server, client, serverService, clientService] = await Promise.all([
45
- process.server.exists(),
46
- process.client.exists(),
47
- process.server.isService(),
48
- process.client.isService()
49
- ]);
50
- return {
51
- identity: process.identity,
52
- name: process.name,
53
- program: process.program().identity,
54
- startedAt: process.startedAt.toISOString(),
55
- server: { declared: process.program().server !== null, running: server, service: serverService },
56
- client: { declared: process.program().client !== null, running: client, service: clientService }
57
- };
58
- }
59
- export async function endpointView(process, name) {
60
- const program = process.program();
61
- return {
62
- process: process.identity,
63
- program: program.identity,
64
- endpoint: name,
65
- declared: name === "server" ? program.server !== null : program.client !== null,
66
- running: await endpoint(process, name).exists(),
67
- service: await endpoint(process, name).isService()
68
- };
69
- }
70
- export async function windowView(process) {
71
- const window = process.client.window;
72
- const [title, position, size, minimized, front, layer, location] = await Promise.all([
73
- window.title(),
74
- window.position(),
75
- window.size(),
76
- window.minimized(),
77
- window.front(),
78
- window.layer(),
79
- window.location()
80
- ]);
81
- return { process: process.identity, title, position, size, minimized, front, layer, location };
82
- }
83
- export function output(value, compact) {
84
- console.log(JSON.stringify(value ?? null, null, compact ? undefined : 2));
85
- blank();
86
- }
87
1
  export function payload(value) {
88
2
  if (value === undefined)
89
3
  return undefined;
@@ -194,9 +108,3 @@ function entries(values = []) {
194
108
  }
195
109
  return result;
196
110
  }
197
- export async function wait(target, event, timeout) {
198
- return target.waitFor(event, timeout);
199
- }
200
- export function windowOf(process) {
201
- return process.client.window;
202
- }