wattetheria 0.4.0 → 0.4.2

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/lib/cli.js CHANGED
@@ -37,6 +37,7 @@ const NATIVE_ARCH_ALIASES = new Map([
37
37
  ]);
38
38
  const BANNER_COMMANDS = new Set([
39
39
  "help",
40
+ "setup",
40
41
  "install",
41
42
  "start",
42
43
  "up",
@@ -55,11 +56,13 @@ function printHelp() {
55
56
 
56
57
  Usage:
57
58
  npx wattetheria [command] [options]
59
+ npx wattetheria setup
58
60
  npx wattetheria install
59
61
 
60
62
  Commands:
61
63
  version Show Wattetheria release version
62
64
  images Show configured release images
65
+ setup Install the local stack and finish first-time runtime/MCP setup
63
66
  install Prepare deployment, pull images, and start the stack
64
67
  start Start an existing deployment
65
68
  status Show docker compose status
@@ -952,6 +955,29 @@ function runCompose(options, args, capture = false) {
952
955
  return result;
953
956
  }
954
957
 
958
+ const RELEASE_SERVICES = [
959
+ "kernel",
960
+ "wattswarm-postgres",
961
+ "wattswarm-runtime",
962
+ "wattswarm-kernel",
963
+ "wattswarm-worker"
964
+ ];
965
+
966
+ function runningComposeServices(options) {
967
+ const result = runCompose(options, ["ps", "--status", "running", "--services"], true);
968
+ return new Set(
969
+ (result.stdout || "")
970
+ .split(/\r?\n/)
971
+ .map((line) => line.trim())
972
+ .filter(Boolean)
973
+ );
974
+ }
975
+
976
+ function composeStackIsRunning(options) {
977
+ const runningServices = runningComposeServices(options);
978
+ return RELEASE_SERVICES.every((service) => runningServices.has(service));
979
+ }
980
+
955
981
  async function waitForHttp(name, url, maxAttempts = 60, delayMs = 2000) {
956
982
  for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
957
983
  try {
@@ -1025,8 +1051,69 @@ function printSummary(options) {
1025
1051
  console.log(`Deploy dir: ${options.dir}`);
1026
1052
  }
1027
1053
 
1028
- async function install(options) {
1029
- await ensureDockerAvailable({ interactive: true });
1054
+ function supervisionUrl(options) {
1055
+ const envMap = readEnvFile(envFilePath(options));
1056
+ const kernelHost = getEnvValue(envMap, "WATTETHERIA_CONTROL_PLANE_BIND_HOST", "127.0.0.1");
1057
+ const kernelPort = getEnvValue(envMap, "WATTETHERIA_CONTROL_PLANE_PORT", "7777");
1058
+ return `http://${kernelHost}:${kernelPort}/supervision`;
1059
+ }
1060
+
1061
+ function mcpServerConfigSnippet(options) {
1062
+ const args = ["wattetheria", "mcp-proxy"];
1063
+ if (path.resolve(options.dir) !== path.resolve(DEFAULT_DEPLOY_DIR)) {
1064
+ args.push("--dir", options.dir);
1065
+ }
1066
+ return JSON.stringify({
1067
+ mcpServers: {
1068
+ wattetheria: {
1069
+ command: "npx",
1070
+ args
1071
+ }
1072
+ }
1073
+ }, null, 2);
1074
+ }
1075
+
1076
+ function printSetupHint() {
1077
+ console.log("");
1078
+ console.log("To finish first-time setup, run:");
1079
+ console.log(" npx wattetheria setup");
1080
+ }
1081
+
1082
+ function printManualSetupChecklist(options) {
1083
+ console.log("");
1084
+ console.log("Finish setup:");
1085
+ console.log("1. Open Supervision and configure the runtime:");
1086
+ console.log(` ${supervisionUrl(options)}`);
1087
+ console.log("");
1088
+ console.log("2. Add Wattetheria MCP to your agent runtime:");
1089
+ console.log(mcpServerConfigSnippet(options));
1090
+ console.log("");
1091
+ console.log("3. Restart Wattetheria so runtime config takes effect:");
1092
+ console.log(" npx wattetheria restart");
1093
+ console.log("");
1094
+ console.log("4. Restart your agent runtime so MCP config takes effect.");
1095
+ console.log("");
1096
+ console.log("5. Verify MCP access from the agent runtime:");
1097
+ console.log(" - list Wattetheria MCP tools");
1098
+ console.log(" - call one read-only Wattetheria MCP tool");
1099
+ }
1100
+
1101
+ async function waitForEnter(message) {
1102
+ const rl = createInterface({
1103
+ input: process.stdin,
1104
+ output: process.stdout
1105
+ });
1106
+ try {
1107
+ await rl.question(message);
1108
+ } finally {
1109
+ rl.close();
1110
+ }
1111
+ }
1112
+
1113
+ async function install(options, behavior = {}) {
1114
+ if (!behavior.dockerAlreadyChecked) {
1115
+ await ensureDockerAvailable({ interactive: true });
1116
+ }
1030
1117
  ensureDeploymentAssets(options);
1031
1118
  if (options.tag) {
1032
1119
  console.log(`Pinning release images to requested tag ${options.tag}.`);
@@ -1042,6 +1129,83 @@ async function install(options) {
1042
1129
  await runHealthChecks(options);
1043
1130
  }
1044
1131
  printSummary(options);
1132
+ if (!behavior.suppressSetupHint) {
1133
+ printSetupHint();
1134
+ }
1135
+ }
1136
+
1137
+ async function setup(options) {
1138
+ console.log("Checking Docker runtime...");
1139
+ const dockerStatus = getDockerStatus();
1140
+ if (!dockerStatus.ready) {
1141
+ throw new Error([
1142
+ formatDockerStatusMessage(dockerStatus),
1143
+ "",
1144
+ "Install Docker, start it, then rerun:",
1145
+ " npx wattetheria setup"
1146
+ ].join("\n"));
1147
+ }
1148
+ console.log("[ok] Docker runtime is ready.");
1149
+
1150
+ const deployment = deploymentState(options.dir);
1151
+ console.log("");
1152
+ if (deployment.runnable) {
1153
+ console.log("[1/6] Start existing Wattetheria deployment");
1154
+ if (composeStackIsRunning(options)) {
1155
+ console.log("Deployment already initialized and running. Skipping docker compose up.");
1156
+ if (options.healthChecks) {
1157
+ await runHealthChecks(options);
1158
+ }
1159
+ printSummary(options);
1160
+ } else {
1161
+ console.log("Deployment already initialized. Starting existing stack...");
1162
+ await start(options);
1163
+ }
1164
+ } else {
1165
+ console.log("[1/6] Install Wattetheria");
1166
+ await install(options, {
1167
+ dockerAlreadyChecked: true,
1168
+ suppressSetupHint: true
1169
+ });
1170
+ }
1171
+
1172
+ if (!isInteractiveTerminal()) {
1173
+ printManualSetupChecklist(options);
1174
+ return;
1175
+ }
1176
+
1177
+ const url = supervisionUrl(options);
1178
+ console.log("");
1179
+ console.log("[2/6] Configure runtime");
1180
+ console.log(`Open: ${url}`);
1181
+ const opened = openUrl(url);
1182
+ if (!opened) {
1183
+ console.log("Open the URL above in your browser.");
1184
+ }
1185
+ await waitForEnter("After saving runtime config, press Enter to continue.");
1186
+
1187
+ console.log("");
1188
+ console.log("[3/6] Install MCP in your agent runtime");
1189
+ console.log(mcpServerConfigSnippet(options));
1190
+ await waitForEnter("After saving MCP config, press Enter to continue.");
1191
+
1192
+ console.log("");
1193
+ console.log("[4/6] Restart Wattetheria");
1194
+ await restart(options);
1195
+
1196
+ console.log("");
1197
+ console.log("[5/6] Restart your agent runtime");
1198
+ await waitForEnter("After restarting your agent runtime, press Enter to continue.");
1199
+
1200
+ console.log("");
1201
+ console.log("[6/6] Verify MCP access");
1202
+ console.log("From the agent runtime:");
1203
+ console.log("- list Wattetheria MCP tools");
1204
+ console.log("- call one read-only Wattetheria MCP tool");
1205
+ await waitForEnter("After verifying MCP access, press Enter to finish.");
1206
+
1207
+ console.log("");
1208
+ console.log("Setup complete.");
1045
1209
  }
1046
1210
 
1047
1211
  async function start(options) {
@@ -1681,6 +1845,9 @@ async function run(argv) {
1681
1845
  case "images":
1682
1846
  printImages(options);
1683
1847
  return;
1848
+ case "setup":
1849
+ await setup(options);
1850
+ return;
1684
1851
  case "install":
1685
1852
  await install(options);
1686
1853
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wattetheria",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "Wattetheria deployment CLI",
5
5
  "license": "AGPL-3.0-only",
6
6
  "type": "commonjs",