@phreshos/cli 0.1.48 → 0.1.49

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,4 @@
1
+ /** Wait for one named event while preserving the target's own subscription contract. */
2
+ export async function wait(target, event, timeout) {
3
+ return target.waitFor(event, timeout);
4
+ }
@@ -0,0 +1,52 @@
1
+ import { collect, integer } from "./input.js";
2
+ export const jsonOption = option("--json", "write the result as machine-readable JSON on one line");
3
+ export const processOptions = Object.freeze([
4
+ option("--process <identity>", "Process identity or Program-local name", { mandatory: true }),
5
+ option("--program <identity>", "owning Program identity when resolving a Process name")
6
+ ]);
7
+ export const endpointOptions = Object.freeze([
8
+ ...processOptions,
9
+ option("--endpoint <endpoint>", "Endpoint kind", { mandatory: true, choices: ["server", "client"] })
10
+ ]);
11
+ export const clientOverrideOptions = Object.freeze([
12
+ option("--client-service", "address this Client incarnation through system.service()"),
13
+ option("--no-client-service", "do not address this Client incarnation through system.service()"),
14
+ option("--client-title <title>", "initial Window title"),
15
+ option("--client-width <value>", "initial Window width"),
16
+ option("--client-height <value>", "initial Window height"),
17
+ option("--client-x <value>", "initial Window horizontal position"),
18
+ option("--client-y <value>", "initial Window vertical position"),
19
+ option("--client-layer <layer>", "initial Window layer", { choices: ["window", "under", "over"] }),
20
+ option("--client-location <location>", "initial page beneath the Client location"),
21
+ option("--client-minimized", "open the Window minimized")
22
+ ]);
23
+ export const serverOverrideOptions = Object.freeze([
24
+ option("--server-service", "address this Server incarnation through system.service()"),
25
+ option("--no-server-service", "do not address this Server incarnation through system.service()")
26
+ ]);
27
+ export const launchOptions = Object.freeze([
28
+ ...serverOverrideOptions,
29
+ option("--client", "start the Client Endpoint"),
30
+ option("--no-client", "do not start the Client Endpoint"),
31
+ ...clientOverrideOptions,
32
+ option("--name <name>", "stable Program-local Process name"),
33
+ option("--server", "start the Server Endpoint"),
34
+ option("--no-server", "do not start the Server Endpoint"),
35
+ option("--option <name=value>", "immutable Process option; repeat for more values", {
36
+ default: [],
37
+ repeatable: true,
38
+ parse: (value, previous) => collect(value, Array.isArray(previous) ? previous : [])
39
+ })
40
+ ]);
41
+ export const namedLaunchOptions = Object.freeze(launchOptions.map(current => current.flags === "--name <name>"
42
+ ? Object.freeze({ ...current, mandatory: true })
43
+ : current));
44
+ export const timeoutOption = option("--timeout <milliseconds>", "maximum wait in milliseconds", {
45
+ parse: value => integer(value)
46
+ });
47
+ export function withJson(...options) {
48
+ return Object.freeze([...options, jsonOption]);
49
+ }
50
+ export function option(flags, description, values = {}) {
51
+ return Object.freeze({ flags, description, ...values });
52
+ }
@@ -0,0 +1,111 @@
1
+ import { defineCommand } from "../contract/command.js";
2
+ import { value } from "../contract/schema.js";
3
+ import { launchOptions, namedLaunchOptions, option, processOptions, timeoutOption, withJson } from "./options.js";
4
+ import { eventOutput, jsonOutput, pageOutput, processOutput } from "./schemas.js";
5
+ import { connected, requireProcess, requireProgram } from "./connection.js";
6
+ import { bounded, integer, launch, page } from "./input.js";
7
+ import { wait } from "./observation.js";
8
+ import { processView } from "./projection.js";
9
+ export default function processCommands(root, connect) {
10
+ const processes = defineCommand(root, {
11
+ name: "process",
12
+ description: "discover and control live Program executions",
13
+ guidance: ["A Process is one execution of a Program and owns its Server and Client Endpoints."]
14
+ });
15
+ defineCommand(processes, {
16
+ name: "list",
17
+ description: "list live Processes with bounded filtering",
18
+ requiresSystem: true,
19
+ options: withJson(option("--program <identity>", "restrict results to one Program"), option("--search <text>", "case-insensitive identity or name search"), option("--limit <count>", "maximum returned Processes", { parse: value => integer(value), default: 30 }), option("--offset <count>", "number of matching Processes to skip", { parse: value => integer(value), default: 0 })),
20
+ output: jsonOutput(pageOutput(processOutput, "matching Processes"), "A bounded page of Processes"),
21
+ examples: ["phresh process list", "phresh process list --program terminal --json"]
22
+ }, async ({ options }) => connected(connect, async (system) => {
23
+ const processes = options.program
24
+ ? await (await requireProgram(system, options.program)).process.list()
25
+ : await system.process.list();
26
+ const selected = page(processes, options.search, bounded(options.offset, "--offset", 0), bounded(options.limit, "--limit", 1, 100), current => `${current.identity}\n${current.name ?? ""}`);
27
+ return { ...selected, data: await Promise.all(selected.data.map(processView)) };
28
+ }));
29
+ defineCommand(processes, {
30
+ name: "inspect",
31
+ description: "read one live Process and its Endpoint state",
32
+ requiresSystem: true,
33
+ options: withJson(...processOptions),
34
+ output: jsonOutput(processOutput, "The selected Process"),
35
+ examples: ["phresh process inspect --process main --program terminal"]
36
+ }, async ({ options }) => connected(connect, async (system) => {
37
+ return await processView(await requireProcess(system, options.process, options.program));
38
+ }));
39
+ defineCommand(processes, {
40
+ name: "create",
41
+ description: "create a Process",
42
+ requiresSystem: true,
43
+ options: withJson(option("--program <identity>", "owning Program identity", { mandatory: true }), ...launchOptions),
44
+ output: jsonOutput(processOutput, "The created Process"),
45
+ examples: ["phresh process create --program terminal --server --client", "phresh process create --program terminal --name main --json"]
46
+ }, async ({ options }) => connected(connect, async (system) => {
47
+ const program = await requireProgram(system, options.program);
48
+ return await processView(await program.process.create(launch(options)));
49
+ }));
50
+ defineCommand(processes, {
51
+ name: "findOrCreate",
52
+ aliases: ["find-or-create"],
53
+ description: "find the named Process or create it atomically",
54
+ requiresSystem: true,
55
+ options: withJson(option("--program <identity>", "owning Program identity", { mandatory: true }), ...namedLaunchOptions),
56
+ output: jsonOutput(processOutput, "The existing or created Process"),
57
+ examples: ["phresh process find-or-create --program terminal --name main --json"]
58
+ }, async ({ options }) => connected(connect, async (system) => {
59
+ const program = await requireProgram(system, options.program);
60
+ return await processView(await program.process.findOrCreate(launch(options, true)));
61
+ }));
62
+ defineCommand(processes, {
63
+ name: "exit",
64
+ description: "exit one Process and all of its live Endpoints",
65
+ requiresSystem: true,
66
+ options: withJson(...processOptions),
67
+ output: jsonOutput(processOutput, "The Process state immediately before exit"),
68
+ examples: ["phresh process exit --process main --program terminal"]
69
+ }, async ({ options }) => connected(connect, async (system) => {
70
+ const process = await requireProcess(system, options.process, options.program);
71
+ const snapshot = await processView(process);
72
+ await process.exit();
73
+ return snapshot;
74
+ }));
75
+ defineCommand(processes, {
76
+ name: "wait",
77
+ description: "wait for one Process lifecycle event",
78
+ requiresSystem: true,
79
+ options: withJson(option("--event <event>", "Process lifecycle event", { mandatory: true, choices: ["create", "exit"] }), option("--process <identity>", "scope the event to one Process"), option("--program <identity>", "scope the event to one Program"), timeoutOption),
80
+ output: jsonOutput(eventOutput("The observed Process event", value.any("Process state or exit result")), "One Process event"),
81
+ examples: ["phresh process wait --event create", "phresh process wait --event exit --process main --program terminal --json"]
82
+ }, async ({ options }) => connected(connect, async (system) => {
83
+ if (options.process && options.event === "create")
84
+ throw new Error("An individual Process does not emit create");
85
+ const target = options.process
86
+ ? await requireProcess(system, options.process, options.program)
87
+ : options.program
88
+ ? (await requireProgram(system, options.program)).process
89
+ : system.process;
90
+ const message = await wait(target, options.event, options.timeout === undefined
91
+ ? undefined
92
+ : bounded(options.timeout, "--timeout", 1));
93
+ return {
94
+ scope: options.process ? `process:${options.process}` : options.program ? `program:${options.program}` : "process",
95
+ event: options.event,
96
+ payload: await eventView(options.event, message, options.process ? target : undefined)
97
+ };
98
+ }));
99
+ }
100
+ async function eventView(event, message, scoped) {
101
+ if (event === "create")
102
+ return processView(message);
103
+ const exit = message;
104
+ const process = exit.process ?? scoped;
105
+ return {
106
+ ...(process ? { process: await processView(process) } : {}),
107
+ status: exit.status,
108
+ code: exit.code,
109
+ signal: exit.signal
110
+ };
111
+ }
@@ -0,0 +1,90 @@
1
+ import { defineCommand } from "../contract/command.js";
2
+ import { value } from "../contract/schema.js";
3
+ import { option, timeoutOption, withJson } from "./options.js";
4
+ import { eventOutput, jsonOutput, pageOutput, programOutput } from "./schemas.js";
5
+ import { connected, requireProgram } from "./connection.js";
6
+ import { bounded, integer, page } from "./input.js";
7
+ import { wait } from "./observation.js";
8
+ import { programView } from "./projection.js";
9
+ export default function programCommands(root, connect) {
10
+ const programs = defineCommand(root, {
11
+ name: "program",
12
+ description: "discover PhreshOS Programs and their agent documentation",
13
+ guidance: ["A Program is the stable installed or retained definition that owns Processes."]
14
+ });
15
+ defineCommand(programs, {
16
+ name: "list",
17
+ description: "list Programs with bounded filtering",
18
+ requiresSystem: true,
19
+ options: withJson(option("--installed-only", "return only installed Programs"), option("--search <text>", "case-insensitive identity, name, or description search"), option("--limit <count>", "maximum returned Programs", { parse: value => integer(value), default: 30 }), option("--offset <count>", "number of matching Programs to skip", { parse: value => integer(value), default: 0 })),
20
+ output: jsonOutput(pageOutput(programOutput, "matching Programs"), "A bounded page of Programs"),
21
+ examples: ["phresh program list", "phresh program list --installed-only --json"]
22
+ }, async ({ options }) => connected(connect, async (system) => {
23
+ const programs = await system.program.list(options.installedOnly === true);
24
+ const selected = page(programs, options.search, bounded(options.offset, "--offset", 0), bounded(options.limit, "--limit", 1, 100), current => `${current.identity}\n${current.name}\n${current.description ?? ""}`);
25
+ return { ...selected, data: await Promise.all(selected.data.map(programView)) };
26
+ }));
27
+ defineCommand(programs, {
28
+ name: "inspect",
29
+ description: "read one Program declaration and installed state",
30
+ requiresSystem: true,
31
+ options: withJson(option("--program <identity>", "Program identity", { mandatory: true })),
32
+ output: jsonOutput(programOutput, "The selected Program"),
33
+ examples: ["phresh program inspect --program terminal"]
34
+ }, async ({ options }) => connected(connect, async (system) => {
35
+ return await programView(await requireProgram(system, options.program));
36
+ }));
37
+ defineCommand(programs, {
38
+ name: "agent",
39
+ description: "read a Program's own agent operating policy",
40
+ requiresSystem: true,
41
+ options: withJson(option("--program <identity>", "Program identity", { mandatory: true })),
42
+ output: jsonOutput(value.object({
43
+ program: value.string("Program identity"),
44
+ content: value.string("Program-owned agent documentation")
45
+ }, ["program", "content"], "Program agent documentation"), "The Program's agent documentation"),
46
+ examples: ["phresh program agent --program terminal --json"]
47
+ }, async ({ options }) => connected(connect, async (system) => {
48
+ const program = await requireProgram(system, options.program);
49
+ const content = await program.agent();
50
+ if (content === null)
51
+ throw new Error(`Program "${program.identity}" has no agent documentation`);
52
+ return { program: program.identity, content };
53
+ }));
54
+ defineCommand(programs, {
55
+ name: "wait",
56
+ description: "wait for one Program registry event",
57
+ requiresSystem: true,
58
+ options: withJson(option("--event <event>", "Program lifecycle event", {
59
+ mandatory: true,
60
+ choices: ["create", "forget", "install", "uninstall"]
61
+ }), option("--program <identity>", "scope forget or uninstall to one Program"), timeoutOption),
62
+ output: jsonOutput(eventOutput("The observed Program event", value.any("Program state or uninstall result")), "One Program event"),
63
+ examples: ["phresh program wait --event create", "phresh program wait --event uninstall --program terminal --json"]
64
+ }, async ({ options }) => connected(connect, async (system) => {
65
+ if (options.program && options.event !== "forget" && options.event !== "uninstall") {
66
+ throw new Error("An individual Program emits only forget and uninstall");
67
+ }
68
+ const target = options.program ? await requireProgram(system, options.program) : system.program;
69
+ const message = await wait(target, options.event, timeout(options.timeout));
70
+ return {
71
+ scope: options.program ? `program:${options.program}` : "program",
72
+ event: options.event,
73
+ payload: await eventView(options.event, message, options.program ? target : undefined)
74
+ };
75
+ }));
76
+ }
77
+ async function eventView(event, message, scoped) {
78
+ if (event === "uninstall") {
79
+ if (scoped)
80
+ return { program: await programView(scoped), everything: message === true };
81
+ const current = message;
82
+ return { program: await programView(current.program), everything: current.everything };
83
+ }
84
+ if (scoped)
85
+ return programView(scoped);
86
+ return programView(message);
87
+ }
88
+ function timeout(value) {
89
+ return value === undefined ? undefined : bounded(value, "--timeout", 1);
90
+ }
@@ -0,0 +1,152 @@
1
+ import { defineCommand } from "../contract/command.js";
2
+ import create from "../create.js";
3
+ import init from "../init.js";
4
+ import install from "../install.js";
5
+ import launch from "../launch.js";
6
+ import pack from "../pack.js";
7
+ import uninstall from "../uninstall.js";
8
+ import { option } from "./options.js";
9
+ import { textOutput } from "./schemas.js";
10
+ const runOptionPrefix = "--run-option-";
11
+ /** Register commands whose subject is a Program project or release. */
12
+ export default function projectCommands(program, coreRange) {
13
+ defineCommand(program, {
14
+ name: "create",
15
+ description: "create a new Program project",
16
+ arguments: [{ syntax: "[directory]", description: "directory for the new Program" }],
17
+ options: [
18
+ option("--name <name>", "human-readable Program name"),
19
+ option("--package-manager <manager>", "package manager used to install dependencies", { choices: ["bun", "npm", "pnpm", "yarn"] }),
20
+ option("--no-install", "create files without installing dependencies")
21
+ ],
22
+ guidance: [
23
+ "Creates a complete Server and Client project from the maintained Phresh Program template bundled with this CLI.",
24
+ "In a terminal, omitted values are collected interactively. Automation supplies the directory and optional choices through named options."
25
+ ],
26
+ examples: ["phresh create", "phresh create my-program --package-manager bun"],
27
+ output: textOutput("Created Program project and installation status")
28
+ }, async ({ arguments: [directory], options }) => {
29
+ await create({ directory, name: options.name, packageManager: options.packageManager, install: options.install });
30
+ });
31
+ defineCommand(program, {
32
+ name: "init",
33
+ description: "initialize an existing Program project",
34
+ options: [
35
+ option("--name <name>", "human-readable Program name"),
36
+ option("--build-command <command>", "prepare production files before use"),
37
+ option("--server", "include a Server endpoint"),
38
+ option("--server-location <path>", "production Server directory"),
39
+ option("--server-start-command <command>", "production Server command"),
40
+ option("--server-entry-file <path>", "production Server worker entry"),
41
+ option("--server-development-start-command <command>", "development Server command"),
42
+ option("--server-development-entry-file <path>", "development Server worker entry"),
43
+ option("--client", "include a Client endpoint"),
44
+ option("--client-location <path>", "production Client directory"),
45
+ option("--client-development-url <url>", "fixed or external development Client URL"),
46
+ option("--client-development-start-command <command>", "development Client command"),
47
+ option("--force", "replace an existing phresh.config.ts")
48
+ ],
49
+ guidance: [
50
+ "Reads identity, version, and description from package.json, then writes phresh.config.ts.",
51
+ "A terminal asks only for values the project cannot provide. Without a terminal, declare at least one endpoint with options."
52
+ ],
53
+ examples: ["phresh init --server --client", "phresh init --client --client-location dist/client"],
54
+ output: textOutput("Initialized Program configuration")
55
+ }, async ({ options }) => {
56
+ await init({
57
+ name: options.name,
58
+ buildCommand: options.buildCommand,
59
+ server: options.server === true || options.serverLocation !== undefined || options.serverStartCommand !== undefined || options.serverEntryFile !== undefined,
60
+ serverLocation: options.serverLocation,
61
+ serverStartCommand: options.serverStartCommand,
62
+ serverEntryFile: options.serverEntryFile,
63
+ serverDevelopmentStartCommand: options.serverDevelopmentStartCommand,
64
+ serverDevelopmentEntryFile: options.serverDevelopmentEntryFile,
65
+ client: options.client === true
66
+ || options.clientLocation !== undefined
67
+ || options.clientDevelopmentUrl !== undefined
68
+ || options.clientDevelopmentStartCommand !== undefined,
69
+ clientLocation: options.clientLocation,
70
+ clientDevelopmentUrl: options.clientDevelopmentUrl,
71
+ clientDevelopmentStartCommand: options.clientDevelopmentStartCommand,
72
+ force: options.force === true
73
+ }, process.cwd(), coreRange);
74
+ });
75
+ defineCommand(program, {
76
+ name: "pack",
77
+ description: "build and package this Program",
78
+ guidance: ["Runs an optional buildCommand, then packages the production files declared for each endpoint."],
79
+ examples: ["phresh pack"],
80
+ output: textOutput("Packaged Program release")
81
+ }, async function () {
82
+ await pack();
83
+ });
84
+ defineCommand(program, {
85
+ name: "install",
86
+ description: "install a local or official Program",
87
+ arguments: [{ syntax: "[name]", description: "name of an official Program" }],
88
+ options: [option("--run", "run the installed Program now")],
89
+ guidance: [
90
+ "Without a name, builds and installs the Program declared by this project.",
91
+ "A name installs its verified official production release. --run launches the installed Program now."
92
+ ],
93
+ requiresSystem: true,
94
+ examples: ["phresh install", "phresh install terminal --run"],
95
+ output: textOutput("Installed Program and optional Process identity")
96
+ }, async ({ arguments: [name], options }) => {
97
+ await install({ name, run: options.run === true });
98
+ });
99
+ defineCommand(program, {
100
+ name: "uninstall",
101
+ description: "uninstall a local or installed Program",
102
+ arguments: [{ syntax: "[name]", description: "name of an installed Program" }],
103
+ options: [option("--everything", "also remove Processes, data, and runtime state")],
104
+ guidance: [
105
+ "Without a name, uses the Program declared by this project.",
106
+ "Removes installed files while preserving Processes, data, and runtime Program state unless --everything is supplied."
107
+ ],
108
+ requiresSystem: true,
109
+ examples: ["phresh uninstall", "phresh uninstall terminal --everything"],
110
+ output: textOutput("Uninstalled Program state")
111
+ }, async ({ arguments: [name], options }) => {
112
+ await uninstall({ name, everything: options.everything === true });
113
+ });
114
+ attached(program, "start", "run the production Program without installing", [
115
+ "Runs this Program attached to the terminal. Output arrives here, and ending this command stops the Program.",
116
+ "An optional buildCommand runs before launch, and the Program's exit status becomes this command's status."
117
+ ], "production");
118
+ attached(program, "dev", "run the development Program without installing", [
119
+ "Runs the same attached lifecycle as start using the development declarations.",
120
+ "A Client URL must respond within 15 seconds before launch."
121
+ ], "development");
122
+ }
123
+ function attached(program, name, description, guidance, mode) {
124
+ defineCommand(program, {
125
+ name,
126
+ description,
127
+ arguments: [{ syntax: "[run-options...]", description: "--run-option-<name>=<value> values passed to the Program" }],
128
+ allowUnknownOptions: true,
129
+ requiresSystem: true,
130
+ guidance,
131
+ examples: [`phresh ${name}`, `phresh ${name} --run-option-example=value`],
132
+ output: textOutput("Attached Process lifecycle and output")
133
+ }, async ({ arguments: [arguments_] }) => {
134
+ await launch(mode, process.cwd(), runOptions(name, arguments_));
135
+ });
136
+ }
137
+ function runOptions(command, arguments_) {
138
+ const options = {};
139
+ for (const argument of arguments_) {
140
+ if (!argument.startsWith(runOptionPrefix))
141
+ throw new Error(`${command} accepts Program options only as ${runOptionPrefix}<name>=<value>; received "${argument}"`);
142
+ const said = argument.slice(runOptionPrefix.length);
143
+ const at = said.indexOf("=");
144
+ if (at < 1)
145
+ throw new Error(`"${argument}" says no value — write ${runOptionPrefix}<name>=<value>, and end with = for an empty value`);
146
+ const name = said.slice(0, at);
147
+ if (Object.hasOwn(options, name))
148
+ throw new Error(`The run option "${name}" was given more than once`);
149
+ options[name] = said.slice(at + 1);
150
+ }
151
+ return options;
152
+ }
@@ -0,0 +1,59 @@
1
+ export function endpoint(process, name) {
2
+ return name === "server" ? process.server : process.client;
3
+ }
4
+ export function windowOf(process) {
5
+ return process.client.window;
6
+ }
7
+ export async function programView(program) {
8
+ return {
9
+ identity: program.identity,
10
+ assetId: program.assetId,
11
+ name: program.name,
12
+ version: program.version,
13
+ description: program.description,
14
+ installed: await program.installed(),
15
+ hasAgent: program.hasAgent,
16
+ server: program.server,
17
+ client: program.client
18
+ };
19
+ }
20
+ export async function processView(process) {
21
+ const [server, client, serverService, clientService] = await Promise.all([
22
+ process.server.exists(),
23
+ process.client.exists(),
24
+ process.server.isService(),
25
+ process.client.isService()
26
+ ]);
27
+ return {
28
+ identity: process.identity,
29
+ name: process.name,
30
+ program: process.program().identity,
31
+ startedAt: process.startedAt.toISOString(),
32
+ server: { declared: process.program().server !== null, running: server, service: serverService },
33
+ client: { declared: process.program().client !== null, running: client, service: clientService }
34
+ };
35
+ }
36
+ export async function endpointView(process, name) {
37
+ const program = process.program();
38
+ return {
39
+ process: process.identity,
40
+ program: program.identity,
41
+ endpoint: name,
42
+ declared: name === "server" ? program.server !== null : program.client !== null,
43
+ running: await endpoint(process, name).exists(),
44
+ service: await endpoint(process, name).isService()
45
+ };
46
+ }
47
+ export async function windowView(process) {
48
+ const window = process.client.window;
49
+ const [title, position, size, minimized, front, layer, location] = await Promise.all([
50
+ window.title(),
51
+ window.position(),
52
+ window.size(),
53
+ window.minimized(),
54
+ window.front(),
55
+ window.layer(),
56
+ window.location()
57
+ ]);
58
+ return { process: process.identity, title, position, size, minimized, front, layer, location };
59
+ }
@@ -0,0 +1,89 @@
1
+ import { value } from "../contract/schema.js";
2
+ const metric = {
3
+ anyOf: [value.number("pixels"), value.string("workspace-relative expression")]
4
+ };
5
+ const endpointDeclaration = value.nullable(value.object({
6
+ start: value.boolean("whether a default Process starts this Endpoint"),
7
+ service: value.boolean("default Service role for new incarnations")
8
+ }, ["start", "service"], "resolved Server Endpoint declaration"));
9
+ const permissions = value.object({
10
+ all: value.array(value.string("permission value"), "all permission values"),
11
+ services: value.array(value.string("Program identity"), "permitted Service Programs"),
12
+ programs: value.array(value.string("Program identity"), "permitted Programs"),
13
+ appearance: value.array(value.string("permission value"), "appearance permission values"),
14
+ desktopPreferences: value.array(value.string("permission value"), "Desktop preferences permission values")
15
+ }, [], "immutable Client permissions");
16
+ const clientDeclaration = value.nullable(value.object({
17
+ start: value.boolean("whether a default Process starts this Endpoint"),
18
+ service: value.boolean("default Service role for new incarnations"),
19
+ title: value.nullable(value.string("default Window title")),
20
+ size: value.nullable(value.object({ width: metric, height: metric }, ["width", "height"], "default Window size")),
21
+ position: value.nullable(value.object({ x: metric, y: metric }, ["x", "y"], "default Window position")),
22
+ layer: value.nullable(value.enumeration(["window", "under", "over"], "default Window layer")),
23
+ minimize: value.nullable(value.boolean("default minimized state")),
24
+ permissions
25
+ }, ["start", "service", "title", "size", "position", "layer", "minimize", "permissions"], "resolved Client Endpoint declaration"));
26
+ export const programOutput = value.object({
27
+ identity: value.string("stable Program identity"),
28
+ assetId: value.string("public Program asset identity"),
29
+ name: value.string("human-readable Program name"),
30
+ version: value.nullable(value.string("Program version")),
31
+ description: value.nullable(value.string("Program description")),
32
+ installed: value.boolean("whether production files are installed"),
33
+ hasAgent: value.boolean("whether the Program provides agent documentation"),
34
+ server: endpointDeclaration,
35
+ client: clientDeclaration
36
+ }, ["identity", "assetId", "name", "version", "description", "installed", "hasAgent", "server", "client"], "Program state");
37
+ export const processOutput = value.object({
38
+ identity: value.string("unique Process identity"),
39
+ name: value.nullable(value.string("stable Program-local Process name")),
40
+ program: value.string("owning Program identity"),
41
+ startedAt: value.string("ISO start time"),
42
+ server: endpointState("Server Endpoint state"),
43
+ client: endpointState("Client Endpoint state")
44
+ }, ["identity", "name", "program", "startedAt", "server", "client"], "Process state");
45
+ export const endpointOutput = value.object({
46
+ process: value.string("owning Process identity"),
47
+ program: value.string("owning Program identity"),
48
+ endpoint: value.enumeration(["server", "client"], "Endpoint kind"),
49
+ declared: value.boolean("whether the Program declares this Endpoint"),
50
+ running: value.boolean("whether the Endpoint currently exists"),
51
+ service: value.boolean("whether this Endpoint incarnation is addressable as a Service")
52
+ }, ["process", "program", "endpoint", "declared", "running", "service"], "Endpoint state");
53
+ export const windowOutput = value.object({
54
+ process: value.string("owning Process identity"),
55
+ title: value.string("Window title"),
56
+ position: value.object({ x: metric, y: metric }, ["x", "y"], "Window position"),
57
+ size: value.object({ width: metric, height: metric }, ["width", "height"], "Window size"),
58
+ minimized: value.boolean("whether the Window is minimized"),
59
+ front: value.boolean("whether the Window is at the front of its layer"),
60
+ layer: value.enumeration(["window", "under", "over"], "Window layer"),
61
+ location: value.string("current Client location")
62
+ }, ["process", "title", "position", "size", "minimized", "front", "layer", "location"], "Window state");
63
+ export function pageOutput(items, description) {
64
+ return value.object({
65
+ data: value.array(items, description),
66
+ total: value.integer("total matching values"),
67
+ truncated: value.boolean("whether more matching values exist")
68
+ }, ["data", "total", "truncated"], description);
69
+ }
70
+ export function eventOutput(description, payload = value.any("event payload")) {
71
+ return value.object({
72
+ scope: value.string("subscription scope"),
73
+ event: value.string("event name"),
74
+ payload
75
+ }, ["scope", "event", "payload"], description);
76
+ }
77
+ export function jsonOutput(schema, description) {
78
+ return { format: "json", description, value: schema };
79
+ }
80
+ export function textOutput(description) {
81
+ return { format: "text", description };
82
+ }
83
+ function endpointState(description) {
84
+ return value.object({
85
+ declared: value.boolean("whether the Program declares this Endpoint"),
86
+ running: value.boolean("whether the Endpoint currently exists"),
87
+ service: value.boolean("whether this Endpoint incarnation is a Service")
88
+ }, ["declared", "running", "service"], description);
89
+ }