hovclaw 0.1.2 → 0.1.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.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  <h1 align="center">HOVClaw</h1>
2
2
 
3
3
  <p align="center">
4
- <strong>Lean self-hosted AI agent gateway with OpenClaw-compatible control surface</strong>
4
+ <strong>Lean self-hosted AI agent gateway</strong>
5
5
  </p>
6
6
 
7
7
  <p align="center">
@@ -20,7 +20,6 @@ HOVClaw is built on a simple principle: **run your own AI agent infrastructure,
20
20
 
21
21
  - **Self-hosted first** - Everything runs on your machine, no cloud dependency
22
22
  - **Channel-native** - Talk to your agent via Telegram or Discord, not a custom app
23
- - **OpenClaw-compatible** - Mirror config to `~/.openclaw` for ClawHub discovery and tooling interop
24
23
  - **Gateway-first control** - WebSocket protocol v3 for programmatic access, with a built-in web UI for quick ops
25
24
 
26
25
  ## Features
@@ -59,12 +58,6 @@ HOVClaw is built on a simple principle: **run your own AI agent infrastructure,
59
58
  - **Channel notifications** - Scheduled job results delivered to Telegram or Discord
60
59
  - **Concurrent execution** - Configurable max concurrent jobs
61
60
 
62
- ### OpenClaw Compatibility
63
-
64
- - **Mirror strategy** - HOVClaw is source of truth; mirror files written to `~/.openclaw`
65
- - **ClawHub discovery** - `~/.openclaw/openclaw.json` + `~/.openclaw/skills` symlink
66
- - **Compat CLI** - `hovclaw compat status --sync` to verify mirror state
67
-
68
61
  ## Installation
69
62
 
70
63
  ### Prerequisites
@@ -252,8 +245,6 @@ hovclaw gateway open-ui
252
245
  # Daemon
253
246
  hovclaw daemon install|uninstall|start|stop|restart|status|logs
254
247
 
