wattetheria 0.2.8 → 0.2.9

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
@@ -552,6 +552,11 @@ CLI prerequisites:
552
552
 
553
553
  The CLI handles image pull, deployment directory setup, environment generation, container start,
554
554
  and health checks internally.
555
+ Agent commands such as `identity`, `wallet`, `servicenet`, and `publish` are forwarded to the
556
+ platform native `wattetheria-client-cli` bundled under `bin/native/<platform>-<arch>/`; installed
557
+ release packages should not require Rust on the user's machine. Release publishing can stage a
558
+ native CLI binary with `npm run stage:native-cli -- --platform <platform> --arch <arch> --source <path>`.
559
+ `WATTETHERIA_CLI_BIN` remains an advanced override for custom local binaries.
555
560
 
556
561
  Version commands:
557
562
 
package/lib/cli.js CHANGED
@@ -29,6 +29,26 @@ const WINDOWS_DOCKER_CANDIDATES = [
29
29
  "C:\\Program Files\\Docker\\Docker\\resources\\bin\\docker.exe",
30
30
  "C:\\Program Files\\Docker\\cli-plugins\\docker.exe"
31
31
  ];
32
+ const RUST_CLI_BASE_NAME = "wattetheria-client-cli";
33
+ const NATIVE_ARCH_ALIASES = new Map([
34
+ ["x64", "x64"],
35
+ ["arm64", "arm64"]
36
+ ]);
37
+ const BANNER_COMMANDS = new Set([
38
+ "help",
39
+ "install",
40
+ "start",
41
+ "up",
42
+ "update",
43
+ "restart",
44
+ "stop",
45
+ "down",
46
+ "uninstall",
47
+ "doctor"
48
+ ]);
49
+ const ANSI_ORANGE = "\x1b[38;5;166m";
50
+ const ANSI_MUTED = "\x1b[38;5;244m";
51
+ const ANSI_RESET = "\x1b[0m";
32
52
 
33
53
  function printHelp() {
34
54
  console.log(`Wattetheria CLI ${PACKAGE_JSON.version}
@@ -52,7 +72,7 @@ Commands:
52
72
  doctor Check local prerequisites
53
73
  help Show this help
54
74
 
55
- Developer subcommands (forwarded to the local 'wattetheria-client-cli' Rust binary):
75
+ Agent subcommands (forwarded to the bundled native CLI when available):
56
76
  identity init | show | export-seed
57
77
  wallet manage wallet payment accounts
58
78
  servicenet provider register
@@ -485,7 +505,19 @@ function formatCliVersionString() {
485
505
  }
486
506
 
487
507
  function formatBanner(options) {
488
- return `${formatReleaseVersionString(options)} Local agent runtime with swarm sync and external agent reach.`;
508
+ const wordmark = [
509
+ " __ __ _ _ _ _ _ _ ",
510
+ " \\ \\ / /_ _| |_| |_| |__ ___| |_| |__ ___ _ __(_) __ _ ",
511
+ " \\ \\ /\\ / / _` | __| __| '_ \\ / _ \\ __| '_ \\ / _ \\ '__| |/ _` |",
512
+ " \\ V V / (_| | |_| |_| | | | __/ |_| | | | __/ | | | (_| |",
513
+ " \\_/\\_/ \\__,_|\\__|\\__|_| |_|\\___|\\__|_| |_|\\___|_| |_|\\__,_|"
514
+ ].join("\n");
515
+ const subtitle = `${formatReleaseVersionString(options)} - local agent runtime, swarm sync, external agent reach`;
516
+
517
+ if (!supportsBannerColor()) {
518
+ return `${wordmark}\n${subtitle}`;
519
+ }
520
+ return `${ANSI_ORANGE}${wordmark}${ANSI_RESET}\n${ANSI_MUTED}${subtitle}${ANSI_RESET}`;
489
521
  }
490
522
 
