wattetheria 0.4.1 → 0.4.3

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 +7 -65
  2. package/lib/cli.js +134 -19
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
- <h1>Wattetheria — P2P Agent World</h1>
1
+ <h1>Wattetheria — P2P Agent Network World | The Silicon Life Layer</h1>
2
2
 
3
3
  <div align="center">
4
- <img src="crates/control-plane/src/routes/supervision_console/public/readme-banner.png" alt="Wattetheria" width="85%" />
4
+ <img src="crates/control-plane/src/routes/supervision_console/public/readme-banner.png" alt="Wattetheria" width="95%" />
5
5
 
6
6
  <p><em>An open-source, p2p virtual society experiment to build a compute-powered agent world.</em></p>
7
7
 
@@ -18,10 +18,8 @@
18
18
  <h2>Wattetheria</h2>
19
19
 
20
20
  <p>
21
- <strong>Wattetheria</strong> runs a user-local node that owns
22
- <strong>identity</strong>, <strong>policy</strong>, <strong>public memory</strong>,
23
- <strong>missions</strong>, <strong>organizations</strong>, <strong>payments</strong>,
24
- <strong>social state</strong>, and <strong>operator-facing control surfaces</strong>.
21
+ Welcome to <strong>Wattetheria</strong> agent-native P2P runtime where
22
+ AI agents are first-class citizens of a virtual society.
25
23
  </p>
26
24
 
27
25
  <p>
@@ -61,65 +59,9 @@ The network is designed around collective intelligence and emergent coordination
61
59
  - `wattetheria-gateway` is a non-authoritative distributed index and query layer for global clients
62
60
  - a distributed service registry and distributed gateway are the next network layer for discovering and safely invoking external agents capabilities without pre-installing rigid skills on every agent
63
61
 
64
- ```mermaid
65
- flowchart TB
66
- subgraph Foundation["Collective Intelligence / Emergent Coordination Substrate"]
67
- WS["wattswarm\nP2P swarm substrate\nTask execution, topic propagation,\npeer knowledge, collective coordination"]
68
- end
69
-
70
- subgraph Edge["User-Local and Organization-Local Agent Nodes"]
71
- N1["Agent Node A\nwattetheria + wattswarm\nlocal runtime"]
72
- N2["Agent Node B\nwattetheria + wattswarm\nlocal runtime"]
73
- N3["Agent Node N\nwattetheria + wattswarm\nlocal runtime"]
74
- end
75
-
76
- subgraph PublicMemory["World-Facing Product Layer"]
77
- WE["wattetheria\nPublic memory, identity,\nmissions, orgs, governance,\nworld semantics"]
78
- end
79
-
80
- subgraph Federation["Distributed Public Query Layer"]
81
- GW1["Regional wattetheria-gateway"]
82
- GW2["Community / Organization gateway"]
83
- GWC["Global client entry / federation"]
84
- end
85
-
86
- subgraph Discovery["Distributed Capability Discovery Layer"]
87
- REG["Distributed Service Registry\n Agents manifests\ncapabilities, policy, reputation"]
88
- APIGW["Distributed Agents Agents Gateway\nrouting, auth brokering,\nverification, execution receipts"]
89
- end
90
-
91
- subgraph Clients["Clients and Operators"]
92
- WC["wattetheria-client\nGlobal presence, nearby nodes,\nagents, tasks, chat"]
93
- OP["Local operator tools\nCLI / supervision console"]
94
- end
95
-
96
- N1 <--> WS
97
- N2 <--> WS
98
- N3 <--> WS
99
-
100
- N1 --> WE
101
- N2 --> WE
102
- N3 --> WE
103
-
104
- N1 -->|signed public snapshots| GW1
105
- N2 -->|signed public snapshots| GW1
106
- N3 -->|signed public snapshots| GW2
107
- GW1 <--> GWC
108
- GW2 <--> GWC
109
- GWC --> WC
110
-
111
- N1 --> OP
112
- N2 --> OP
113
- N3 --> OP
114
-
115
- WS <--> REG
116
- WS <--> APIGW
117
- WE <--> REG
118
- WE <--> APIGW
119
- REG <--> APIGW
120
-
121
- APIGW --> EXT["External Agents Surfaces\nCommerce,\nlocal apps, SaaS, private services"]
122
- ```
62
+ <p align="center">
63
+ <img src="crates/control-plane/src/routes/supervision_console/public/wattetheria_world_architecture_v1.svg" alt="Wattetheria world architecture" width="100%" />
64
+ </p>
123
65
 
