@paniolo/cli 0.5.0

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.
Files changed (3) hide show
  1. package/README.md +19 -0
  2. package/bin/paniolo.js +86 -0
  3. package/package.json +23 -0
package/README.md ADDED
@@ -0,0 +1,19 @@
1
+ # @paniolo/cli
2
+
3
+ Internal distribution of the unified native `paniolo` CLI.
4
+
5
+ The wrapper selects one optional per-platform package and launches its bundled
6
+ binary. Commands include `paniolo scan`, `paniolo qmd`, `paniolo wiki`,
7
+ `paniolo evolve`, and `paniolo mcp`.
8
+
9
+ ## Local release workflow
10
+
11
+ ```bash
12
+ node npm/scripts/gen-packages.mjs --tool cli
13
+ node npm/scripts/stage-binaries.mjs --tool cli
14
+ node npm/scripts/pack-smoke.mjs --tool cli
15
+ ```
16
+
17
+ Ranch Hand releases are validated locally. `paniolo-internal` is not included
18
+ in this package family; harness maintenance scripts invoke it from the sibling
19
+ Ranch Hand source checkout.
package/bin/paniolo.js ADDED
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ // Thin launcher for the native paniolo CLI. The binary itself ships in a
5
+ // per-platform optional dependency (@paniolo/cli-<platform>-<arch>); npm only
6
+ // installs the one matching the host's os/cpu. We resolve that package here and
7
+ // exec its binary. No network access, no postinstall — see
8
+ // docs/cross-building.md for how the binaries are produced and published.
9
+
10
+ const fs = require("fs");
11
+ const path = require("path");
12
+ const { spawn } = require("child_process");
13
+
14
+ // npm tarballs packed on Windows lose the Unix executable bit, so a binary
15
+ // published from a Windows machine arrives mode 0644 and fails to spawn with
16
+ // EACCES on Linux/macOS. Restore the bit at runtime (only when missing, and
17
+ // best-effort so a read-only install still surfaces the real spawn error).
18
+ function ensureExecutable(binary) {
19
+ if (process.platform === "win32") {
20
+ return;
21
+ }
22
+ try {
23
+ const { mode } = fs.statSync(binary);
24
+ if ((mode & 0o111) === 0) {
25
+ fs.chmodSync(binary, 0o755);
26
+ }
27
+ } catch {
28
+ // ignore; the spawn below will report a meaningful error if truly broken
29
+ }
30
+ }
31
+
32
+ // The supported platform/arch keys, the platform-package scope, and the binary
33
+ // name are derived from this wrapper's own package.json — its
34
+ // optionalDependencies are the per-platform packages, generated from the single
35
+ // target list in npm/scripts/tools.mjs. So nothing about the target set is
36
+ // duplicated here; adding a platform there flows through on the next generate.
37
+ const wrapperPkg = require("../package.json");
38
+ const PKG_PREFIX = `${wrapperPkg.name}-`; // e.g. "@paniolo/cli-"
39
+ const BIN_NAME = Object.keys(wrapperPkg.bin)[0]; // "paniolo"
40
+ const SUPPORTED = new Set(
41
+ Object.keys(wrapperPkg.optionalDependencies || {}).map((dep) => dep.slice(PKG_PREFIX.length))
42
+ );
43
+
44
+ function resolveBinary() {
45
+ const key = `${process.platform}-${process.arch}`;
46
+ if (!SUPPORTED.has(key)) {
47
+ return { error: `unsupported platform/arch: ${key}` };
48
+ }
49
+
50
+ const pkg = `${PKG_PREFIX}${key}`;
51
+ const exe = process.platform === "win32" ? `${BIN_NAME}.exe` : BIN_NAME;
52
+ try {
53
+ // Resolve via the platform package's manifest so this works regardless of
54
+ // how the binary file is named in `exports`.
55
+ const manifest = require.resolve(`${pkg}/package.json`);
56
+ return { binary: path.join(path.dirname(manifest), exe) };
57
+ } catch {
58
+ return {
59
+ error:
60
+ `the platform package ${pkg} is not installed.\n` +
61
+ `Reinstall ${wrapperPkg.name} with optional dependencies enabled ` +
62
+ `(npm install --include=optional, or remove --no-optional / --omit=optional).`,
63
+ };
64
+ }
65
+ }
66
+
67
+ const resolved = resolveBinary();
68
+ if (resolved.error) {
69
+ process.stderr.write(`${BIN_NAME}: ${resolved.error}\n`);
70
+ process.exit(1);
71
+ }
72
+
73
+ ensureExecutable(resolved.binary);
74
+
75
+ const child = spawn(resolved.binary, process.argv.slice(2), { stdio: "inherit" });
76
+ child.on("error", (error) => {
77
+ process.stderr.write(`${BIN_NAME}: failed to run ${resolved.binary}: ${error.message}\n`);
78
+ process.exit(1);
79
+ });
80
+ child.on("exit", (code, signal) => {
81
+ if (signal !== null) {
82
+ process.kill(process.pid, signal);
83
+ return;
84
+ }
85
+ process.exit(code ?? 0);
86
+ });
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@paniolo/cli",
3
+ "version": "0.5.0",
4
+ "description": "Unified native Paniolo CLI, distributed as per-platform npm packages.",
5
+ "license": "UNLICENSED",
6
+ "bin": {
7
+ "paniolo": "bin/paniolo.js"
8
+ },
9
+ "files": [
10
+ "bin"
11
+ ],
12
+ "engines": {
13
+ "node": ">=18"
14
+ },
15
+ "optionalDependencies": {
16
+ "@paniolo/cli-linux-x64": "0.5.0",
17
+ "@paniolo/cli-linux-arm64": "0.5.0",
18
+ "@paniolo/cli-win32-x64": "0.5.0",
19
+ "@paniolo/cli-win32-arm64": "0.5.0",
20
+ "@paniolo/cli-darwin-x64": "0.5.0",
21
+ "@paniolo/cli-darwin-arm64": "0.5.0"
22
+ }
23
+ }