@phreshos/cli 0.1.20 → 0.1.21
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 +24 -4
- package/dist/derive.js +4 -0
- package/dist/pack.js +13 -4
- package/dist/program-command-output.js +8 -0
- package/dist/program-installation.js +4 -1
- package/dist/project.js +19 -1
- package/dist/template/metadata.json +11 -0
- package/dist/template/package.json +2 -2
- package/dist/template/phresh.config.ts +1 -1
- package/dist/template.json +2 -2
- package/dist/uninstall.js +3 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -156,6 +156,12 @@ export default defineConfig({
|
|
|
156
156
|
|
|
157
157
|
icon: "icon.png",
|
|
158
158
|
|
|
159
|
+
categories: ["Utilities"],
|
|
160
|
+
|
|
161
|
+
keywords: ["files", "storage"],
|
|
162
|
+
|
|
163
|
+
website: "https://example.com/file-manager",
|
|
164
|
+
|
|
159
165
|
buildCommand: "bun run build",
|
|
160
166
|
|
|
161
167
|
server: {
|
|
@@ -164,6 +170,8 @@ export default defineConfig({
|
|
|
164
170
|
|
|
165
171
|
installCommand: "npm ci",
|
|
166
172
|
|
|
173
|
+
uninstallCommand: "npm run clean:external",
|
|
174
|
+
|
|
167
175
|
startCommand: "node main.js",
|
|
168
176
|
|
|
169
177
|
development: {
|
|
@@ -368,6 +376,10 @@ The command installs through the machine's local intake. A running
|
|
|
368
376
|
Program may also install itself through the server SDK; installation is not a
|
|
369
377
|
client capability.
|
|
370
378
|
|
|
379
|
+
When a Server declares `installCommand`, `phresh install` writes that command's
|
|
380
|
+
`stdout` and `stderr` chunks as the System emits them. The final installed
|
|
381
|
+
confirmation appears only after the output stream completes successfully.
|
|
382
|
+
|
|
371
383
|
That is also why it names **paths** rather than sending bytes: install
|
|
372
384
|
used to want an upload because the installer was a browser, which has
|
|
373
385
|
bytes and no path. You have the paths.
|
|
@@ -384,13 +396,19 @@ running Processes, stored data, and runtime Program. `--everything` explicitly
|
|
|
384
396
|
ends those Processes, removes everything the system owns for the Program, and
|
|
385
397
|
forgets its runtime record.
|
|
386
398
|
|
|
399
|
+
When the installed Server declares `uninstallCommand`, the System runs it from
|
|
400
|
+
that Server directory before removing files. `phresh uninstall` writes its
|
|
401
|
+
ordered `stdout` and `stderr` chunks as they arrive. A failed cleanup command
|
|
402
|
+
aborts removal and reports the failure.
|
|
403
|
+
|
|
387
404
|
The identity comes from this project's `phresh.config.ts`; the command does not
|
|
388
405
|
accept an arbitrary Program identity.
|
|
389
406
|
|
|
390
407
|
## What pack produces
|
|
391
408
|
|
|
392
|
-
`pack` takes what is at each half's `location` and writes
|
|
393
|
-
`<identity>@<version>.zip`.
|
|
409
|
+
`pack` takes what is at each half's `location` and writes both `program.json`
|
|
410
|
+
and `<identity>@<version>.zip`. The exact generated declaration is also stored
|
|
411
|
+
inside the archive. Your program may leave its halves anywhere; the
|
|
394
412
|
package always keeps them in the same places, so the artifact's shape
|
|
395
413
|
belongs to the contract rather than to your project. That is why the
|
|
396
414
|
`program.json` it writes names `server` and `client` explicitly — those
|
|
@@ -405,5 +423,7 @@ An authored agent document may use any project-relative path, while packaging
|
|
|
405
423
|
normalizes it to `agent.md`.
|
|
406
424
|
|
|
407
425
|
Nothing about the system moves because this exists. `program.json` is
|
|
408
|
-
still the only
|
|
409
|
-
|
|
426
|
+
still the only declaration the system and release catalog read. Root
|
|
427
|
+
`categories`, `keywords`, and `website` values are optional and cross into it
|
|
428
|
+
without affecting execution. The file is generated output; `phresh.config.ts`
|
|
429
|
+
remains the authored source.
|
package/dist/derive.js
CHANGED
|
@@ -27,6 +27,9 @@ export default function derive(config, directory, which) {
|
|
|
27
27
|
name: config.name,
|
|
28
28
|
version: config.version,
|
|
29
29
|
description: config.description,
|
|
30
|
+
categories: config.categories,
|
|
31
|
+
keywords: config.keywords,
|
|
32
|
+
website: config.website,
|
|
30
33
|
// Where it already is. Unlike pack, which gives it its canonical
|
|
31
34
|
// name, this points into the authoring tree and leaves it alone.
|
|
32
35
|
icon: config.icon && resolve(directory, config.icon),
|
|
@@ -41,6 +44,7 @@ export default function derive(config, directory, which) {
|
|
|
41
44
|
location: resolve(directory, server.location),
|
|
42
45
|
start: server.start,
|
|
43
46
|
installCommand: config.server?.installCommand,
|
|
47
|
+
uninstallCommand: config.server?.uninstallCommand,
|
|
44
48
|
startCommand: server.startCommand
|
|
45
49
|
} },
|
|
46
50
|
// A URL stands as written; a directory is made absolute. The
|
package/dist/pack.js
CHANGED
|
@@ -24,8 +24,9 @@ import build from "./build-command.js";
|
|
|
24
24
|
* The archive itself therefore needs no second naming layer.
|
|
25
25
|
*
|
|
26
26
|
* The files go into the archive directly rather than through a staging
|
|
27
|
-
* directory: a copy of a build is a thing that can be stale
|
|
28
|
-
*
|
|
27
|
+
* directory: a copy of a build is a thing that can be stale. The generated
|
|
28
|
+
* standalone program.json is also placed beside the archive for release
|
|
29
|
+
* discovery; both declarations are made from the same bytes.
|
|
29
30
|
*/
|
|
30
31
|
export default async function pack(directory = process.cwd()) {
|
|
31
32
|
const config = await readConfig(directory);
|
|
@@ -47,7 +48,12 @@ export default async function pack(directory = process.cwd()) {
|
|
|
47
48
|
file(zip, directory, config.icon, "icon.png", "Program icon");
|
|
48
49
|
if (config.agent)
|
|
49
50
|
file(zip, directory, config.agent, "agent.md", "Program agent documentation");
|
|
50
|
-
|
|
51
|
+
const declaration = Buffer.from(JSON.stringify(program(config, version), null, 4) + "\n");
|
|
52
|
+
zip.addFile("program.json", declaration);
|
|
53
|
+
// The standalone release declaration and the declaration inside the
|
|
54
|
+
// archive are the same bytes. There is no separately authored catalog
|
|
55
|
+
// description that can drift from the installable Program.
|
|
56
|
+
writeFileSync(resolve(directory, "program.json"), declaration);
|
|
51
57
|
const archive = `${config.identity}@${version ?? "0.0.0"}.zip`;
|
|
52
58
|
const bytes = zip.toBuffer();
|
|
53
59
|
writeFileSync(resolve(directory, archive), bytes);
|
|
@@ -67,7 +73,10 @@ function program(config, version) {
|
|
|
67
73
|
description: config.description,
|
|
68
74
|
icon: config.icon ? "icon.png" : undefined,
|
|
69
75
|
agent: config.agent ? "agent.md" : undefined,
|
|
70
|
-
|
|
76
|
+
categories: config.categories,
|
|
77
|
+
keywords: config.keywords,
|
|
78
|
+
website: config.website,
|
|
79
|
+
...config.server && { server: { location: "server", start: config.server.start, installCommand: config.server.installCommand, uninstallCommand: config.server.uninstallCommand, startCommand: config.server.startCommand } },
|
|
71
80
|
...config.client && { client: { location: "client", start: config.client.start, title: config.client.title, size: config.client.size, position: config.client.position, layer: config.client.layer, minimize: config.client.minimize } }
|
|
72
81
|
};
|
|
73
82
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Writes one validated Program lifecycle-command output event verbatim. */
|
|
2
|
+
export default function writeProgramCommandOutput(event) {
|
|
3
|
+
if ((event.stream !== "stdout" && event.stream !== "stderr") || typeof event.text !== "string") {
|
|
4
|
+
throw new Error("The System returned an invalid Program command output chunk");
|
|
5
|
+
}
|
|
6
|
+
const output = event.stream === "stderr" ? process.stderr : process.stdout;
|
|
7
|
+
output.write(event.text);
|
|
8
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import speak from "./program-intake.js";
|
|
2
|
+
import writeProgramCommandOutput from "./program-command-output.js";
|
|
2
3
|
/** Install one prepared Program and await every explicitly requested outcome. */
|
|
3
4
|
export default async function installProgram(program, options = {}) {
|
|
4
5
|
let installedValue;
|
|
@@ -11,7 +12,9 @@ export default async function installProgram(program, options = {}) {
|
|
|
11
12
|
run: options.run === true,
|
|
12
13
|
startup: options.startup === true
|
|
13
14
|
}, function (event) {
|
|
14
|
-
if (event.event === "
|
|
15
|
+
if (event.event === "output")
|
|
16
|
+
writeProgramCommandOutput(event);
|
|
17
|
+
else if (event.event === "installed") {
|
|
15
18
|
installedValue = event.program;
|
|
16
19
|
replaced = event.replaced === true;
|
|
17
20
|
}
|
package/dist/project.js
CHANGED
|
@@ -39,12 +39,28 @@ function coherent(config) {
|
|
|
39
39
|
throw new Error("A program's identity is kebab-case, because it is also the name of its directory");
|
|
40
40
|
if (!config.server && !config.client)
|
|
41
41
|
throw new Error("A program must have a server half, a client half, or both");
|
|
42
|
-
for (const field of ["name", "version", "description", "icon", "agent"]) {
|
|
42
|
+
for (const field of ["name", "version", "description", "icon", "agent", "website"]) {
|
|
43
43
|
if (config[field] !== undefined && typeof config[field] !== "string")
|
|
44
44
|
throw new Error(`A program's ${field} must be text`);
|
|
45
45
|
}
|
|
46
46
|
if (config.agent !== undefined && config.agent.trim().length === 0)
|
|
47
47
|
throw new Error("A program's agent documentation must be a non-empty path");
|
|
48
|
+
if (config.website !== undefined) {
|
|
49
|
+
try {
|
|
50
|
+
new URL(config.website);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
throw new Error("A program's website must be a valid URL");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
for (const [field, maximum] of [["categories", 20], ["keywords", 50]]) {
|
|
57
|
+
const values = config[field];
|
|
58
|
+
if (values === undefined)
|
|
59
|
+
continue;
|
|
60
|
+
if (!Array.isArray(values) || values.length > maximum || values.some(value => typeof value !== "string" || value.trim().length === 0 || value.trim().length > 50)) {
|
|
61
|
+
throw new Error(`A program's ${field} must contain at most ${maximum} non-empty values of at most 50 characters`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
48
64
|
if (config.buildCommand !== undefined && (typeof config.buildCommand !== "string" || config.buildCommand.trim().length === 0))
|
|
49
65
|
throw new Error("A program's buildCommand must be non-empty text");
|
|
50
66
|
for (const half of ["server", "client"]) {
|
|
@@ -64,6 +80,8 @@ function coherent(config) {
|
|
|
64
80
|
throw new Error("A server half must say what starts it");
|
|
65
81
|
if (config.server?.installCommand !== undefined && typeof config.server.installCommand !== "string")
|
|
66
82
|
throw new Error("A server half's install command must be text");
|
|
83
|
+
if (config.server?.uninstallCommand !== undefined && typeof config.server.uninstallCommand !== "string")
|
|
84
|
+
throw new Error("A server half's uninstall command must be text");
|
|
67
85
|
if (config.client?.title !== undefined && typeof config.client.title !== "string")
|
|
68
86
|
throw new Error("A client half's title must be text");
|
|
69
87
|
if (config.client?.minimize !== undefined && typeof config.client.minimize !== "boolean")
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": 1,
|
|
3
|
+
"identity": "phresh",
|
|
4
|
+
"version": "0.1.13",
|
|
5
|
+
"name": "Phresh Program",
|
|
6
|
+
"description": "A minimal Client and Server Program for exploring PhreshOS development.",
|
|
7
|
+
"icon": "icon.png",
|
|
8
|
+
"categories": ["Development"],
|
|
9
|
+
"keywords": ["example", "counter", "client", "server"],
|
|
10
|
+
"website": "https://github.com/PhreshOS/phresh-program"
|
|
11
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "phresh",
|
|
3
3
|
"private": true,
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.13",
|
|
5
5
|
"description": "The official PhreshOS starter Program.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"scripts": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"react-dom": "^19.2.8"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@phreshos/cli": "^0.1.
|
|
25
|
+
"@phreshos/cli": "^0.1.21",
|
|
26
26
|
"@types/node": "^26.2.0",
|
|
27
27
|
"@types/react": "^19.2.18",
|
|
28
28
|
"@types/react-dom": "^19.2.4",
|
|
@@ -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.
|
|
7
|
+
version: "0.1.13",
|
|
8
8
|
icon: "icon.png",
|
|
9
9
|
buildCommand: "vite-node scripts/build.ts",
|
|
10
10
|
server: {
|
package/dist/template.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"repository": "PhreshOS/phresh-program",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"sha256": "
|
|
3
|
+
"version": "0.1.13",
|
|
4
|
+
"sha256": "c55ff8129295c9c90b7a78fef8689fef6e0d180c7a284fdb180127700b74fcb0",
|
|
5
5
|
"development": true
|
|
6
6
|
}
|
package/dist/uninstall.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { readConfig } from "./project.js";
|
|
2
2
|
import { dim, heading } from "./style.js";
|
|
3
3
|
import speak from "./program-intake.js";
|
|
4
|
+
import writeProgramCommandOutput from "./program-command-output.js";
|
|
4
5
|
/** Uninstall the Program declared by the current project. */
|
|
5
6
|
export default async function uninstall(everything = false, directory = process.cwd()) {
|
|
6
7
|
const config = await readConfig(directory);
|
|
7
8
|
await speak({ word: "uninstall", identity: config.identity, everything }, function (event) {
|
|
9
|
+
if (event.event === "output")
|
|
10
|
+
return writeProgramCommandOutput(event);
|
|
8
11
|
if (event.event !== "uninstalled")
|
|
9
12
|
return;
|
|
10
13
|
heading(config.name ?? config.identity, "uninstalled");
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phreshos/cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.21",
|
|
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.
|
|
52
|
+
"@phreshos/core": "^0.1.13",
|
|
53
53
|
"adm-zip": "^0.6.0",
|
|
54
54
|
"commander": "^15.0.0",
|
|
55
55
|
"picocolors": "^1.1.1"
|