@phreshos/cli 0.1.15 → 0.1.17

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.
@@ -1,33 +1,26 @@
1
1
  # Phresh Program
2
2
 
3
- A small Counter built as a complete Program. Its Node.js Server owns the
4
- number, while its React Client reads and increments that same authoritative
5
- state.
3
+ The minimal PhreshOS starter Program. Its Client talks directly to its Server;
4
+ there is no MVC structure and no registered service.
6
5
 
7
6
  ```bash
8
7
  bun install
9
- bun phresh dev
8
+ bun run dev
10
9
  ```
11
10
 
12
- Development starts the Server source and Vite Client together. For the
13
- production shape, build and attach the Program with:
14
-
15
- ```bash
16
- bun phresh start
17
- ```
18
-
19
- The structure keeps composition, representation, and authoritative behavior distinct:
11
+ The complete authored source is intentionally small:
20
12
 
21
13
  ```text
22
14
  source/
23
15
  ├── client/
24
- │ ├── main.tsx Client composition
25
- └── view/ React representation
16
+ │ ├── app.tsx
17
+ ├── index.html
18
+ │ ├── main.tsx
19
+ │ └── style.css
26
20
  └── server/
27
- ├── main.ts Server composition
28
- ├── core/ authoritative counter
29
- └── view/ endpoint adapter and service exposure
21
+ └── main.ts
30
22
  ```
31
23
 
32
- The Program declaration lives in `phresh.config.ts`. Its own service contract
33
- is exposed as the `counter` Server service and documented in `api-docs.md`.
24
+ `app.tsx` owns the small React component. The two `main` files are direct
25
+ endpoint entries: the Client renders the app and the Server owns the counter.
26
+ Nothing registers or exposes a named service.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "phresh-program",
3
3
  "private": true,
4
- "version": "0.1.6",
4
+ "version": "0.1.11",
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.9",
18
- "@phreshos/core": "^0.1.6",
19
- "@phreshos/react": "^0.1.5",
20
- "@phreshos/server": "^0.1.7",
17
+ "@phreshos/client": "^0.1.13",
18
+ "@phreshos/core": "^0.1.9",
19
+ "@phreshos/react": "^0.1.7",
20
+ "@phreshos/server": "^0.1.11",
21
21
  "react": "^19.2.8",
22
22
  "react-dom": "^19.2.8"
23
23
  },
