wattetheria 0.4.2 → 0.4.4

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/.env.release CHANGED
@@ -44,6 +44,8 @@ WATTETHERIA_BRAIN_BASE_URL=
44
44
  WATTETHERIA_BRAIN_MODEL=
45
45
  WATTETHERIA_BRAIN_API_KEY_ENV=
46
46
  WATTETHERIA_BRAIN_API_KEY=
47
+ WATTETHERIA_BRAIN_RUNTIME_ADAPTER=
48
+ WATTETHERIA_BRAIN_SESSION_HEADER_NAME=
47
49
  WATTETHERIA_SERVICENET_BASE_URL=
48
50
  WATTETHERIA_AUTONOMY_ENABLED=false
49
51
  WATTETHERIA_AUTONOMY_INTERVAL_SEC=30
package/README.md CHANGED
@@ -144,6 +144,28 @@ Agent runtime MCP proxy:
144
144
  npx wattetheria mcp-proxy
145
145
  ```
146
146
 
147
+ Agent runtime adapter:
148
+
149
+ Wattetheria connects each local agent identity to an agent runtime adapter. The
150
+ runtime endpoint still uses an OpenAI-compatible chat completions path, but the
151
+ adapter determines how Wattetheria passes the long-lived identity session into
152
+ the runtime loop.
153
+
154
+ ```text
155
+ Hermes -> X-Hermes-Session-Id
156
+ OpenClaw -> x-openclaw-session-key
157
+ Custom -> configured session header name
158
+ ```
159
+
160
+ The session id is generated deterministically at call time:
161
+
162
+ ```text
163
+ wattetheria:identity:<agent_did>:<network_id>
164
+ ```
165
+
166
+ DM, Hive, Mission, payment, and friend-request ids remain event scope data in
167
+ the brain input. They are not used as runtime sessions.
168
+
147
169
  ServiceNet publishing entry points:
148
170
 
149
171
  ```bash
@@ -38,6 +38,8 @@ services:
38
38
  WATTETHERIA_BRAIN_MODEL: ${WATTETHERIA_BRAIN_MODEL:-}
39
39
  WATTETHERIA_BRAIN_API_KEY_ENV: ${WATTETHERIA_BRAIN_API_KEY_ENV:-}
40
40
  WATTETHERIA_BRAIN_API_KEY: ${WATTETHERIA_BRAIN_API_KEY:-}
41
+ WATTETHERIA_BRAIN_RUNTIME_ADAPTER: ${WATTETHERIA_BRAIN_RUNTIME_ADAPTER:-}
42
+ WATTETHERIA_BRAIN_SESSION_HEADER_NAME: ${WATTETHERIA_BRAIN_SESSION_HEADER_NAME:-}
41
43
  WATTETHERIA_GATEWAY_URLS: ${WATTETHERIA_GATEWAY_URLS:-}
42
44
  WATTETHERIA_GATEWAY_CONFIG_PATH: ${WATTETHERIA_GATEWAY_CONFIG_PATH:-/var/lib/wattswarm/startup_config.json}
43
45
  WATTETHERIA_AUTONOMY_ENABLED: ${WATTETHERIA_AUTONOMY_ENABLED:-false}
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,74 @@ 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
+
958
1028
  const RELEASE_SERVICES = [
959
1029
  "kernel",
960
1030
  "wattswarm-postgres",
@@ -1268,14 +1338,21 @@ async function stop(options) {
1268
1338
 
1269
1339
  async function uninstall(options) {
1270
1340
  await ensureDockerAvailable();
1271
- const args = ["down"];
1272
- if (options.volumes) {
1273
- args.push("-v");
1274
- }
1275
- runCompose(options, args);
1276
- if (options.purge && fs.existsSync(options.dir)) {
1277
- fs.rmSync(options.dir, { recursive: true, force: true });
1278
- 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();
1279
1356
  }
1280
1357
  }
1281
1358
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wattetheria",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "description": "Wattetheria deployment CLI",
5
5
  "license": "AGPL-3.0-only",
6
6
  "type": "commonjs",