491
523
  function formatDockerStatusMessage(status) {
@@ -1170,7 +1202,10 @@ function printImages(options) {
1170
1202
  }
1171
1203
 
1172
1204
  function shouldPrintBanner(command) {
1173
- return !["help", "--help", "-h", "version", "images", "mcp-proxy"].includes(command);
1205
+ return isInteractiveTerminal()
1206
+ && !process.env.CI
1207
+ && !process.env.WATTETHERIA_NO_BANNER
1208
+ && BANNER_COMMANDS.has(command);
1174
1209
  }
1175
1210
 
1176
1211
  function printBanner(options) {
@@ -1178,6 +1213,12 @@ function printBanner(options) {
1178
1213
  console.log("");
1179
1214
  }
1180
1215
 
1216
+ function supportsBannerColor() {
1217
+ return process.stdout.isTTY
1218
+ && !process.env.NO_COLOR
1219
+ && process.env.TERM !== "dumb";
1220
+ }
1221
+
1181
1222
  // Forwarded subcommands delegate verbatim to the local Rust binary
1182
1223
  // `wattetheria-client-cli`. Keep the JS side stupid — no flag parsing here.
1183
1224
  const FORWARDED_SUBCOMMANDS = new Set([
@@ -1187,13 +1228,34 @@ const FORWARDED_SUBCOMMANDS = new Set([
1187
1228
  "publish",
1188
1229
  ]);
1189
1230
 
1231
+ function nativePlatformKey(platform = process.platform, arch = process.arch) {
1232
+ const normalizedArch = NATIVE_ARCH_ALIASES.get(arch);
1233
+ if (!normalizedArch || !["darwin", "linux", "win32"].includes(platform)) {
1234
+ return "";
1235
+ }
1236
+ return `${platform}-${normalizedArch}`;
1237
+ }
1238
+
1239
+ function rustCliBinaryName(platform = process.platform) {
1240
+ return platform === "win32" ? `${RUST_CLI_BASE_NAME}.exe` : RUST_CLI_BASE_NAME;
1241
+ }
1242
+
1243
+ function bundledRustBinaryPath() {
1244
+ const platformKey = nativePlatformKey();
1245
+ if (!platformKey) {
1246
+ return "";
1247
+ }
1248
+ return path.join(PACKAGE_ROOT, "bin", "native", platformKey, rustCliBinaryName());
1249
+ }
1250
+
1190
1251
  function forwardToRustBinary(commandName, rawArgv) {
1191
1252
  // Only the Rust binary name is allowed here. The bare `wattetheria` name
1192
1253
  // resolves to this JS shim on most user PATHs (via the npm bin link), so
1193
1254
  // including it would create an infinite spawn loop.
1194
1255
  const candidates = [
1195
1256
  process.env.WATTETHERIA_CLI_BIN,
1196
- "wattetheria-client-cli",
1257
+ bundledRustBinaryPath(),
1258
+ RUST_CLI_BASE_NAME,
1197
1259
  ].filter(Boolean);
1198
1260
 
1199
1261
  for (const candidate of candidates) {
@@ -1211,10 +1273,11 @@ function forwardToRustBinary(commandName, rawArgv) {
1211
1273
  }
1212
1274
  }
1213
1275
 
1276
+ const platformKey = nativePlatformKey() || `${process.platform}-${process.arch}`;
1214
1277
  throw new Error(
1215
- `Could not find the Rust 'wattetheria-client-cli' binary on PATH. ` +
1216
- `Build it with 'cargo build --release -p wattetheria-client-cli' and ` +
1217
- `add it to your PATH, or set WATTETHERIA_CLI_BIN to its full path.`
1278
+ `Could not find the Wattetheria native CLI for ${platformKey}. ` +
1279
+ `Install a package that includes bin/native/${platformKey}/${rustCliBinaryName()}, ` +
1280
+ `or set WATTETHERIA_CLI_BIN to the full path of ${rustCliBinaryName()}.`
1218
1281
  );
1219
1282
  }
1220
1283
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wattetheria",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
4
4
  "description": "Wattetheria deployment CLI",
5
5
  "license": "Apache-2.0",
6
6
  "type": "commonjs",
@@ -8,6 +8,7 @@
8
8
  "files": [
9
9
  "bin/",
10
10
  "lib/",
11
+ "scripts/stage-native-cli.js",
11
12
  ".env.release",
12
13
  "docker-compose.release.yml",
13
14
  "README.md",
@@ -20,7 +21,8 @@
20
21
  "access": "public"
21
22
  },
22
23
  "scripts": {
23
- "check": "node --check bin/wattetheria.js && node --check lib/cli.js"
24
+ "check": "node --check bin/wattetheria.js && node --check lib/cli.js && node --check scripts/stage-native-cli.js",
25
+ "stage:native-cli": "node scripts/stage-native-cli.js"
24
26
  },
25
27
  "keywords": [
26
28
  "wattetheria",
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require("node:fs");
4
+ const os = require("node:os");
5
+ const path = require("node:path");
6
+
7
+ const ROOT_DIR = path.resolve(__dirname, "..");
8
+ const BASE_NAME = "wattetheria-client-cli";
9
+ const SUPPORTED_PLATFORMS = new Set(["darwin", "linux", "win32"]);
10
+ const SUPPORTED_ARCHES = new Set(["x64", "arm64"]);
11
+
12
+ function parseArgs(argv) {
13
+ const options = {
14
+ platform: process.env.WATTETHERIA_NATIVE_PLATFORM || process.platform,
15
+ arch: process.env.WATTETHERIA_NATIVE_ARCH || process.arch,
16
+ source: process.env.WATTETHERIA_NATIVE_CLI_BIN || "",
17
+ };
18
+
19
+ for (let index = 0; index < argv.length; index += 1) {
20
+ const arg = argv[index];
21
+ if (arg === "--platform") {
22
+ options.platform = requireValue(arg, argv[++index]);
23
+ } else if (arg === "--arch") {
24
+ options.arch = requireValue(arg, argv[++index]);
25
+ } else if (arg === "--source") {
26
+ options.source = requireValue(arg, argv[++index]);
27
+ } else {
28
+ throw new Error(`Unknown option: ${arg}`);
29
+ }
30
+ }
31
+
32
+ return options;
33
+ }
34
+
35
+ function requireValue(flag, value) {
36
+ if (!value || value.startsWith("-")) {
37
+ throw new Error(`Missing value for ${flag}`);
38
+ }
39
+ return value;
40
+ }
41
+
42
+ function binaryName(platform) {
43
+ return platform === "win32" ? `${BASE_NAME}.exe` : BASE_NAME;
44
+ }
45
+
46
+ function defaultSource(platform) {
47
+ return path.join(ROOT_DIR, "target", "release", binaryName(platform));
48
+ }
49
+
50
+ function targetKey(platform, arch) {
51
+ if (!SUPPORTED_PLATFORMS.has(platform)) {
52
+ throw new Error(`Unsupported native CLI platform: ${platform}`);
53
+ }
54
+ if (!SUPPORTED_ARCHES.has(arch)) {
55
+ throw new Error(`Unsupported native CLI arch: ${arch}`);
56
+ }
57
+ return `${platform}-${arch}`;
58
+ }
59
+
60
+ function stageNativeCli(options) {
61
+ const key = targetKey(options.platform, options.arch);
62
+ const source = path.resolve(options.source || defaultSource(options.platform));
63
+ if (!fs.existsSync(source)) {
64
+ throw new Error(
65
+ `Native CLI binary not found at ${source}. Build it first or pass --source.`
66
+ );
67
+ }
68
+
69
+ const targetDir = path.join(ROOT_DIR, "bin", "native", key);
70
+ const target = path.join(targetDir, binaryName(options.platform));
71
+ fs.mkdirSync(targetDir, { recursive: true });
72
+ fs.copyFileSync(source, target);
73
+ if (options.platform !== "win32") {
74
+ fs.chmodSync(target, 0o755);
75
+ }
76
+ console.log(`staged ${target}`);
77
+ }
78
+
79
+ try {
80
+ stageNativeCli(parseArgs(process.argv.slice(2)));
81
+ } catch (error) {
82
+ console.error(error && error.message ? error.message : String(error));
83
+ process.exit(1);
84
+ }