24
24
  "devDependencies": {
25
- "@phreshos/cli": "^0.1.15",
25
+ "@phreshos/cli": "^0.1.17",
26
26
  "@types/node": "^26.2.0",
27
27
  "@types/react": "^19.2.18",
28
28
  "@types/react-dom": "^19.2.4",
@@ -1,102 +1,24 @@
1
1
  import { defineConfig } from "@phreshos/core"
2
2
 
3
- /**
4
- * This is the Program's authoring declaration, not a runtime configuration
5
- * loaded by either endpoint. The Phresh CLI reads it and derives the concrete
6
- * Program description needed for development, production, installation, or
7
- * packaging.
8
- *
9
- * Production uses the built locations and commands declared below.
10
- * Development replaces only each endpoint's location and start command with
11
- * its `development` declaration. Packaging relocates the production files
12
- * into the Program archive. Relative paths begin at this project directory.
13
- */
14
3
  export default defineConfig({
15
-
16
- // Permanent public address of the Program. It is kebab-case because the
17
- // system also uses it as the installed directory name. Unlike `name`, it
18
- // is an identifier and must remain stable across releases.
19
4
  identity: "phresh-program",
20
-
21
- // Human-facing metadata shown by the desktop and authoring tools. None of
22
- // these values determines the Program's identity.
23
5
  name: "Phresh Program",
24
- description: "A simple counter whose state lives on the Server.",
25
- version: "0.1.6",
26
-
27
- // One authored PNG. Installation gives it a canonical name and the system
28
- // derives the standard hosted icon sizes from it.
6
+ description: "A minimal counter with direct Client and Server endpoints.",
7
+ version: "0.1.11",
29
8
  icon: "icon.png",
30
-
31
- // Prepares both production endpoint directories. The CLI runs it from this
32
- // project before `phresh start`, `phresh install`, and `phresh pack`.
33
- // `phresh dev` does not build and uses the declarations below instead.
34
9
  buildCommand: "vite-node scripts/build.ts",
35
-
36
- // A Process may run its Server and Client independently. This declaration
37
- // says how the Server is prepared and started; it does not merge Server
38
- // code into the browser Client.
39
10
  server: {
40
-
41
- // Production directory containing the Server artifact. The start
42
- // command runs with this directory as its working directory.
43
11
  location: "dist/server",
44
12
  startCommand: "node main.js",
45
-
46
- // An install command is optional and runs inside `location` when the
47
- // Program is installed. This build bundles its Server dependencies, so
48
- // the example does not need one.
49
- // installCommand: "npm install",
50
-
51
- // Declared endpoints start in a default Process unless `start` is
52
- // false. A false value keeps the capability available for an explicit
53
- // Process launch without starting it automatically.
54
- // start: false,
55
-
56
13
  development: {
57
-
58
- // `phresh dev` runs this command from the project directory. The
59
- // project directory becomes the development Server location, so
60
- // source imports work without a production build.
61
14
  startCommand: "vite-node source/server/main.ts"
62
15
  }
63
16
  },
64
-
65
- // The Client declaration also defines the initial Window created for it.
66
- // It contains presentation defaults only; live Window state belongs to
67
- // each running Process.
68
17
  client: {
69
-
70
- // Production directory containing the browser application's
71
- // `index.html` and all files reachable from it.
72
18
  location: "dist/client",
73
-
74
- // Initial Window values. The title defaults to the Program name when
75
- // omitted. This example chooses a fixed initial size while leaving
76
- // placement, layer, and minimized state to their system defaults.
77
19
  title: "Phresh Program",
78
20
  size: { width: 600, height: 500 },
79
-
80
- // Geometry accepts finite pixel numbers or linear values. Fractions
81
- // and percentages are relative to the selected desktop layer, and a
82
- // pixel offset may be combined with either form.
83
- // size: { width: "50% + 20", height: 440 },
84
- // position: { x: "1/2 + 10", y: 40 },
85
-
86
- // `window` is the ordinary framed layer. `under` and `over` are
87
- // structurally isolated, frameless desktop layers.
88
- // layer: "window",
89
-
90
- // The initial Window may also be declared to open minimized.
91
- // minimize: true,
92
-
93
21
  development: {
94
-
95
- // Development Clients are addressed by URL rather than a local
96
- // artifact directory. The CLI starts this optional tool, waits for
97
- // the URL to respond, and only then launches the Program. The dev
98
- // server must allow the desktop origin through CORS; this project's
99
- // Vite configuration does so.
100
22
  url: "http://localhost:5200/",
101
23
  startCommand: "vite dev --config vite.client.ts"
102
24
  }
@@ -1,20 +1,10 @@
1
- import { externalDependencies } from "@/vite.config"
2
- import { writeFile } from "node:fs/promises"
3
- import packageConfig from "@/package.json"
1
+ import { rm, writeFile } from "node:fs/promises"
4
2
 
5
3
  process.env.NODE_ENV = "production"
6
4
 
7
5
  const { build } = await import("vite")
8
6
 
9
- const dependencies: Partial<typeof packageConfig.dependencies> = {}
10
-
11
- for (const externalDependency of externalDependencies) {
12
-
13
- dependencies[externalDependency] = packageConfig.dependencies[externalDependency]
14
- }
15
-
7
+ await rm("dist", { recursive: true, force: true })
16
8
  await build({ configFile: "vite.config.ts", ssr: { noExternal: true } })
17
-
18
9
  await build({ configFile: "vite.client.ts" })
19
-
20
- await writeFile("dist/server/package.json", JSON.stringify({ type: "module", dependencies }))
10
+ await writeFile("dist/server/package.json", JSON.stringify({ type: "module" }))
@@ -1,36 +1,22 @@
1
+ import { current } from "@phreshos/client"
1
2
  import { useSubscribe } from "@phreshos/react"
2
3
  import { useEffect, useState } from "react"
3
- import { current } from "@phreshos/client"
4
-
5
- function Counter() {
6
4
 
5
+ export default function App() {
7
6
  const [count, setCount] = useState<number>()
8
7
 
9
8
  useSubscribe(current.server, "changed", setCount)
10
9
 
11
- useEffect(function () {
12
-
10
+ useEffect(() => {
13
11
  current.server.ask<number>("read").then(setCount)
14
-
15
12
  }, [])
16
13
 
17
- return <main className="counter-card">
18
-
19
- <span className="label">Phresh Program</span>
20
-
14
+ return <main>
15
+ <span>PhreshOS</span>
21
16
  <h1>Server counter</h1>
22
-
23
- <p>The value belongs to the Server and is shared with every Client representation.</p>
24
-
17
+ <p>The Client talks directly to its Process Server.</p>
25
18
  <button type="button" onClick={() => current.server.publish("increment")}>
26
-
27
- count is {count ?? "…"}
28
-
19
+ Count is {count ?? "…"}
29
20
  </button>
30
-
31
21
  </main>
32
22
  }
33
-
34
- export default function App() {
35
- return <Counter />
36
- }
@@ -4,10 +4,10 @@
4
4
  <head>
5
5
  <meta charset="UTF-8" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Phresh Program</title>
7
8
  <script type="module" src="./main.tsx"></script>
8
9
  </head>
9
10
 
10
- <body>
11
- </body>
11
+ <body></body>
12
12
 
13
- </html>
13
+ </html>
@@ -1,6 +1,6 @@
1
- import client from "react-dom/client"
2
1
  import { StrictMode } from "react"
3
- import App from "./view/app"
2
+ import client from "react-dom/client"
3
+ import App from "./app"
4
4
  import "./style.css"
5
5
 
6
6
  const root = client.createRoot(document.body)
@@ -1,38 +1,37 @@
1
1
  :root {
2
2
  color: #20242a;
3
- background: #f3f4f6;
4
- font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
3
+ background: transparent;
4
+ font-family: Inter, ui-sans-serif, system-ui, sans-serif;
5
5
  font-synthesis: none;
6
6
  }
7
7
 
8
- * { box-sizing: border-box; }
9
-
10
- html, body, #root { min-height: 100vh; display: grid; }
11
-
12
- body { margin: 0; }
8
+ * {
9
+ box-sizing: border-box;
10
+ }
13
11
 
14
- button { font: inherit; }
12
+ html,
13
+ body {
14
+ min-height: 100%;
15
+ background: transparent;
16
+ }
15
17
 
16
- #root {
18
+ body {
19
+ margin: 0;
17
20
  min-height: 100vh;
18
21
  display: grid;
19
22
  place-items: center;
20
23
  padding: 1.5rem;
21
24
  }
22
25
 
23
- .counter-card {
26
+ main {
24
27
  width: min(26rem, 100%);
25
- display: grid;
26
- justify-items: start;
27
- gap: 1rem;
28
28
  padding: 2rem;
29
29
  border: 1px solid #d8dce2;
30
30
  border-radius: 0.75rem;
31
31
  background: #ffffff;
32
- margin: auto;
33
32
  }
34
33
 
35
- .label {
34
+ span {
36
35
  color: #646b76;
37
36
  font-size: 0.72rem;
38
37
  font-weight: 700;
@@ -41,21 +40,19 @@ button { font: inherit; }
41
40
  }
42
41
 
43
42
  h1 {
44
- margin: 0;
43
+ margin: 0.75rem 0;
45
44
  font-size: 2rem;
46
45
  line-height: 1.1;
47
- letter-spacing: -0.04em;
48
46
  }
49
47
 
50
48
  p {
51
49
  margin: 0;
52
50
  color: #5f6670;
53
- font-size: 0.95rem;
54
- line-height: 1.55;
51
+ line-height: 1.5;
55
52
  }
56
53
 
57
- .counter-card button {
58
- min-width: 9rem;
54
+ button {
55
+ margin-top: 1.5rem;
59
56
  min-height: 2.75rem;
60
57
  padding: 0.65rem 1rem;
61
58
  border: 0;
@@ -63,19 +60,15 @@ p {
63
60
  color: #ffffff;
64
61
  background: #2563eb;
65
62
  cursor: pointer;
63
+ font: inherit;
66
64
  font-weight: 650;
67
65
  }
68
66
 
69
- .counter-card button:hover { background: #1d4ed8; }
70
-
71
- .counter-card button:active { background: #1e40af; }
72
-
73
- .counter-card button:focus-visible {
74
- outline: 3px solid rgba(37, 99, 235, 0.25);
75
- outline-offset: 2px;
67
+ button:hover {
68
+ background: #1d4ed8;
76
69
  }
77
70
 
78
- .loading {
79
- color: #646b76;
80
- font-size: 0.9rem;
71
+ button:focus-visible {
72
+ outline: 3px solid rgb(37 99 235 / 25%);
73
+ outline-offset: 2px;
81
74
  }
@@ -1,3 +1,10 @@
1
- import view from "./view/view"
1
+ import { current } from "@phreshos/server"
2
2
 
3
- await view()
3
+ let count = 0
4
+
5
+ current.answer("read", () => count)
6
+
7
+ current.subscribe("increment", () => {
8
+ count += 1
9
+ current.publish("changed", count)
10
+ })
@@ -12,17 +12,6 @@
12
12
  "types": [
13
13
  "@types/node",
14
14
  "vite/client"
15
- ],
16
- "paths": {
17
- "@/*": [
18
- "./*"
19
- ],
20
- "@server/*": [
21
- "./source/server/*"
22
- ],
23
- "@client/*": [
24
- "./source/client/*"
25
- ]
26
- }
15
+ ]
27
16
  }
28
17
  }
@@ -1,20 +1,8 @@
1
- import packageConfig from "./package.json" with { type: "json" }
2
1
  import { defineConfig } from "vite"
3
2
  import { resolve } from "node:path"
4
3
 
5
- export const externalDependencies: (keyof typeof packageConfig.dependencies)[] = [
6
-
7
- // Add packages here that should NOT be bundled during server, Example: "sqlite3"
8
- ]
9
-
10
4
  export default defineConfig({
11
5
  root: "source/server",
12
- resolve: {
13
- tsconfigPaths: true
14
- },
15
- ssr: {
16
- external: externalDependencies
17
- },
18
6
  build: {
19
7
  ssr: true,
20
8
  emptyOutDir: true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "repository": "PhreshOS/phresh-program",
3
- "version": "0.1.6",
4
- "sha256": "a56227927522a550ef5dab3eb5127274e23ecd9c0dabb912f8b46f37990a9602",
3
+ "version": "0.1.11",
4
+ "sha256": "70248597565f2e02bb8f8b052758321d92fe54d30ef47e8e1b9347034d4a93b8",
5
5
  "development": true
6
6
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@phreshos/cli",
3
3
  "type": "module",
4
- "version": "0.1.15",
4
+ "version": "0.1.17",
5
5
  "description": "The Phresh command-line interface for Program projects and system management.",
6
6
  "engines": {
7
7
  "node": ">=20.10"
@@ -49,7 +49,7 @@
49
49
  "packageManager": "bun@1.3.14",
50
50
  "dependencies": {
51
51
  "@clack/prompts": "^1.7.0",
52
- "@phreshos/core": "^0.1.4",
52
+ "@phreshos/core": "^0.1.9",
53
53
  "adm-zip": "^0.6.0",
54
54
  "commander": "^15.0.0",
55
55
  "picocolors": "^1.1.1"
@@ -1,44 +0,0 @@
1
- # Counter API
2
-
3
- The `counter` Server service owns one number for the lifetime of its Process.
4
-
5
- | Name | Destination | Interaction | Payload | Answer |
6
- | --- | --- | --- | --- | --- |
7
- | `read` | Server | `ask()` | `undefined` | `number` |
8
- | `increment` | Server | `publish()` | `undefined` | None |
9
- | `changed` | Server | `subscribe()` | `number` | None |
10
-
11
- ## Ask the Server: `read`
12
-
13
- `read` is a question addressed to this Process's Server. It answers with the
14
- current counter value.
15
-
16
- ```ts
17
- const counter = host.service({
18
- program: "phresh-program",
19
- endpoint: "server",
20
- name: "counter"
21
- })
22
-
23
- const count = await counter.channel.ask<number>("read")
24
- ```
25
-
26
- ## Publish to the Server: `increment`
27
-
28
- `increment` is a one-way event addressed to this Process's Server. It adds one
29
- to the counter and does not produce an answer.
30
-
31
- ```ts
32
- counter.channel.publish("increment")
33
- ```
34
-
35
- ## Subscribe to the Server: `changed`
36
-
37
- After an increment, the Server emits `changed` with the new counter value.
38
- Anyone holding that Process's Server can subscribe to the event.
39
-
40
- ```ts
41
- counter.channel.subscribe<number>("changed", count => {
42
- // use the latest count
43
- })
44
- ```
@@ -1,13 +0,0 @@
1
- /** Owns the Program's authoritative counter state without knowing how it is exposed. */
2
- export default class Counter {
3
- private value = 0
4
-
5
- public read() {
6
- return this.value
7
- }
8
-
9
- public increment() {
10
- this.value += 1
11
- return this.value
12
- }
13
- }
@@ -1,16 +0,0 @@
1
- import { current } from "@phreshos/server"
2
- import docs from "@/api-docs.md?raw"
3
- import Counter from "@server/core/counter"
4
-
5
- const counter = new Counter()
6
-
7
- /** Exposes the counter core through this Server endpoint. */
8
- export default async function view() {
9
- current.answer("read", () => counter.read())
10
-
11
- current.subscribe("increment", () => {
12
- current.publish("changed", counter.increment())
13
- })
14
-
15
- await current.enableService({ name: "counter", docs })
16
- }