255
- # Compatibility
256
- hovclaw compat status [--sync] [--json]
257
248
  ```
258
249
 
259
250
  ## Gateway Methods (v3)
@@ -148,7 +148,7 @@ function runDoctorChecks(options, env = process.env) {
148
148
  } else addFinding(findings, "telegram-webhook-secret", "fail", "Telegram webhook secret missing", `Accounts: ${webhookAccountsMissingSecret.join(", ")}`);
149
149
  else addFinding(findings, "telegram-webhook-secret", "pass", "Telegram webhook secret policy", "OK");
150
150
  }
151
- if (!loadedConfig.gateway.enabled) addFinding(findings, "gateway-enabled", "warn", "Gateway is disabled", "Enable gateway for OpenClaw/ClawHub compatibility.");
151
+ if (!loadedConfig.gateway.enabled) addFinding(findings, "gateway-enabled", "warn", "Gateway is disabled", "Enable gateway for gateway RPC and built-in web UI access.");
152
152
  else addFinding(findings, "gateway-enabled", "pass", "Gateway enabled", "OK");
153
153
  if (loadedConfig.gateway.auth.allowUnauthenticated) addFinding(findings, "gateway-auth-mode", "warn", "Gateway unauthenticated mode is enabled", "Set gateway.auth.allowUnauthenticated=false for secure deployments.");
154
154
  else if (!loadedConfig.gateway.auth.token.trim() && !loadedConfig.gateway.auth.password.trim()) if (options.repair) {
package/dist/hovclaw.js CHANGED
@@ -4,11 +4,11 @@ import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { log } from "@clack/prompts";
6
6
  import { Command } from "commander";
7
+ import crypto, { randomUUID, timingSafeEqual } from "node:crypto";
8
+ import WebSocket from "ws";
7
9
  import os from "node:os";
8
10
  import dotenv from "dotenv";
9
11
  import { z } from "zod";
10
- import crypto, { randomUUID, timingSafeEqual } from "node:crypto";
11
- import WebSocket from "ws";
12
12
  import fs$1 from "node:fs/promises";
13
13
  import { Agent } from "@mariozechner/pi-agent-core";
14
14
  import { Type, getModel, getOAuthApiKey, getProviders } from "@mariozechner/pi-ai";
@@ -39,132 +39,6 @@ var __exportAll = (all, no_symbols) => {
39
39
  return target;
40
40
  };
41
41
 
42
- //#endregion
43
- //#region src/compat/openclaw-mirror.ts
44
- function resolveOpenClawHome(env = process.env) {
45
- const override = env.OPENCLAW_STATE_DIR?.trim();
46
- if (override) return path.resolve(override.startsWith("~") ? path.join(os.homedir(), override.slice(1)) : override);
47
- return path.join(os.homedir(), ".openclaw");
48
- }
49
- function resolveOpenClawConfigPath(openclawHome) {
50
- return path.join(openclawHome, "openclaw.json");
51
- }
52
- function resolveOpenClawSharedSkillsPath(openclawHome) {
53
- return path.join(openclawHome, "skills");
54
- }
55
- function readJsonIfExists(filePath) {
56
- if (!fs.existsSync(filePath)) return null;
57
- try {
58
- return JSON.parse(fs.readFileSync(filePath, "utf8"));
59
- } catch {
60
- return null;
61
- }
62
- }
63
- function buildMirrorConfig(config) {
64
- const fallbackWorkspace = config.agents.defaults.workspace || path.join(config.hovclawHome, "workspace");
65
- const agentList = config.agents.list.length > 0 ? config.agents.list : [{
66
- id: "main",
67
- name: "Main",
68
- workspace: fallbackWorkspace,
69
- default: true
70
- }];
71
- const extraDirs = /* @__PURE__ */ new Set();
72
- extraDirs.add(config.skillsDir);
73
- for (const agent of agentList) {
74
- const workspace = (agent.workspace || fallbackWorkspace).trim();
75
- if (!workspace) continue;
76
- extraDirs.add(path.join(workspace, "skills"));
77
- }
78
- return {
79
- agent: { workspace: fallbackWorkspace },
80
- agents: {
81
- defaults: { workspace: fallbackWorkspace },
82
- list: agentList
83
- },
84
- skills: { load: { extraDirs: Array.from(extraDirs) } }
85
- };
86
- }
87
- function ensureDir(dirPath) {
88
- fs.mkdirSync(dirPath, {
89
- recursive: true,
90
- mode: 448
91
- });
92
- }
93
- function syncSkillsDir(sharedSkillsPath, sourceSkillsPath) {
94
- if (!fs.existsSync(sourceSkillsPath)) {
95
- ensureDir(sharedSkillsPath);
96
- return false;
97
- }
98
- try {
99
- if (fs.lstatSync(sharedSkillsPath).isSymbolicLink()) {
100
- const linkTarget = fs.readlinkSync(sharedSkillsPath);
101
- if (path.resolve(path.dirname(sharedSkillsPath), linkTarget) === sourceSkillsPath) return true;
102
- fs.unlinkSync(sharedSkillsPath);
103
- }
104
- } catch {}
105
- if (!fs.existsSync(sharedSkillsPath)) try {
106
- fs.symlinkSync(sourceSkillsPath, sharedSkillsPath, "dir");
107
- return true;
108
- } catch {}
109
- ensureDir(sharedSkillsPath);
110
- for (const entry of fs.readdirSync(sourceSkillsPath, { withFileTypes: true })) {
111
- const src = path.join(sourceSkillsPath, entry.name);
112
- const dst = path.join(sharedSkillsPath, entry.name);
113
- if (entry.isDirectory()) {
114
- fs.cpSync(src, dst, {
115
- recursive: true,
116
- force: true
117
- });
118
- continue;
119
- }
120
- if (entry.isFile()) fs.copyFileSync(src, dst);
121
- }
122
- return false;
123
- }
124
- function writeOpenClawMirror(config) {
125
- const openclawHome = resolveOpenClawHome();
126
- const configPath = resolveOpenClawConfigPath(openclawHome);
127
- const sharedSkillsPath = resolveOpenClawSharedSkillsPath(openclawHome);
128
- ensureDir(openclawHome);
129
- const mirrorConfig = buildMirrorConfig(config);
130
- fs.writeFileSync(configPath, `${JSON.stringify(mirrorConfig, null, 2)}\n`, {
131
- encoding: "utf8",
132
- mode: 384
133
- });
134
- fs.chmodSync(configPath, 384);
135
- return {
136
- openclawHome,
137
- configPath,
138
- sharedSkillsPath,
139
- linkedSharedSkills: syncSkillsDir(sharedSkillsPath, config.skillsDir)
140
- };
141
- }
142
- function getOpenClawMirrorStatus(config) {
143
- const openclawHome = resolveOpenClawHome();
144
- const configPath = resolveOpenClawConfigPath(openclawHome);
145
- const sharedSkillsPath = resolveOpenClawSharedSkillsPath(openclawHome);
146
- const expectedConfig = buildMirrorConfig(config);
147
- const currentConfig = readJsonIfExists(configPath);
148
- let linkedSharedSkills = false;
149
- try {
150
- if (fs.lstatSync(sharedSkillsPath).isSymbolicLink()) {
151
- const target = fs.readlinkSync(sharedSkillsPath);
152
- linkedSharedSkills = path.resolve(path.dirname(sharedSkillsPath), target) === path.resolve(config.skillsDir);
153
- }
154
- } catch {
155
- linkedSharedSkills = false;
156
- }
157
- return {
158
- openclawHome,
159
- configPath,
160
- sharedSkillsPath,
161
- linkedSharedSkills,
162
- configExists: fs.existsSync(configPath),
163
- configInSync: JSON.stringify(currentConfig) === JSON.stringify(expectedConfig),
164
- skillsPathExists: fs.existsSync(sharedSkillsPath)
165
- };
166
- }
167
-
168
42
  //#endregion
169
43
  //#region src/config.ts
170
44
  dotenv.config();
@@ -1251,31 +1125,6 @@ function getProviderApiKeyFromEnv(provider, env = process.env) {
1251
1125
  }
1252
1126
  const config = loadConfig();
1253
1127
 
1254
- //#endregion
1255
- //#region src/cli/compat.ts
1256
- function renderStatus(status) {
1257
- const lines = [];
1258
- lines.push(`OpenClaw home: ${status.openclawHome}`);
1259
- lines.push(`Config path: ${status.configPath}`);
1260
- lines.push(`Config exists: ${status.configExists ? "yes" : "no"}`);
1261
- lines.push(`Config in sync: ${status.configInSync ? "yes" : "no"}`);
1262
- lines.push(`Skills path: ${status.sharedSkillsPath}`);
1263
- lines.push(`Skills exists: ${status.skillsPathExists ? "yes" : "no"}`);
1264
- lines.push(`Skills symlinked: ${status.linkedSharedSkills ? "yes" : "no"}`);
1265
- return lines.join("\n");
1266
- }
1267
- function registerCompatCommands(program) {
1268
- program.command("compat").description("Compatibility helpers").command("status").description("Show OpenClaw mirror compatibility status").option("--sync", "Rewrite mirror before reading status").option("--json", "Print JSON output").action((options) => {
1269
- if (options.sync) writeOpenClawMirror(config);
1270
- const status = getOpenClawMirrorStatus(config);
1271
- if (options.json) {
1272
- process.stdout.write(`${JSON.stringify(status, null, 2)}\n`);
1273
- return;
1274
- }
1275
- process.stdout.write(`${renderStatus(status)}\n`);
1276
- });
1277
- }
1278
-
1279
1128
  //#endregion
1280
1129
  //#region src/gateway/protocol/schema.ts
1281
1130
  const nonEmptyStringSchema = z.string().min(1);
@@ -4455,7 +4304,6 @@ function readFileConfigForCli(env = process.env) {
4455
4304
  }
4456
4305
  function writeFileConfigForCli(next, env = process.env) {
4457
4306
  saveConfigFile(next, env);
4458
- writeOpenClawMirror(loadConfig(env));
4459
4307
  }
4460
4308
 
4461
4309
  //#endregion
@@ -5631,7 +5479,7 @@ function registerGatewayCommands(program, deps = defaultGatewayCommandDeps) {
5631
5479
  gateway.command("run").description("Run HOVClaw daemon with gateway in foreground").action(async () => {
5632
5480
  if (!config.gateway.enabled) throw new Error("Gateway is disabled in config. Enable gateway.enabled first.");
5633
5481
  process.stdout.write(`Starting HOVClaw gateway on ${config.gateway.host}:${config.gateway.port}...\n`);
5634
- await import("./src-Y6AqidKn.js");
5482
+ await import("./src-qX1C6PLF.js");
5635
5483
  });
5636
5484
  gateway.command("open-ui").description("Open the minimal gateway web UI in your default browser").option("--no-open", "Print URL but do not open browser").option("--json", "Print JSON output").action(async (options) => {
5637
5485
  const url = resolveGatewayWebUiUrl();
@@ -5935,7 +5783,7 @@ function registerCoreCommands(program) {
5935
5783
  await (await import("./login-BwvBMKdz.js")).main(provider ? [provider] : []);
5936
5784
  });
5937
5785
  program.command("doctor").description("Run installation and config health checks").option("--fix", "Attempt auto-repair").option("--repair", "Attempt auto-repair").option("--deep", "Run deep checks").option("--json", "Print JSON output").action(async (options) => {
5938
- const module = await import("./doctor-D52M80De.js");
5786
+ const module = await import("./doctor-DJHTvhli.js");
5939
5787
  const args = [];
5940
5788
  if (options.fix || options.repair) args.push("--fix");
5941
5789
  if (options.deep) args.push("--deep");
@@ -6051,7 +5899,6 @@ async function main() {
6051
5899
  registerPairingCommands(program);
6052
5900
  registerGatewayCommands(program);
6053
5901
  registerSkillsCommands(program);
6054
- registerCompatCommands(program);
6055
5902
  await program.parseAsync(process.argv);
6056
5903
  }
6057
5904
  main().catch((error) => {
@@ -6060,4 +5907,4 @@ main().catch((error) => {
6060
5907
  });
6061
5908
 
6062
5909
  //#endregion
6063
- export { ensureConfigFromLegacyEnv as A, resolveTelegramAccountConfig as B, resolveModelAlias as C, parseGatewayFrame as D, parseConnectParams as E, hasConfigFile as F, saveCredentials as H, hasCredentialsFile as I, loadConfig as L, getCredentialsPath as M, getDefaultFileConfig as N, config as O, getHovclawHome as P, loadCredentials as R, parseModelRef as S, PROTOCOL_VERSION as T, writeOpenClawMirror as U, saveConfigFile as V, extractAssistantText as _, LocalHostRuntime as a, loadSkill as b, redactSensitiveData as c, PiAgentManager as d, composeSessionKey as f, extractAssistantError as g, resolveAgentWorkspaceDir as h, createTools as i, getConfigPath as j, detectLegacyEnvConfig as k, TelegramChannel as l, ensureWorkspaceBootstrapForConfig as m, stopDaemon as n, ContainerRuntime as o, WORKSPACE_CONTEXT_FILE_ORDER as p, TelegramPairingStore as r, HovClawDb as s, requestDaemonRestartFromCurrentProcess as t, DiscordChannel as u, toUserFacingAssistantError as v, logger as w, listConfiguredModelRefs as x, listAvailableSkills as y, loadFileConfig as z };
5910
+ export { ensureConfigFromLegacyEnv as A, resolveTelegramAccountConfig as B, resolveModelAlias as C, parseGatewayFrame as D, parseConnectParams as E, hasConfigFile as F, saveCredentials as H, hasCredentialsFile as I, loadConfig as L, getCredentialsPath as M, getDefaultFileConfig as N, config as O, getHovclawHome as P, loadCredentials as R, parseModelRef as S, PROTOCOL_VERSION as T, saveConfigFile as V, extractAssistantText as _, LocalHostRuntime as a, loadSkill as b, redactSensitiveData as c, PiAgentManager as d, composeSessionKey as f, extractAssistantError as g, resolveAgentWorkspaceDir as h, createTools as i, getConfigPath as j, detectLegacyEnvConfig as k, TelegramChannel as l, ensureWorkspaceBootstrapForConfig as m, stopDaemon as n, ContainerRuntime as o, WORKSPACE_CONTEXT_FILE_ORDER as p, TelegramPairingStore as r, HovClawDb as s, requestDaemonRestartFromCurrentProcess as t, DiscordChannel as u, toUserFacingAssistantError as v, logger as w, listConfiguredModelRefs as x, listAvailableSkills as y, loadFileConfig as z };
package/dist/index.js CHANGED
@@ -3084,99 +3084,6 @@ async function requestDaemonRestartFromCurrentProcess(env = process.env) {
3084
3084
  };
3085
3085
  }
3086
3086
 
3087
- //#endregion
3088
- //#region src/compat/openclaw-mirror.ts
3089
- function resolveOpenClawHome(env = process.env) {
3090
- const override = env.OPENCLAW_STATE_DIR?.trim();
3091
- if (override) return path.resolve(override.startsWith("~") ? path.join(os.homedir(), override.slice(1)) : override);
3092
- return path.join(os.homedir(), ".openclaw");
3093
- }
3094
- function resolveOpenClawConfigPath(openclawHome) {
3095
- return path.join(openclawHome, "openclaw.json");
3096
- }
3097
- function resolveOpenClawSharedSkillsPath(openclawHome) {
3098
- return path.join(openclawHome, "skills");
3099
- }
3100
- function buildMirrorConfig(config) {
3101
- const fallbackWorkspace = config.agents.defaults.workspace || path.join(config.hovclawHome, "workspace");
3102
- const agentList = config.agents.list.length > 0 ? config.agents.list : [{
3103
- id: "main",
3104
- name: "Main",
3105
- workspace: fallbackWorkspace,
3106
- default: true
3107
- }];
3108
- const extraDirs = /* @__PURE__ */ new Set();
3109
- extraDirs.add(config.skillsDir);
3110
- for (const agent of agentList) {
3111
- const workspace = (agent.workspace || fallbackWorkspace).trim();
3112
- if (!workspace) continue;
3113
- extraDirs.add(path.join(workspace, "skills"));
3114
- }
3115
- return {
3116
- agent: { workspace: fallbackWorkspace },
3117
- agents: {
3118
- defaults: { workspace: fallbackWorkspace },
3119
- list: agentList
3120
- },
3121
- skills: { load: { extraDirs: Array.from(extraDirs) } }
3122
- };
3123
- }
3124
- function ensureDir(dirPath) {
3125
- fs.mkdirSync(dirPath, {
3126
- recursive: true,
3127
- mode: 448
3128
- });
3129
- }
3130
- function syncSkillsDir(sharedSkillsPath, sourceSkillsPath) {
3131
- if (!fs.existsSync(sourceSkillsPath)) {
3132
- ensureDir(sharedSkillsPath);
3133
- return false;
3134
- }
3135
- try {
3136
- if (fs.lstatSync(sharedSkillsPath).isSymbolicLink()) {
3137
- const linkTarget = fs.readlinkSync(sharedSkillsPath);
3138
- if (path.resolve(path.dirname(sharedSkillsPath), linkTarget) === sourceSkillsPath) return true;
3139
- fs.unlinkSync(sharedSkillsPath);
3140
- }
3141
- } catch {}
3142
- if (!fs.existsSync(sharedSkillsPath)) try {
3143
- fs.symlinkSync(sourceSkillsPath, sharedSkillsPath, "dir");
3144
- return true;
3145
- } catch {}
3146
- ensureDir(sharedSkillsPath);
3147
- for (const entry of fs.readdirSync(sourceSkillsPath, { withFileTypes: true })) {
3148
- const src = path.join(sourceSkillsPath, entry.name);
3149
- const dst = path.join(sharedSkillsPath, entry.name);
3150
- if (entry.isDirectory()) {
3151
- fs.cpSync(src, dst, {
3152
- recursive: true,
3153
- force: true
3154
- });
3155
- continue;
3156
- }
3157
- if (entry.isFile()) fs.copyFileSync(src, dst);
3158
- }
3159
- return false;
3160
- }
3161
- function writeOpenClawMirror(config) {
3162
- const openclawHome = resolveOpenClawHome();
3163
- const configPath = resolveOpenClawConfigPath(openclawHome);
3164
- const sharedSkillsPath = resolveOpenClawSharedSkillsPath(openclawHome);
3165
- ensureDir(openclawHome);
3166
- const mirrorConfig = buildMirrorConfig(config);
3167
- fs.writeFileSync(configPath, `${JSON.stringify(mirrorConfig, null, 2)}\n`, {
3168
- encoding: "utf8",
3169
- mode: 384
3170
- });
3171
- fs.chmodSync(configPath, 384);
3172
- return {
3173
- openclawHome,
3174
- configPath,
3175
- sharedSkillsPath,
3176
- linkedSharedSkills: syncSkillsDir(sharedSkillsPath, config.skillsDir)
3177
- };
3178
- }
3179
-
3180
3087
  //#endregion
3181
3088
  //#region src/models/catalog.ts
3182
3089
  function buildModelCatalog(aliases) {
@@ -3583,7 +3490,6 @@ function reloadRuntimeConfig() {
3583
3490
  function persistFileConfig(next) {
3584
3491
  saveConfigFile(next);
3585
3492
  reloadRuntimeConfig();
3586
- writeOpenClawMirror(config);
3587
3493
  }
3588
3494
  function parseConfigPath(raw) {
3589
3495
  const pathValue = raw?.trim();
@@ -5083,14 +4989,12 @@ const configGetMethod = async (_params, context) => {
5083
4989
  const configSetMethod = async (params, context) => {
5084
4990
  const parsed = configSetParamsSchema.parse(params);
5085
4991
  context.writeFileConfig(parsed.config);
5086
- writeOpenClawMirror(loadConfig());
5087
4992
  return { ok: true };
5088
4993
  };
5089
4994
  const configPatchMethod = async (params, context) => {
5090
4995
  const parsed = configPatchParamsSchema.parse(params);
5091
4996
  const merged = deepMerge(context.readFileConfig(), parsed.patch);
5092
4997
  context.writeFileConfig(merged);
5093
- writeOpenClawMirror(loadConfig());
5094
4998
  return { ok: true };
5095
4999
  };
5096
5000
 
@@ -7082,7 +6986,6 @@ async function main() {
7082
6986
  } catch (error) {
7083
6987
  logger.warn({ error }, "Workspace bootstrap failed");
7084
6988
  }
7085
- writeOpenClawMirror(config);
7086
6989
  const db = new HovClawDb(path.join(config.storeDir, "hovclaw.db"));
7087
6990
  db.ping();
7088
6991
  const runtime = config.runtime.mode === "container" ? new ContainerRuntime({
@@ -1,10 +1,10 @@
1
- import { A as ensureConfigFromLegacyEnv, B as resolveTelegramAccountConfig, C as resolveModelAlias, D as parseGatewayFrame, E as parseConnectParams, F as hasConfigFile, L as loadConfig, N as getDefaultFileConfig, O as config, S as parseModelRef, T as PROTOCOL_VERSION, U as writeOpenClawMirror, V as saveConfigFile, _ as extractAssistantText, a as LocalHostRuntime, b as loadSkill, c as redactSensitiveData, d as PiAgentManager, f as composeSessionKey, g as extractAssistantError, h as resolveAgentWorkspaceDir, i as createTools, l as TelegramChannel, m as ensureWorkspaceBootstrapForConfig, o as ContainerRuntime, p as WORKSPACE_CONTEXT_FILE_ORDER, r as TelegramPairingStore, s as HovClawDb, t as requestDaemonRestartFromCurrentProcess, u as DiscordChannel, v as toUserFacingAssistantError, w as logger, x as listConfiguredModelRefs, y as listAvailableSkills, z as loadFileConfig } from "./hovclaw.js";
1
+ import { A as ensureConfigFromLegacyEnv, B as resolveTelegramAccountConfig, C as resolveModelAlias, D as parseGatewayFrame, E as parseConnectParams, F as hasConfigFile, L as loadConfig, N as getDefaultFileConfig, O as config, S as parseModelRef, T as PROTOCOL_VERSION, V as saveConfigFile, _ as extractAssistantText, a as LocalHostRuntime, b as loadSkill, c as redactSensitiveData, d as PiAgentManager, f as composeSessionKey, g as extractAssistantError, h as resolveAgentWorkspaceDir, i as createTools, l as TelegramChannel, m as ensureWorkspaceBootstrapForConfig, o as ContainerRuntime, p as WORKSPACE_CONTEXT_FILE_ORDER, r as TelegramPairingStore, s as HovClawDb, t as requestDaemonRestartFromCurrentProcess, u as DiscordChannel, v as toUserFacingAssistantError, w as logger, x as listConfiguredModelRefs, y as listAvailableSkills, z as loadFileConfig } from "./hovclaw.js";
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
- import { ZodError, z } from "zod";
6
5
  import { randomUUID } from "node:crypto";
7
6
  import WebSocket, { WebSocketServer } from "ws";
7
+ import { ZodError, z } from "zod";
8
8
  import fs$1 from "node:fs/promises";
9
9
  import { createServer } from "node:http";
10
10
  import { spawnSync } from "node:child_process";
@@ -543,7 +543,6 @@ function reloadRuntimeConfig() {
543
543
  function persistFileConfig(next) {
544
544
  saveConfigFile(next);
545
545
  reloadRuntimeConfig();
546
- writeOpenClawMirror(config);
547
546
  }
548
547
  function parseConfigPath(raw) {
549
548
  const pathValue = raw?.trim();
@@ -1483,14 +1482,12 @@ const configGetMethod = async (_params, context) => {
1483
1482
  const configSetMethod = async (params, context) => {
1484
1483
  const parsed = configSetParamsSchema.parse(params);
1485
1484
  context.writeFileConfig(parsed.config);
1486
- writeOpenClawMirror(loadConfig());
1487
1485
  return { ok: true };
1488
1486
  };
1489
1487
  const configPatchMethod = async (params, context) => {
1490
1488
  const parsed = configPatchParamsSchema.parse(params);
1491
1489
  const merged = deepMerge(context.readFileConfig(), parsed.patch);
1492
1490
  context.writeFileConfig(merged);
1493
- writeOpenClawMirror(loadConfig());
1494
1491
  return { ok: true };
1495
1492
  };
1496
1493
 
@@ -2604,7 +2601,6 @@ async function main() {
2604
2601
  } catch (error) {
2605
2602
  logger.warn({ error }, "Workspace bootstrap failed");
2606
2603
  }
2607
- writeOpenClawMirror(config);
2608
2604
  const db = new HovClawDb(path.join(config.storeDir, "hovclaw.db"));
2609
2605
  db.ping();
2610
2606
  const runtime = config.runtime.mode === "container" ? new ContainerRuntime({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hovclaw",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Multi-channel AI agent gateway",
5
5
  "license": "MIT",
6
6
  "type": "module",