@phreshos/cli 0.1.53 → 0.1.54

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
@@ -55,6 +55,12 @@ bun run verify
55
55
  `verify` checks the scripts, builds the CLI and bundled starter, runs the
56
56
  command tests, and validates the package artifact.
57
57
 
58
+ `check` performs static checks, `build` creates distributable output, and `test`
59
+ runs Vitest assertions from `tests/`. Run `build` before testing built artifacts.
60
+ `verify` runs `check`, `build`, and `test` in order. Operational tooling belongs
61
+ in `scripts/`; tests and their fixtures belong in `tests/`. Verification uses
62
+ the committed dependency graph without local package substitutions.
63
+
58
64
  ## Related repositories
59
65
 
60
66
  - [`@phreshos/node`](https://github.com/PhreshOS/node) owns the Project and
@@ -76,3 +82,10 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for the repository workflow and
76
82
  ## License
77
83
 
78
84
  Licensed under the [MIT License](LICENSE). Copyright © 2026 Zohayr SLILEH.
85
+
86
+ `test:platform` explicitly selects native service/installation tests for the
87
+ current OS. These may change temporary host services; CI runs them on disposable
88
+ runners after building.
89
+
90
+ `test:live` explicitly selects external-service tests. They require network
91
+ access and, for providers, credentials; provider calls may incur costs.
@@ -64,7 +64,6 @@ export function clientLaunch(options) {
64
64
  || options.clientX !== undefined
65
65
  || options.clientY !== undefined
66
66
  || options.clientLayer !== undefined
67
- || options.clientLocation !== undefined
68
67
  || options.clientMinimized === true
69
68
  || service !== undefined;
70
69
  if (!configured)
@@ -83,8 +82,8 @@ export function clientLaunch(options) {
83
82
  ...(options.clientWidth === undefined ? {} : { size: size(options.clientWidth, options.clientHeight) }),
84
83
  ...(options.clientX === undefined ? {} : { position: position(options.clientX, options.clientY) }),
85
84
  ...(options.clientLayer === undefined ? {} : { layer: options.clientLayer }),
86
- ...(options.clientLocation === undefined ? {} : { location: options.clientLocation }),
87
- ...(options.clientMinimized === true ? { minimize: true } : {})
85
+ ...(options.clientMinimized === true ? { minimize: true } : {}),
86
+ ...(options.clientMaximized === true ? { maximize: true } : {})
88
87
  };
89
88
  }
90
89
  export function serverLaunch(options) {
@@ -1,4 +1,4 @@
1
1
  /** Wait for one named event while preserving the target's own subscription contract. */
2
2
  export async function wait(target, event, timeout) {
3
- return target.waitFor(event, timeout);
3
+ return target.wait(event, timeout);
4
4
  }
@@ -17,8 +17,8 @@ export const clientOverrideOptions = Object.freeze([
17
17
  option("--client-x <value>", "initial Window horizontal position"),
18
18
  option("--client-y <value>", "initial Window vertical position"),
19
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")
20
+ option("--client-minimized", "open the Window minimized"),
21
+ option("--client-maximized", "open the Window maximized")
22
22
  ]);
23
23
  export const serverOverrideOptions = Object.freeze([
24
24
  option("--server-service", "address this Server incarnation through system.service()"),
@@ -46,14 +46,14 @@ export async function endpointView(process, name) {
46
46
  }
47
47
  export async function windowView(process) {
48
48
  const window = process.client.window;
49
- const [title, position, size, minimized, front, layer, location] = await Promise.all([
49
+ const [title, position, size, minimized, maximized, front, layer] = await Promise.all([
50
50
  window.title(),
51
51
  window.position(),
52
52
  window.size(),
53
53
  window.minimized(),
54
+ window.maximized(),
54
55
  window.front(),
55
- window.layer(),
56
- window.location()
56
+ window.layer()
57
57
  ]);
58
- return { process: process.identity, title, position, size, minimized, front, layer, location };
58
+ return { process: process.identity, title, position, size, minimized, maximized, front, layer };
59
59
  }
@@ -1,4 +1,3 @@
1
- import { clientPermissionCatalog } from "@phreshos/core";
2
1
  import { value } from "../contract/schema.js";
3
2
  const metric = {
4
3
  anyOf: [value.number("pixels"), value.string("workspace-relative expression")]
@@ -7,10 +6,6 @@ const endpointDeclaration = value.nullable(value.object({
7
6
  start: value.boolean("whether a default Process starts this Endpoint"),
8
7
  service: value.boolean("default Service role for new incarnations")
9
8
  }, ["start", "service"], "resolved Server Endpoint declaration"));
10
- const permissions = value.object(Object.fromEntries(Object.entries(clientPermissionCatalog).map(([name, domain]) => [name, domain === "none"
11
- ? { type: "array", maxItems: 0, description: `${name} presence-only grant` }
12
- : value.array(value.string(permissionValueDescription(domain)), `${name} permission values`)
13
- ])), [], "immutable Client permissions");
14
9
  const clientDeclaration = value.nullable(value.object({
15
10
  start: value.boolean("whether a default Process starts this Endpoint"),
16
11
  service: value.boolean("default Service role for new incarnations"),
@@ -19,8 +14,8 @@ const clientDeclaration = value.nullable(value.object({
19
14
  position: value.nullable(value.object({ x: metric, y: metric }, ["x", "y"], "default Window position")),
20
15
  layer: value.nullable(value.enumeration(["window", "under", "over"], "default Window layer")),
21
16
  minimize: value.nullable(value.boolean("default minimized state")),
22
- permissions
23
- }, ["start", "service", "title", "size", "position", "layer", "minimize", "permissions"], "resolved Client Endpoint declaration"));
17
+ maximize: value.nullable(value.boolean("default maximized state"))
18
+ }, ["start", "service", "title", "size", "position", "layer", "minimize", "maximize"], "resolved Client Endpoint declaration"));
24
19
  export const programOutput = value.object({
25
20
  identity: value.string("stable Program identity"),
26
21
  assetId: value.string("public Program asset identity"),
@@ -54,10 +49,10 @@ export const windowOutput = value.object({
54
49
  position: value.object({ x: metric, y: metric }, ["x", "y"], "Window position"),
55
50
  size: value.object({ width: metric, height: metric }, ["width", "height"], "Window size"),
56
51
  minimized: value.boolean("whether the Window is minimized"),
52
+ maximized: value.boolean("whether the Window is maximized"),
57
53
  front: value.boolean("whether the Window is at the front of its layer"),
58
- layer: value.enumeration(["window", "under", "over"], "Window layer"),
59
- location: value.string("current Client location")
60
- }, ["process", "title", "position", "size", "minimized", "front", "layer", "location"], "Window state");
54
+ layer: value.enumeration(["window", "under", "over"], "Window layer")
55
+ }, ["process", "title", "position", "size", "minimized", "maximized", "front", "layer"], "Window state");
61
56
  export const programPresentation = fields(["Identity", "identity"], ["Asset", "assetId"], ["Name", "name"], ["Version", "version"], ["Description", "description"], ["Installed", "installed"], ["Agent", "hasAgent"], ["Server", "server"], ["Client", "client"]);
62
57
  export const programListPresentation = table("data", "Program", "Programs", "No matching Programs", [
63
58
  { label: "Name", path: "name", width: 2 },
@@ -77,11 +72,12 @@ export const processListPresentation = table("data", "Process", "Processes", "No
77
72
  ]);
78
73
  export const endpointPresentation = fields(["Process", "process"], ["Program", "program"], ["Endpoint", "endpoint"], ["Declared", "declared"], ["Running", "running"], ["Service", "service"]);
79
74
  export const endpointActionPresentation = fields(["Process", "process"], ["Endpoint", "endpoint"], ["Running", "running"], ["Service", "service"]);
80
- export const windowPresentation = fields(["Process", "process"], ["Title", "title"], ["Position", "position"], ["Size", "size"], ["Minimized", "minimized"], ["Front", "front"], ["Layer", "layer"], ["Location", "location"]);
75
+ export const windowPresentation = fields(["Process", "process"], ["Title", "title"], ["Position", "position"], ["Size", "size"], ["Minimized", "minimized"], ["Maximized", "maximized"], ["Front", "front"], ["Layer", "layer"], ["Location", "location"]);
81
76
  export const windowPositionPresentation = fields(["Process", "process"], ["Position", "position"]);
82
77
  export const windowSizePresentation = fields(["Process", "process"], ["Size", "size"]);
83
78
  export const windowGeometryPresentation = fields(["Process", "process"], ["Position", "position"], ["Size", "size"]);
84
79
  export const windowMinimizePresentation = fields(["Process", "process"], ["Minimized", "minimized"]);
80
+ export const windowMaximizePresentation = fields(["Process", "process"], ["Maximized", "maximized"]);
85
81
  export const windowTitlePresentation = fields(["Process", "process"], ["Title", "title"]);
86
82
  export const windowRaisePresentation = fields(["Process", "process"], ["Front", "front"]);
87
83
  export const eventPresentation = fields(["Scope", "scope"], ["Event", "event"], ["Payload", "payload"]);
@@ -124,10 +120,3 @@ function fields(...values) {
124
120
  function table(rows, item, items, empty, columns) {
125
121
  return { format: "table", rows, columns, item, items, empty, total: "total", truncated: "truncated" };
126
122
  }
127
- function permissionValueDescription(domain) {
128
- switch (domain) {
129
- case "program": return "Program identity";
130
- case "network": return "network destination scope";
131
- case "storage": return "storage path scope";
132
- }
133
- }
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from "../contract/command.js";
2
2
  import { option, processOptions, timeoutOption, withJson } from "./options.js";
3
- import { dataOutput, eventOutput, eventPresentation, windowGeometryPresentation, windowMinimizePresentation, windowOutput, windowPositionPresentation, windowPresentation, windowRaisePresentation, windowSizePresentation, windowTitlePresentation } from "./schemas.js";
3
+ import { dataOutput, eventOutput, eventPresentation, windowGeometryPresentation, windowMinimizePresentation, windowMaximizePresentation, windowOutput, windowPositionPresentation, windowPresentation, windowRaisePresentation, windowSizePresentation, windowTitlePresentation } from "./schemas.js";
4
4
  import { connected, requireProcess } from "./connection.js";
5
5
  import { bounded, position, size } from "./input.js";
6
6
  import { wait } from "./observation.js";
@@ -50,6 +50,14 @@ export default function windowCommands(root, connect) {
50
50
  await windowOf(process).minimize(options.restore !== true);
51
51
  return await windowView(process);
52
52
  }));
53
+ defineCommand(windows, {
54
+ ...state("maximize", "set Window maximization without changing visibility or stored geometry", windowMaximizePresentation),
55
+ options: withJson(...processOptions, option("--restore", "restore rather than maximize the Window")),
56
+ examples: ["phresh window maximize --process main --program terminal", "phresh window maximize --process main --program terminal --restore"]
57
+ }, async ({ options }) => withWindow(connect, options, async (process) => {
58
+ await windowOf(process).maximize(options.restore !== true);
59
+ return await windowView(process);
60
+ }));
53
61
  defineCommand(windows, {
54
62
  ...state("changeTitle", "change the human-readable Window title", windowTitlePresentation),
55
63
  aliases: ["change-title"],
@@ -72,7 +80,7 @@ export default function windowCommands(root, connect) {
72
80
  requiresSystem: true,
73
81
  options: withJson(...processOptions, option("--event <event>", "Window event", {
74
82
  mandatory: true,
75
- choices: ["move", "resize", "geometry", "minimize", "changeTitle", "front"]
83
+ choices: ["move", "resize", "geometry", "minimize", "maximize", "changeTitle", "front"]
76
84
  }), timeoutOption),
77
85
  output: dataOutput(eventOutput("The observed Window event"), "One Window event", eventPresentation),
78
86
  examples: ["phresh window wait --process main --program terminal --event geometry --json"]
package/dist/github.js ADDED
@@ -0,0 +1,9 @@
1
+ /** Headers for requests to GitHub's API, never for release asset hosts. */
2
+ export function githubApiHeaders() {
3
+ const token = process.env.GH_TOKEN || process.env.GITHUB_TOKEN;
4
+ return {
5
+ Accept: "application/vnd.github+json",
6
+ "User-Agent": "@phreshos/cli",
7
+ ...(token ? { Authorization: `Bearer ${token}` } : {})
8
+ };
9
+ }
@@ -1,9 +1,11 @@
1
+ import { githubApiHeaders } from "./github.js";
1
2
  import { createHash } from "node:crypto";
2
3
  import { mkdirSync, writeFileSync } from "node:fs";
3
4
  import { mkdtemp, readFile, rm } from "node:fs/promises";
4
5
  import { tmpdir } from "node:os";
5
6
  import { dirname, isAbsolute, join, relative, resolve } from "node:path";
6
7
  import AdmZip from "adm-zip";
8
+ import { parseProgramDefinition } from "@phreshos/core";
7
9
  /** Resolve, verify, and unpack one official production Program release. */
8
10
  export async function prepareOfficialProgram(name, fetcher = fetch) {
9
11
  const release = await resolveOfficialProgramRelease(name, fetcher);
@@ -26,10 +28,7 @@ export async function prepareOfficialProgram(name, fetcher = fetch) {
26
28
  export async function resolveOfficialProgramRelease(name, fetcher = fetch) {
27
29
  const requested = programName(name);
28
30
  const response = await fetcher(`https://api.github.com/repos/PhreshOS/${requested}-program/releases?per_page=100`, {
29
- headers: {
30
- Accept: "application/vnd.github+json",
31
- "User-Agent": "@phreshos/cli"
32
- },
31
+ headers: githubApiHeaders(),
33
32
  signal: AbortSignal.timeout(30_000)
34
33
  });
35
34
  if (!response.ok)
@@ -83,14 +82,14 @@ async function readProgram(directory, release) {
83
82
  }
84
83
  if (value.storage !== undefined)
85
84
  throw new Error("A published Program package cannot choose its installed storage");
86
- return {
85
+ return parseProgramDefinition({
87
86
  ...value,
88
87
  storage: join(directory, "storage"),
89
88
  ...pathField(value, directory, "icon", "icon.png"),
90
89
  ...pathField(value, directory, "agent", "agent.md"),
91
90
  ...half(value, directory, "server"),
92
91
  ...half(value, directory, "client")
93
- };
92
+ });
94
93
  }
95
94
  function half(value, directory, name) {
96
95
  const declared = value[name];
@@ -1,13 +1,11 @@
1
+ import { githubApiHeaders } from "../github.js";
1
2
  import { createHash } from "node:crypto";
2
3
  const releases = "https://api.github.com/repos/PhreshOS/system/releases?per_page=100";
3
4
  const compatible = { major: 0, minor: 1 };
4
5
  /** Resolve the newest stable release in the System line supported by this CLI. */
5
6
  export async function resolveSystemRelease(fetcher = fetch) {
6
7
  const response = await fetcher(releases, {
7
- headers: {
8
- Accept: "application/vnd.github+json",
9
- "User-Agent": "@phreshos/cli"
10
- },
8
+ headers: githubApiHeaders(),
11
9
  signal: AbortSignal.timeout(30_000)
12
10
  });
13
11
  if (!response.ok)
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "phresh",
3
3
  "private": true,
4
- "version": "0.1.31",
4
+ "version": "0.1.32",
5
5
  "description": "The official PhreshOS starter Program.",
6
6
  "type": "module",
7
7
  "scripts": {
@@ -14,15 +14,15 @@
14
14
  "starter"
15
15
  ],
16
16
  "dependencies": {
17
- "@phreshos/client": "^0.1.37",
18
- "@phreshos/core": "^0.1.41",
19
- "@phreshos/react": "^0.1.20",
20
- "@phreshos/server": "^0.1.41",
17
+ "@phreshos/client": "^0.1.38",
18
+ "@phreshos/core": "^0.1.42",
19
+ "@phreshos/react": "^0.1.21",
20
+ "@phreshos/server": "^0.1.42",
21
21
  "react": "^19.2.8",
22
22
  "react-dom": "^19.2.8"
23
23
  },
24
24
  "devDependencies": {
25
- "@phreshos/cli": "^0.1.53",
25
+ "@phreshos/cli": "^0.1.54",
26
26
  "@types/node": "^26.4.0",
27
27
  "@types/react": "^19.2.18",
28
28
  "@types/react-dom": "^19.2.5",
@@ -4,7 +4,7 @@ export default defineConfig({
4
4
  identity: "phresh",
5
5
  name: "Phresh Program",
6
6
  description: "A minimal counter with direct Client and Server endpoints.",
7
- version: "0.1.31",
7
+ version: "0.1.32",
8
8
  icon: "icon.png",
9
9
  categories: ["Development"],
10
10
  keywords: ["example", "counter", "client", "server"],
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "repository": "PhreshOS/phresh-program",
3
- "version": "0.1.31",
4
- "sha256": "2e6fd21f0f7e3c95934edda1790579c7d5dadb0b381fa525ebb02f747b395520",
3
+ "version": "0.1.32",
4
+ "sha256": "2644513c80b924eda546f257f853bbc03619c5b9bd2b510259d4f87ecd126f4a",
5
5
  "development": true
6
6
  }
package/package.json CHANGED
@@ -1,66 +1,65 @@
1
1
  {
2
- "name": "@phreshos/cli",
3
- "type": "module",
4
- "version": "0.1.53",
5
- "description": "The Phresh command-line interface for Program projects and system management.",
6
- "engines": {
7
- "node": ">=20.10"
8
- },
9
- "scripts": {
10
- "clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
11
- "check:scripts": "tsc --project tsconfig.scripts.json",
12
- "compile": "tsc --noEmit false --outDir dist --rootDir source --rewriteRelativeImportExtensions true --allowImportingTsExtensions true",
13
- "build": "node --run clean && node --run compile && vite-node scripts/build-template.ts",
14
- "test": "node --run compile && node --test tests/*.test.mjs",
15
- "verify": "node --run check:scripts && node --run build && node --run test && node scripts/verify-package.mjs",
16
- "verify:system-release": "node --run compile && node scripts/verify-system-release.mjs",
17
- "verify:linux-service": "node --run compile && node scripts/verify-linux-service.mjs",
18
- "verify:macos-service": "node --run compile && node scripts/verify-macos-service.mjs",
19
- "verify:windows-service": "node --run compile && node scripts/verify-windows-service.mjs",
20
- "prepack": "node --run build"
21
- },
22
- "bin": {
23
- "phresh": "dist/cli.js"
24
- },
25
- "files": [
26
- "dist",
27
- "LICENSE",
28
- "README.md"
29
- ],
30
- "author": "Zohayr SLILEH",
31
- "license": "MIT",
32
- "repository": {
33
- "type": "git",
34
- "url": "git+https://github.com/PhreshOS/cli.git"
35
- },
36
- "bugs": {
37
- "url": "https://github.com/PhreshOS/cli/issues"
38
- },
39
- "homepage": "https://github.com/PhreshOS/cli#readme",
40
- "keywords": [
41
- "phreshos",
42
- "cli",
43
- "program"
44
- ],
45
- "publishConfig": {
46
- "access": "public",
47
- "provenance": true
48
- },
49
- "packageManager": "bun@1.3.14",
50
- "dependencies": {
51
- "@clack/prompts": "^1.7.0",
52
- "@phreshos/core": "^0.1.42",
53
- "@phreshos/node": "^0.1.17",
54
- "adm-zip": "^0.6.0",
55
- "cli-table3": "^0.6.5",
56
- "commander": "^15.0.0",
2
+ "name": "@phreshos/cli",
3
+ "type": "module",
4
+ "version": "0.1.54",
5
+ "description": "The Phresh command-line interface for Program projects and system management.",
6
+ "engines": {
7
+ "node": ">=20.10"
8
+ },
9
+ "scripts": {
10
+ "clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
11
+ "compile": "tsc --noEmit false --outDir dist --rootDir source --rewriteRelativeImportExtensions true --allowImportingTsExtensions true",
12
+ "build": "node --run clean && node --run compile && vite-node scripts/build-template.ts",
13
+ "test": "vitest run --project default",
14
+ "verify": "node --run check && node --run build && node --run test",
15
+ "prepack": "node --run build",
16
+ "check": "tsc --noEmit && tsc -p tsconfig.scripts.json",
17
+ "test:platform": "vitest run --project platform",
18
+ "test:live": "vitest run --project live"
19
+ },
20
+ "bin": {
21
+ "phresh": "dist/cli.js"
22
+ },
23
+ "files": [
24
+ "dist",
25
+ "LICENSE",
26
+ "README.md"
27
+ ],
28
+ "author": "Zohayr SLILEH",
29
+ "license": "MIT",
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/PhreshOS/cli.git"
33
+ },
34
+ "bugs": {
35
+ "url": "https://github.com/PhreshOS/cli/issues"
36
+ },
37
+ "homepage": "https://github.com/PhreshOS/cli#readme",
38
+ "keywords": [
39
+ "phreshos",
40
+ "cli",
41
+ "program"
42
+ ],
43
+ "publishConfig": {
44
+ "access": "public",
45
+ "provenance": true
46
+ },
47
+ "packageManager": "bun@1.3.14",
48
+ "dependencies": {
49
+ "@clack/prompts": "^1.7.0",
50
+ "@phreshos/core": "^0.1.43",
51
+ "@phreshos/node": "^0.1.18",
52
+ "adm-zip": "^0.6.0",
53
+ "cli-table3": "^0.6.5",
54
+ "commander": "^15.0.0",
57
55
  "picocolors": "^1.1.1",
58
- "string-width": "^4.2.3"
59
- },
60
- "devDependencies": {
61
- "@types/adm-zip": "^0.5.8",
62
- "@types/node": "^25.9.5",
63
- "typescript": "^6.0.3",
64
- "vite-node": "^6.0.0"
65
- }
56
+ "string-width": "^4.2.3"
57
+ },
58
+ "devDependencies": {
59
+ "@types/adm-zip": "^0.5.8",
60
+ "@types/node": "^25.9.5",
61
+ "typescript": "^6.0.3",
62
+ "vite-node": "^6.0.0",
63
+ "vitest": "^4.1.10"
64
+ }
66
65
  }