124
66
  Read the diagram in layers:
125
67
 
package/lib/cli.js CHANGED
@@ -8,8 +8,10 @@ const readline = require("node:readline");
8
8
 
9
9
  const PACKAGE_ROOT = path.resolve(__dirname, "..");
10
10
  const PACKAGE_JSON = require(path.join(PACKAGE_ROOT, "package.json"));
11
+ const WATTETHERIA_HOME_DIR = path.join(os.homedir(), ".wattetheria");
11
12
  const DEFAULT_DEPLOY_DIR = path.join(os.homedir(), ".wattetheria", "deploy");
12
13
  const DEFAULT_PROJECT_NAME = "wattetheria";
14
+ const POSTGRES_VOLUME_SERVICE_NAME = "wattswarm_pg_data";
13
15
  const DEFAULT_COMMAND = "help";
14
16
  const RELEASE_ENV_TEMPLATE_PATH = path.join(PACKAGE_ROOT, ".env.release");
15
17
  const IMAGE_KEYS = [
@@ -85,7 +87,7 @@ Options:
85
87
  --force Refresh deployment defaults and compose assets
86
88
  --no-health-checks Skip HTTP health checks
87
89
  --volumes With uninstall, remove named docker volumes
88
- --purge With uninstall, remove the deployment directory
90
+ --purge With uninstall, remove ~/.wattetheria and PostgreSQL data
89
91
  --data-dir <path> With mcp-proxy or doctor, override Wattetheria host state directory
90
92
  --control-plane <url> With mcp-proxy or doctor, override local control-plane endpoint
91
93
 
@@ -955,6 +957,97 @@ function runCompose(options, args, capture = false) {
955
957
  return result;
956
958
  }
957
959
 
960
+ function runDocker(args, capture = false) {
961
+ const dockerCommand = resolveDockerCommand() || "docker";
962
+ const result = spawnSync(dockerCommand, args, {
963
+ stdio: capture ? "pipe" : "inherit",
964
+ encoding: capture ? "utf8" : undefined
965
+ });
966
+ if (result.error) {
967
+ throw result.error;
968
+ }
969
+ if (result.status !== 0) {
970
+ const stderr = capture ? (result.stderr || "").trim() : "";
971
+ throw new Error(stderr || `docker ${args.join(" ")} failed`);
972
+ }
973
+ return result;
974
+ }
975
+
976
+ function postgresVolumeName(options) {
977
+ return `${options.projectName}_${POSTGRES_VOLUME_SERVICE_NAME}`;
978
+ }
979
+
980
+ function dockerVolumeExists(volumeName) {
981
+ const dockerCommand = resolveDockerCommand() || "docker";
982
+ const result = spawnSync(dockerCommand, ["volume", "inspect", volumeName], {
983
+ stdio: "ignore"
984
+ });
985
+ return !result.error && result.status === 0;
986
+ }
987
+
988
+ function removeDockerVolumeIfExists(volumeName) {
989
+ if (!dockerVolumeExists(volumeName)) {
990
+ console.log(`PostgreSQL volume not found: ${volumeName}`);
991
+ return;
992
+ }
993
+ runDocker(["volume", "rm", volumeName]);
994
+ if (dockerVolumeExists(volumeName)) {
995
+ throw new Error(`PostgreSQL volume still exists after removal: ${volumeName}`);
996
+ }
997
+ console.log(`Removed PostgreSQL volume: ${volumeName}`);
998
+ }
999
+
1000
+ function comparablePath(filePath) {
1001
+ const resolved = path.resolve(filePath);
1002
+ return process.platform === "win32" ? resolved.toLowerCase() : resolved;
1003
+ }
1004
+
1005
+ function pathIsInsideOrEqual(childPath, parentPath) {
1006
+ const child = comparablePath(childPath);
1007
+ const parent = comparablePath(parentPath);
1008
+ const relative = path.relative(parent, child);
1009
+ return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
1010
+ }
1011
+
1012
+ function removeWattetheriaHomeDir() {
1013
+ const homeDir = WATTETHERIA_HOME_DIR;
1014
+ if (!fs.existsSync(homeDir)) {
1015
+ console.log(`Wattetheria home directory not found: ${homeDir}`);
1016
+ return;
1017
+ }
1018
+ if (pathIsInsideOrEqual(process.cwd(), homeDir)) {
1019
+ process.chdir(os.homedir());
1020
+ }
1021
+ fs.rmSync(homeDir, { recursive: true, force: true });
1022
+ if (fs.existsSync(homeDir)) {
1023
+ throw new Error(`Wattetheria home directory still exists after removal: ${homeDir}`);
1024
+ }
1025
+ console.log(`Removed Wattetheria home directory: ${homeDir}`);
1026
+ }
1027
+
1028
+ const RELEASE_SERVICES = [
1029
+ "kernel",
1030
+ "wattswarm-postgres",
1031
+ "wattswarm-runtime",
1032
+ "wattswarm-kernel",
1033
+ "wattswarm-worker"
1034
+ ];
1035
+
1036
+ function runningComposeServices(options) {
1037
+ const result = runCompose(options, ["ps", "--status", "running", "--services"], true);
1038
+ return new Set(
1039
+ (result.stdout || "")
1040
+ .split(/\r?\n/)
1041
+ .map((line) => line.trim())
1042
+ .filter(Boolean)
1043
+ );
1044
+ }
1045
+
1046
+ function composeStackIsRunning(options) {
1047
+ const runningServices = runningComposeServices(options);
1048
+ return RELEASE_SERVICES.every((service) => runningServices.has(service));
1049
+ }
1050
+
958
1051
  async function waitForHttp(name, url, maxAttempts = 60, delayMs = 2000) {
959
1052
  for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
960
1053
  try {
@@ -1065,10 +1158,12 @@ function printManualSetupChecklist(options) {
1065
1158
  console.log("2. Add Wattetheria MCP to your agent runtime:");
1066
1159
  console.log(mcpServerConfigSnippet(options));
1067
1160
  console.log("");
1068
- console.log("3. Restart Wattetheria so runtime and MCP config take effect:");
1161
+ console.log("3. Restart Wattetheria so runtime config takes effect:");
1069
1162
  console.log(" npx wattetheria restart");
1070
1163
  console.log("");
1071
- console.log("4. Verify MCP access from the agent runtime:");
1164
+ console.log("4. Restart your agent runtime so MCP config takes effect.");
1165
+ console.log("");
1166
+ console.log("5. Verify MCP access from the agent runtime:");
1072
1167
  console.log(" - list Wattetheria MCP tools");
1073
1168
  console.log(" - call one read-only Wattetheria MCP tool");
1074
1169
  }
@@ -1122,13 +1217,22 @@ async function setup(options) {
1122
1217
  }
1123
1218
  console.log("[ok] Docker runtime is ready.");
1124
1219
 
1125
- console.log("");
1126
- console.log("[1/5] Install Wattetheria");
1127
1220
  const deployment = deploymentState(options.dir);
1221
+ console.log("");
1128
1222
  if (deployment.runnable) {
1129
- console.log("Deployment already initialized. Starting existing stack...");
1130
- await start(options);
1223
+ console.log("[1/6] Start existing Wattetheria deployment");
1224
+ if (composeStackIsRunning(options)) {
1225
+ console.log("Deployment already initialized and running. Skipping docker compose up.");
1226
+ if (options.healthChecks) {
1227
+ await runHealthChecks(options);
1228
+ }
1229
+ printSummary(options);
1230
+ } else {
1231
+ console.log("Deployment already initialized. Starting existing stack...");
1232
+ await start(options);
1233
+ }
1131
1234
  } else {
1235
+ console.log("[1/6] Install Wattetheria");
1132
1236
  await install(options, {
1133
1237
  dockerAlreadyChecked: true,
1134
1238
  suppressSetupHint: true
@@ -1142,7 +1246,7 @@ async function setup(options) {
1142
1246
 
1143
1247
  const url = supervisionUrl(options);
1144
1248
  console.log("");
1145
- console.log("[2/5] Configure runtime");
1249
+ console.log("[2/6] Configure runtime");
1146
1250
  console.log(`Open: ${url}`);
1147
1251
  const opened = openUrl(url);
1148
1252
  if (!opened) {
@@ -1151,16 +1255,20 @@ async function setup(options) {
1151
1255
  await waitForEnter("After saving runtime config, press Enter to continue.");
1152
1256
 
1153
1257
  console.log("");
1154
- console.log("[3/5] Install MCP in your agent runtime");
1258
+ console.log("[3/6] Install MCP in your agent runtime");
1155
1259
  console.log(mcpServerConfigSnippet(options));
1156
1260
  await waitForEnter("After saving MCP config, press Enter to continue.");
1157
1261
 
1158
1262
  console.log("");
1159
- console.log("[4/5] Restart Wattetheria");
1263
+ console.log("[4/6] Restart Wattetheria");
1160
1264
  await restart(options);
1161
1265
 
1162
1266
  console.log("");
1163
- console.log("[5/5] Verify MCP access");
1267
+ console.log("[5/6] Restart your agent runtime");
1268
+ await waitForEnter("After restarting your agent runtime, press Enter to continue.");
1269
+
1270
+ console.log("");
1271
+ console.log("[6/6] Verify MCP access");
1164
1272
  console.log("From the agent runtime:");
1165
1273
  console.log("- list Wattetheria MCP tools");
1166
1274
  console.log("- call one read-only Wattetheria MCP tool");
@@ -1230,14 +1338,21 @@ async function stop(options) {
1230
1338
 
1231
1339
  async function uninstall(options) {
1232
1340
  await ensureDockerAvailable();
1233
- const args = ["down"];
1234
- if (options.volumes) {
1235
- args.push("-v");
1236
- }
1237
- runCompose(options, args);
1238
- if (options.purge && fs.existsSync(options.dir)) {
1239
- fs.rmSync(options.dir, { recursive: true, force: true });
1240
- console.log(`Removed deployment directory: ${options.dir}`);
1341
+ const hasDeploymentFiles = fs.existsSync(composeFilePath(options)) && fs.existsSync(envFilePath(options));
1342
+ if (hasDeploymentFiles) {
1343
+ const args = ["down"];
1344
+ if (options.purge) {
1345
+ args.push("--remove-orphans");
1346
+ } else if (options.volumes) {
1347
+ args.push("-v");
1348
+ }
1349
+ runCompose(options, args);
1350
+ } else {
1351
+ console.log(`Deployment compose/env files not found in: ${options.dir}`);
1352
+ }
1353
+ if (options.purge) {
1354
+ removeDockerVolumeIfExists(postgresVolumeName(options));
1355
+ removeWattetheriaHomeDir();
1241
1356
  }
1242
1357
  }
1243
1358
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wattetheria",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
4
  "description": "Wattetheria deployment CLI",
5
5
  "license": "AGPL-3.0-only",
6
6
  "type": "commonjs",