@openclawcity/become 1.0.12 → 1.0.18
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/dist/cli.cjs +438 -157
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +438 -157
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +4 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -98,146 +98,147 @@ var import_node_path2 = require("path");
|
|
|
98
98
|
var import_node_os2 = require("os");
|
|
99
99
|
var import_node_child_process = require("child_process");
|
|
100
100
|
var OPENCLAW_CONFIG = (0, import_node_path2.join)((0, import_node_os2.homedir)(), ".openclaw", "openclaw.json");
|
|
101
|
-
var
|
|
102
|
-
var
|
|
103
|
-
var
|
|
104
|
-
|
|
101
|
+
var STATE_DIR = (0, import_node_path2.join)((0, import_node_os2.homedir)(), ".become", "state");
|
|
102
|
+
var BACKUP_PATH = (0, import_node_path2.join)(STATE_DIR, "original_openclaw.json");
|
|
103
|
+
var ORIGINAL_URL_PATH = (0, import_node_path2.join)(STATE_DIR, "original_base_url.txt");
|
|
104
|
+
var PATCHED_PROVIDER_PATH = (0, import_node_path2.join)(STATE_DIR, "patched_provider.txt");
|
|
105
|
+
function patchOpenClaw(config) {
|
|
105
106
|
if (!(0, import_node_fs2.existsSync)(OPENCLAW_CONFIG)) {
|
|
106
107
|
throw new Error(`OpenClaw config not found at ${OPENCLAW_CONFIG}`);
|
|
107
108
|
}
|
|
108
109
|
const raw = (0, import_node_fs2.readFileSync)(OPENCLAW_CONFIG, "utf-8");
|
|
109
|
-
const clawConfig =
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
const clawConfig = parseConfig(raw);
|
|
111
|
+
(0, import_node_fs2.mkdirSync)(STATE_DIR, { recursive: true });
|
|
112
|
+
const primaryModel = clawConfig.agents?.defaults?.model?.primary ?? "";
|
|
113
|
+
if (!primaryModel) {
|
|
114
|
+
throw new Error("No default model configured in openclaw.json (agents.defaults.model.primary)");
|
|
115
|
+
}
|
|
116
|
+
const providerName = primaryModel.split("/")[0];
|
|
117
|
+
if (!providerName) {
|
|
118
|
+
throw new Error(`Cannot determine provider from model: ${primaryModel}`);
|
|
119
|
+
}
|
|
120
|
+
if ((0, import_node_fs2.existsSync)(ORIGINAL_URL_PATH)) {
|
|
121
|
+
const existingUrl = (0, import_node_fs2.readFileSync)(ORIGINAL_URL_PATH, "utf-8").trim();
|
|
122
|
+
if (existingUrl) {
|
|
123
|
+
console.log("become is already connected. Run `become off` first to disconnect.");
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const modelsJsonPath = getModelsJsonPath(clawConfig);
|
|
128
|
+
let modelsConfig = null;
|
|
129
|
+
let modelsSource = "openclaw.json";
|
|
130
|
+
if (modelsJsonPath && (0, import_node_fs2.existsSync)(modelsJsonPath)) {
|
|
131
|
+
modelsConfig = JSON.parse((0, import_node_fs2.readFileSync)(modelsJsonPath, "utf-8"));
|
|
132
|
+
modelsSource = "models.json";
|
|
133
|
+
}
|
|
134
|
+
let provider = null;
|
|
135
|
+
let providerLocation = null;
|
|
136
|
+
if (modelsConfig?.providers?.[providerName]) {
|
|
137
|
+
provider = modelsConfig.providers[providerName];
|
|
138
|
+
providerLocation = modelsConfig.providers;
|
|
139
|
+
} else if (clawConfig.models?.providers?.[providerName]) {
|
|
140
|
+
provider = clawConfig.models.providers[providerName];
|
|
141
|
+
providerLocation = clawConfig.models.providers;
|
|
142
|
+
modelsSource = "openclaw.json";
|
|
143
|
+
}
|
|
144
|
+
if (!provider) {
|
|
145
|
+
throw new Error(
|
|
146
|
+
`Provider "${providerName}" not found in models.json or openclaw.json. Your model is "${primaryModel}" which needs a "${providerName}" provider.`
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
const originalUrl = provider.baseUrl;
|
|
150
|
+
if (!originalUrl) {
|
|
151
|
+
throw new Error(`Provider "${providerName}" has no baseUrl`);
|
|
113
152
|
}
|
|
114
|
-
(0, import_node_fs2.mkdirSync)((0, import_node_path2.join)((0, import_node_os2.homedir)(), ".become", "state"), { recursive: true });
|
|
115
153
|
(0, import_node_fs2.writeFileSync)(BACKUP_PATH, raw, "utf-8");
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (
|
|
120
|
-
|
|
121
|
-
if (!agent) {
|
|
122
|
-
throw new Error(`Agent "${agentId}" not found in agents.list. Available: ${agents.map((a) => a.id).join(", ")}`);
|
|
123
|
-
}
|
|
124
|
-
originalModel = agent.model ?? clawConfig.agents?.defaults?.model?.primary ?? "";
|
|
125
|
-
patchedAgentId = agentId;
|
|
126
|
-
const modelId2 = stripProvider(originalModel);
|
|
127
|
-
if (!modelId2) {
|
|
128
|
-
throw new Error("No model configured for this agent. Set a model in openclaw.json first.");
|
|
129
|
-
}
|
|
130
|
-
agent.model = `become/${modelId2}`;
|
|
154
|
+
(0, import_node_fs2.writeFileSync)(ORIGINAL_URL_PATH, originalUrl, "utf-8");
|
|
155
|
+
(0, import_node_fs2.writeFileSync)(PATCHED_PROVIDER_PATH, `${providerName}:${modelsSource}`, "utf-8");
|
|
156
|
+
provider.baseUrl = `http://127.0.0.1:${config.proxy_port}`;
|
|
157
|
+
if (modelsSource === "models.json" && modelsJsonPath) {
|
|
158
|
+
(0, import_node_fs2.writeFileSync)(modelsJsonPath, JSON.stringify(modelsConfig, null, 2), "utf-8");
|
|
131
159
|
} else {
|
|
132
|
-
|
|
133
|
-
patchedAgentId = "_defaults";
|
|
134
|
-
const modelId2 = stripProvider(originalModel);
|
|
135
|
-
if (!modelId2) {
|
|
136
|
-
throw new Error("No default model configured. Set agents.defaults.model.primary in openclaw.json first.");
|
|
137
|
-
}
|
|
138
|
-
if (!clawConfig.agents) clawConfig.agents = {};
|
|
139
|
-
if (!clawConfig.agents.defaults) clawConfig.agents.defaults = {};
|
|
140
|
-
if (!clawConfig.agents.defaults.model) clawConfig.agents.defaults.model = {};
|
|
141
|
-
clawConfig.agents.defaults.model.primary = `become/${modelId2}`;
|
|
142
|
-
}
|
|
143
|
-
(0, import_node_fs2.writeFileSync)(ORIGINAL_MODEL_PATH, originalModel, "utf-8");
|
|
144
|
-
(0, import_node_fs2.writeFileSync)(PATCHED_AGENT_PATH, patchedAgentId, "utf-8");
|
|
145
|
-
const modelId = stripProvider(originalModel);
|
|
146
|
-
if (!clawConfig.models) clawConfig.models = {};
|
|
147
|
-
if (!clawConfig.models.providers) clawConfig.models.providers = {};
|
|
148
|
-
clawConfig.models.providers.become = {
|
|
149
|
-
api: config.llm_provider === "openai" || config.llm_provider === "openrouter" ? "openai-completions" : "anthropic-messages",
|
|
150
|
-
baseUrl: `http://127.0.0.1:${config.proxy_port}`,
|
|
151
|
-
apiKey: config.llm_api_key,
|
|
152
|
-
models: [
|
|
153
|
-
{ id: modelId, name: `${modelId} via become` }
|
|
154
|
-
]
|
|
155
|
-
};
|
|
156
|
-
(0, import_node_fs2.writeFileSync)(OPENCLAW_CONFIG, JSON.stringify(clawConfig, null, 2), "utf-8");
|
|
157
|
-
console.log("Restarting OpenClaw gateway...");
|
|
158
|
-
try {
|
|
159
|
-
(0, import_node_child_process.execSync)("openclaw gateway restart", { stdio: "pipe", timeout: 15e3 });
|
|
160
|
-
console.log("OpenClaw gateway restarted. Your agent is now routing through become.");
|
|
161
|
-
} catch {
|
|
162
|
-
console.log("\n*** OpenClaw gateway needs a manual restart to pick up the new config. ***");
|
|
163
|
-
console.log("*** Run: openclaw gateway restart ***\n");
|
|
160
|
+
(0, import_node_fs2.writeFileSync)(OPENCLAW_CONFIG, JSON.stringify(clawConfig, null, 2), "utf-8");
|
|
164
161
|
}
|
|
162
|
+
console.log(` provider: ${providerName}`);
|
|
163
|
+
console.log(` baseUrl: ${originalUrl} -> localhost:${config.proxy_port}`);
|
|
164
|
+
restartGateway();
|
|
165
165
|
}
|
|
166
166
|
function restoreOpenClaw() {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
const backupConfig = parseOpenClawConfig(backup);
|
|
173
|
-
if (!backupConfig.models?.providers?.become) {
|
|
174
|
-
(0, import_node_fs2.writeFileSync)(OPENCLAW_CONFIG, backup, "utf-8");
|
|
175
|
-
restartGateway();
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
167
|
+
const originalUrl = readSafe(ORIGINAL_URL_PATH);
|
|
168
|
+
const patchInfo = readSafe(PATCHED_PROVIDER_PATH);
|
|
169
|
+
if (!originalUrl || !patchInfo) {
|
|
170
|
+
cleanState();
|
|
171
|
+
return;
|
|
178
172
|
}
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
agent.model = originalModel;
|
|
189
|
-
}
|
|
190
|
-
} else {
|
|
191
|
-
if (config.agents?.defaults?.model) {
|
|
192
|
-
config.agents.defaults.model.primary = originalModel;
|
|
173
|
+
const [providerName, source] = patchInfo.split(":");
|
|
174
|
+
if (source === "models.json") {
|
|
175
|
+
const clawConfig = parseConfig((0, import_node_fs2.readFileSync)(OPENCLAW_CONFIG, "utf-8"));
|
|
176
|
+
const modelsJsonPath = getModelsJsonPath(clawConfig);
|
|
177
|
+
if (modelsJsonPath && (0, import_node_fs2.existsSync)(modelsJsonPath)) {
|
|
178
|
+
const modelsConfig = JSON.parse((0, import_node_fs2.readFileSync)(modelsJsonPath, "utf-8"));
|
|
179
|
+
if (modelsConfig.providers?.[providerName]) {
|
|
180
|
+
modelsConfig.providers[providerName].baseUrl = originalUrl;
|
|
181
|
+
(0, import_node_fs2.writeFileSync)(modelsJsonPath, JSON.stringify(modelsConfig, null, 2), "utf-8");
|
|
193
182
|
}
|
|
194
183
|
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
184
|
+
} else {
|
|
185
|
+
if ((0, import_node_fs2.existsSync)(OPENCLAW_CONFIG)) {
|
|
186
|
+
const clawConfig = parseConfig((0, import_node_fs2.readFileSync)(OPENCLAW_CONFIG, "utf-8"));
|
|
187
|
+
if (clawConfig.models?.providers?.[providerName]) {
|
|
188
|
+
clawConfig.models.providers[providerName].baseUrl = originalUrl;
|
|
189
|
+
(0, import_node_fs2.writeFileSync)(OPENCLAW_CONFIG, JSON.stringify(clawConfig, null, 2), "utf-8");
|
|
190
|
+
}
|
|
202
191
|
}
|
|
203
192
|
}
|
|
204
|
-
(
|
|
193
|
+
cleanState();
|
|
205
194
|
restartGateway();
|
|
206
195
|
}
|
|
207
196
|
function listOpenClawAgents() {
|
|
208
197
|
if (!(0, import_node_fs2.existsSync)(OPENCLAW_CONFIG)) return [];
|
|
209
198
|
try {
|
|
210
|
-
const config =
|
|
199
|
+
const config = parseConfig((0, import_node_fs2.readFileSync)(OPENCLAW_CONFIG, "utf-8"));
|
|
211
200
|
const agents = config.agents?.list ?? [];
|
|
212
|
-
const defaultModel =
|
|
201
|
+
const defaultModel = config.agents?.defaults?.model?.primary ?? "unknown";
|
|
213
202
|
if (agents.length === 0) {
|
|
214
203
|
return [{ id: "_defaults", model: defaultModel }];
|
|
215
204
|
}
|
|
216
205
|
return agents.map((a) => ({
|
|
217
206
|
id: a.id,
|
|
218
|
-
model:
|
|
207
|
+
model: a.model ?? defaultModel
|
|
219
208
|
}));
|
|
220
209
|
} catch {
|
|
221
210
|
return [];
|
|
222
211
|
}
|
|
223
212
|
}
|
|
224
|
-
function
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
213
|
+
function getModelsJsonPath(clawConfig) {
|
|
214
|
+
const agentList = clawConfig.agents?.list ?? [];
|
|
215
|
+
const defaultAgent = agentList.find((a) => a.default) ?? agentList[0];
|
|
216
|
+
if (defaultAgent?.agentDir) {
|
|
217
|
+
return (0, import_node_path2.join)(defaultAgent.agentDir.replace("~", (0, import_node_os2.homedir)()), "models.json");
|
|
218
|
+
}
|
|
219
|
+
const mainPath = (0, import_node_path2.join)((0, import_node_os2.homedir)(), ".openclaw", "agents", "main", "agent", "models.json");
|
|
220
|
+
if ((0, import_node_fs2.existsSync)(mainPath)) return mainPath;
|
|
221
|
+
return null;
|
|
229
222
|
}
|
|
230
|
-
function
|
|
223
|
+
function parseConfig(raw) {
|
|
231
224
|
const stripped = raw.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "").replace(/,\s*([\]}])/g, "$1");
|
|
232
225
|
return JSON.parse(stripped);
|
|
233
226
|
}
|
|
234
|
-
function
|
|
227
|
+
function readSafe(path) {
|
|
235
228
|
try {
|
|
236
229
|
return (0, import_node_fs2.existsSync)(path) ? (0, import_node_fs2.readFileSync)(path, "utf-8").trim() : "";
|
|
237
230
|
} catch {
|
|
238
231
|
return "";
|
|
239
232
|
}
|
|
240
233
|
}
|
|
234
|
+
function cleanState() {
|
|
235
|
+
for (const f of [ORIGINAL_URL_PATH, PATCHED_PROVIDER_PATH]) {
|
|
236
|
+
try {
|
|
237
|
+
(0, import_node_fs2.writeFileSync)(f, "", "utf-8");
|
|
238
|
+
} catch {
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
241
242
|
function restartGateway() {
|
|
242
243
|
console.log("Restarting OpenClaw gateway...");
|
|
243
244
|
try {
|
|
@@ -323,6 +324,11 @@ Proxy port (default 30001): `);
|
|
|
323
324
|
}
|
|
324
325
|
}
|
|
325
326
|
|
|
327
|
+
// src/cli/commands.ts
|
|
328
|
+
var import_node_fs7 = require("fs");
|
|
329
|
+
var import_node_path7 = require("path");
|
|
330
|
+
var import_node_os5 = require("os");
|
|
331
|
+
|
|
326
332
|
// src/proxy/server.ts
|
|
327
333
|
var import_node_http = require("http");
|
|
328
334
|
|
|
@@ -749,7 +755,7 @@ Rules:
|
|
|
749
755
|
|
|
750
756
|
// src/proxy/server.ts
|
|
751
757
|
var SKILL_CACHE_TTL_MS = 5e3;
|
|
752
|
-
function createProxyServer(config, analyzer) {
|
|
758
|
+
function createProxyServer(config, analyzer, overrideUpstreamUrl) {
|
|
753
759
|
const store = new FileSkillStore({ baseDir: config.baseDir });
|
|
754
760
|
const trust = new TrustManager(config.baseDir);
|
|
755
761
|
const extractor = analyzer ? new LessonExtractor(store, trust, analyzer) : null;
|
|
@@ -796,7 +802,7 @@ function createProxyServer(config, analyzer) {
|
|
|
796
802
|
stats.skills_injected++;
|
|
797
803
|
}
|
|
798
804
|
}
|
|
799
|
-
const upstreamUrl = buildUpstreamUrl(config, req.url);
|
|
805
|
+
const upstreamUrl = buildUpstreamUrl(overrideUpstreamUrl ?? config.llm_base_url, req.url);
|
|
800
806
|
const upstreamHeaders = buildUpstreamHeaders(config, req.headers);
|
|
801
807
|
const isStreaming = body.stream === true;
|
|
802
808
|
const modifiedBody = JSON.stringify(body);
|
|
@@ -880,8 +886,8 @@ function readBody(req) {
|
|
|
880
886
|
req.on("error", reject);
|
|
881
887
|
});
|
|
882
888
|
}
|
|
883
|
-
function buildUpstreamUrl(
|
|
884
|
-
const base =
|
|
889
|
+
function buildUpstreamUrl(baseUrl, path) {
|
|
890
|
+
const base = baseUrl.replace(/\/+$/, "");
|
|
885
891
|
return `${base}${path}`;
|
|
886
892
|
}
|
|
887
893
|
function buildUpstreamHeaders(config, incomingHeaders) {
|
|
@@ -1433,49 +1439,88 @@ var import_node_fs5 = require("fs");
|
|
|
1433
1439
|
var import_node_path5 = require("path");
|
|
1434
1440
|
var import_node_os3 = require("os");
|
|
1435
1441
|
var import_node_child_process2 = require("child_process");
|
|
1436
|
-
var IRONCLAW_ENV = (0, import_node_path5.join)((0, import_node_os3.homedir)(), ".ironclaw", ".env");
|
|
1442
|
+
var IRONCLAW_ENV = (0, import_node_path5.join)(process.env.IRONCLAW_BASE_DIR ?? (0, import_node_path5.join)((0, import_node_os3.homedir)(), ".ironclaw"), ".env");
|
|
1437
1443
|
var BACKUP_PATH2 = (0, import_node_path5.join)((0, import_node_os3.homedir)(), ".become", "state", "original_ironclaw.env");
|
|
1438
1444
|
function patchIronClaw(config) {
|
|
1439
1445
|
if (!(0, import_node_fs5.existsSync)(IRONCLAW_ENV)) {
|
|
1440
1446
|
throw new Error(`IronClaw .env not found at ${IRONCLAW_ENV}`);
|
|
1441
1447
|
}
|
|
1448
|
+
if ((0, import_node_fs5.existsSync)(BACKUP_PATH2)) {
|
|
1449
|
+
console.log("become is already connected to IronClaw. Run `become off` first.");
|
|
1450
|
+
return;
|
|
1451
|
+
}
|
|
1442
1452
|
(0, import_node_fs5.mkdirSync)((0, import_node_path5.join)((0, import_node_os3.homedir)(), ".become", "state"), { recursive: true });
|
|
1443
1453
|
(0, import_node_fs5.copyFileSync)(IRONCLAW_ENV, BACKUP_PATH2);
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
+
const content = (0, import_node_fs5.readFileSync)(IRONCLAW_ENV, "utf-8");
|
|
1455
|
+
const backendMatch = content.match(/^LLM_BACKEND=(.+)$/m);
|
|
1456
|
+
const backend = backendMatch?.[1]?.trim().toLowerCase() ?? "openai_compatible";
|
|
1457
|
+
const proxyUrl = `http://127.0.0.1:${config.proxy_port}`;
|
|
1458
|
+
const vars = {};
|
|
1459
|
+
switch (backend) {
|
|
1460
|
+
case "anthropic":
|
|
1461
|
+
vars["ANTHROPIC_BASE_URL"] = proxyUrl;
|
|
1462
|
+
break;
|
|
1463
|
+
case "ollama":
|
|
1464
|
+
vars["OLLAMA_BASE_URL"] = proxyUrl;
|
|
1465
|
+
break;
|
|
1466
|
+
case "nearai":
|
|
1467
|
+
case "near_ai":
|
|
1468
|
+
case "near":
|
|
1469
|
+
vars["NEARAI_BASE_URL"] = proxyUrl;
|
|
1470
|
+
break;
|
|
1471
|
+
default:
|
|
1472
|
+
vars["LLM_BASE_URL"] = proxyUrl;
|
|
1473
|
+
break;
|
|
1454
1474
|
}
|
|
1475
|
+
patchDotEnv(IRONCLAW_ENV, vars);
|
|
1476
|
+
console.log(` backend: ${backend}`);
|
|
1477
|
+
console.log(` patched: ${Object.keys(vars).join(", ")} -> localhost:${config.proxy_port}`);
|
|
1478
|
+
restartIronClaw();
|
|
1455
1479
|
}
|
|
1456
1480
|
function restoreIronClaw() {
|
|
1457
1481
|
if (!(0, import_node_fs5.existsSync)(BACKUP_PATH2)) {
|
|
1458
|
-
|
|
1482
|
+
return;
|
|
1459
1483
|
}
|
|
1460
1484
|
(0, import_node_fs5.copyFileSync)(BACKUP_PATH2, IRONCLAW_ENV);
|
|
1485
|
+
try {
|
|
1486
|
+
(0, import_node_fs5.unlinkSync)(BACKUP_PATH2);
|
|
1487
|
+
} catch {
|
|
1488
|
+
}
|
|
1489
|
+
restartIronClaw();
|
|
1490
|
+
}
|
|
1491
|
+
function restartIronClaw() {
|
|
1461
1492
|
console.log("Restarting IronClaw...");
|
|
1462
1493
|
try {
|
|
1463
|
-
(0, import_node_child_process2.execSync)("ironclaw service
|
|
1494
|
+
(0, import_node_child_process2.execSync)("ironclaw service stop", { stdio: "pipe", timeout: 1e4 });
|
|
1495
|
+
(0, import_node_child_process2.execSync)("ironclaw service start", { stdio: "pipe", timeout: 1e4 });
|
|
1464
1496
|
console.log("IronClaw restarted.");
|
|
1497
|
+
return;
|
|
1498
|
+
} catch {
|
|
1499
|
+
}
|
|
1500
|
+
try {
|
|
1501
|
+
(0, import_node_child_process2.execSync)("launchctl kickstart -k gui/$(id -u)/com.ironclaw.daemon", { stdio: "pipe", timeout: 1e4 });
|
|
1502
|
+
console.log("IronClaw restarted via launchctl.");
|
|
1503
|
+
return;
|
|
1504
|
+
} catch {
|
|
1505
|
+
}
|
|
1506
|
+
try {
|
|
1507
|
+
(0, import_node_child_process2.execSync)("systemctl --user restart ironclaw", { stdio: "pipe", timeout: 1e4 });
|
|
1508
|
+
console.log("IronClaw restarted via systemd.");
|
|
1509
|
+
return;
|
|
1465
1510
|
} catch {
|
|
1466
|
-
console.log("\n*** IronClaw needs a manual restart. ***");
|
|
1467
|
-
console.log("*** Run: ironclaw service restart ***\n");
|
|
1468
1511
|
}
|
|
1512
|
+
console.log("\n*** IronClaw needs a manual restart. ***");
|
|
1513
|
+
console.log("*** Run: ironclaw service stop && ironclaw service start ***\n");
|
|
1469
1514
|
}
|
|
1470
1515
|
function patchDotEnv(path, vars) {
|
|
1471
|
-
let content = (0, import_node_fs5.readFileSync)(path, "utf-8");
|
|
1516
|
+
let content = (0, import_node_fs5.existsSync)(path) ? (0, import_node_fs5.readFileSync)(path, "utf-8") : "";
|
|
1472
1517
|
for (const [key, value] of Object.entries(vars)) {
|
|
1473
1518
|
const regex = new RegExp(`^${key}=.*$`, "m");
|
|
1474
1519
|
if (regex.test(content)) {
|
|
1475
1520
|
content = content.replace(regex, `${key}=${value}`);
|
|
1476
1521
|
} else {
|
|
1477
|
-
content
|
|
1478
|
-
|
|
1522
|
+
content = content.trimEnd() + (content.length > 0 ? "\n" : "") + `${key}=${value}
|
|
1523
|
+
`;
|
|
1479
1524
|
}
|
|
1480
1525
|
}
|
|
1481
1526
|
(0, import_node_fs5.writeFileSync)(path, content, "utf-8");
|
|
@@ -1487,40 +1532,88 @@ var import_node_path6 = require("path");
|
|
|
1487
1532
|
var import_node_os4 = require("os");
|
|
1488
1533
|
var import_node_child_process3 = require("child_process");
|
|
1489
1534
|
var BACKUP_PATH3 = (0, import_node_path6.join)((0, import_node_os4.homedir)(), ".become", "state", "original_nanoclaw.env");
|
|
1535
|
+
var PATCHED_ENV_PATH_FILE = (0, import_node_path6.join)((0, import_node_os4.homedir)(), ".become", "state", "nanoclaw_env_path.txt");
|
|
1536
|
+
var NANOCLAW_URL_VAR = "ANTHROPIC_BASE_URL";
|
|
1490
1537
|
function patchNanoClaw(config) {
|
|
1491
1538
|
const envPath = findNanoClawEnv();
|
|
1492
1539
|
if (!envPath) {
|
|
1493
|
-
throw new Error(
|
|
1540
|
+
throw new Error(
|
|
1541
|
+
`Could not find NanoClaw .env file.
|
|
1542
|
+
NanoClaw stores .env in its project root (where you cloned it).
|
|
1543
|
+
Set ${NANOCLAW_URL_VAR}=http://127.0.0.1:${config.proxy_port} manually in your NanoClaw .env file.`
|
|
1544
|
+
);
|
|
1545
|
+
}
|
|
1546
|
+
if ((0, import_node_fs6.existsSync)(BACKUP_PATH3)) {
|
|
1547
|
+
console.log("become is already connected to NanoClaw. Run `become off` first.");
|
|
1548
|
+
return;
|
|
1494
1549
|
}
|
|
1495
1550
|
(0, import_node_fs6.mkdirSync)((0, import_node_path6.join)((0, import_node_os4.homedir)(), ".become", "state"), { recursive: true });
|
|
1496
1551
|
(0, import_node_fs6.copyFileSync)(envPath, BACKUP_PATH3);
|
|
1552
|
+
(0, import_node_fs6.writeFileSync)(PATCHED_ENV_PATH_FILE, envPath, "utf-8");
|
|
1497
1553
|
patchDotEnv2(envPath, {
|
|
1498
|
-
|
|
1554
|
+
[NANOCLAW_URL_VAR]: `http://127.0.0.1:${config.proxy_port}`
|
|
1499
1555
|
});
|
|
1556
|
+
console.log(` env file: ${envPath}`);
|
|
1557
|
+
console.log(` patched: ${NANOCLAW_URL_VAR} -> localhost:${config.proxy_port}`);
|
|
1500
1558
|
restartNanoClaw();
|
|
1501
1559
|
}
|
|
1502
1560
|
function restoreNanoClaw() {
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1561
|
+
if (!(0, import_node_fs6.existsSync)(BACKUP_PATH3)) {
|
|
1562
|
+
return;
|
|
1563
|
+
}
|
|
1564
|
+
let envPath = null;
|
|
1565
|
+
if ((0, import_node_fs6.existsSync)(PATCHED_ENV_PATH_FILE)) {
|
|
1566
|
+
envPath = (0, import_node_fs6.readFileSync)(PATCHED_ENV_PATH_FILE, "utf-8").trim();
|
|
1567
|
+
}
|
|
1568
|
+
if (!envPath) {
|
|
1569
|
+
envPath = findNanoClawEnv();
|
|
1570
|
+
}
|
|
1571
|
+
if (!envPath) {
|
|
1572
|
+
console.log("Warning: Cannot find NanoClaw .env to restore. Backup is at " + BACKUP_PATH3);
|
|
1573
|
+
return;
|
|
1506
1574
|
}
|
|
1507
1575
|
(0, import_node_fs6.copyFileSync)(BACKUP_PATH3, envPath);
|
|
1576
|
+
try {
|
|
1577
|
+
(0, import_node_fs6.unlinkSync)(BACKUP_PATH3);
|
|
1578
|
+
} catch {
|
|
1579
|
+
}
|
|
1580
|
+
try {
|
|
1581
|
+
(0, import_node_fs6.unlinkSync)(PATCHED_ENV_PATH_FILE);
|
|
1582
|
+
} catch {
|
|
1583
|
+
}
|
|
1508
1584
|
restartNanoClaw();
|
|
1509
1585
|
}
|
|
1510
1586
|
function findNanoClawEnv() {
|
|
1511
|
-
const candidates = [
|
|
1512
|
-
|
|
1513
|
-
(0, import_node_path6.join)((0, import_node_os4.homedir)(), ".config", "nanoclaw", ".env")
|
|
1514
|
-
];
|
|
1515
|
-
const plistPath = (0, import_node_path6.join)((0, import_node_os4.homedir)(), "Library", "LaunchAgents", "ai.nanoclaw.agent.plist");
|
|
1587
|
+
const candidates = [];
|
|
1588
|
+
const plistPath = (0, import_node_path6.join)((0, import_node_os4.homedir)(), "Library", "LaunchAgents", "com.nanoclaw.plist");
|
|
1516
1589
|
if ((0, import_node_fs6.existsSync)(plistPath)) {
|
|
1517
1590
|
try {
|
|
1518
1591
|
const plist = (0, import_node_fs6.readFileSync)(plistPath, "utf-8");
|
|
1519
|
-
const match = plist.match(/<string>([^<]
|
|
1520
|
-
if (match) candidates.
|
|
1592
|
+
const match = plist.match(/<key>WorkingDirectory<\/key>\s*<string>([^<]+)<\/string>/);
|
|
1593
|
+
if (match) candidates.push((0, import_node_path6.join)(match[1], ".env"));
|
|
1594
|
+
} catch {
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
const userUnit = (0, import_node_path6.join)((0, import_node_os4.homedir)(), ".config", "systemd", "user", "nanoclaw.service");
|
|
1598
|
+
if ((0, import_node_fs6.existsSync)(userUnit)) {
|
|
1599
|
+
try {
|
|
1600
|
+
const unit = (0, import_node_fs6.readFileSync)(userUnit, "utf-8");
|
|
1601
|
+
const match = unit.match(/WorkingDirectory=(.+)/);
|
|
1602
|
+
if (match) candidates.push((0, import_node_path6.join)(match[1].trim(), ".env"));
|
|
1521
1603
|
} catch {
|
|
1522
1604
|
}
|
|
1523
1605
|
}
|
|
1606
|
+
const rootUnit = "/etc/systemd/system/nanoclaw.service";
|
|
1607
|
+
if ((0, import_node_fs6.existsSync)(rootUnit)) {
|
|
1608
|
+
try {
|
|
1609
|
+
const unit = (0, import_node_fs6.readFileSync)(rootUnit, "utf-8");
|
|
1610
|
+
const match = unit.match(/WorkingDirectory=(.+)/);
|
|
1611
|
+
if (match) candidates.push((0, import_node_path6.join)(match[1].trim(), ".env"));
|
|
1612
|
+
} catch {
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
candidates.push((0, import_node_path6.join)((0, import_node_os4.homedir)(), "nanoclaw", ".env"));
|
|
1616
|
+
candidates.push("/opt/nanoclaw/.env");
|
|
1524
1617
|
for (const path of candidates) {
|
|
1525
1618
|
if ((0, import_node_fs6.existsSync)(path)) return path;
|
|
1526
1619
|
}
|
|
@@ -1528,35 +1621,207 @@ function findNanoClawEnv() {
|
|
|
1528
1621
|
}
|
|
1529
1622
|
function restartNanoClaw() {
|
|
1530
1623
|
console.log("Restarting NanoClaw...");
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
console.log("NanoClaw restarted.");
|
|
1534
|
-
} catch {
|
|
1624
|
+
const plistPath = (0, import_node_path6.join)((0, import_node_os4.homedir)(), "Library", "LaunchAgents", "com.nanoclaw.plist");
|
|
1625
|
+
if ((0, import_node_fs6.existsSync)(plistPath)) {
|
|
1535
1626
|
try {
|
|
1536
|
-
(0, import_node_child_process3.execSync)(
|
|
1627
|
+
(0, import_node_child_process3.execSync)(`launchctl unload "${plistPath}"`, { stdio: "pipe", timeout: 1e4 });
|
|
1628
|
+
(0, import_node_child_process3.execSync)(`launchctl load "${plistPath}"`, { stdio: "pipe", timeout: 1e4 });
|
|
1537
1629
|
console.log("NanoClaw restarted.");
|
|
1630
|
+
return;
|
|
1538
1631
|
} catch {
|
|
1539
|
-
console.log("\n*** NanoClaw needs a manual restart. ***");
|
|
1540
|
-
console.log("*** macOS: launchctl kickstart -k gui/$(id -u)/ai.nanoclaw.agent ***");
|
|
1541
|
-
console.log("*** Linux: systemctl --user restart nanoclaw ***\n");
|
|
1542
1632
|
}
|
|
1543
1633
|
}
|
|
1634
|
+
try {
|
|
1635
|
+
(0, import_node_child_process3.execSync)("systemctl --user restart nanoclaw", { stdio: "pipe", timeout: 1e4 });
|
|
1636
|
+
console.log("NanoClaw restarted.");
|
|
1637
|
+
return;
|
|
1638
|
+
} catch {
|
|
1639
|
+
}
|
|
1640
|
+
console.log("\n*** NanoClaw needs a manual restart. ***");
|
|
1641
|
+
console.log("*** macOS: launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist && launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist ***");
|
|
1642
|
+
console.log("*** Linux: systemctl --user restart nanoclaw ***\n");
|
|
1544
1643
|
}
|
|
1545
1644
|
function patchDotEnv2(path, vars) {
|
|
1546
|
-
let content = (0, import_node_fs6.readFileSync)(path, "utf-8");
|
|
1645
|
+
let content = (0, import_node_fs6.existsSync)(path) ? (0, import_node_fs6.readFileSync)(path, "utf-8") : "";
|
|
1547
1646
|
for (const [key, value] of Object.entries(vars)) {
|
|
1548
1647
|
const regex = new RegExp(`^${key}=.*$`, "m");
|
|
1549
1648
|
if (regex.test(content)) {
|
|
1550
1649
|
content = content.replace(regex, `${key}=${value}`);
|
|
1551
1650
|
} else {
|
|
1552
|
-
content
|
|
1553
|
-
|
|
1651
|
+
content = content.trimEnd() + (content.length > 0 ? "\n" : "") + `${key}=${value}
|
|
1652
|
+
`;
|
|
1554
1653
|
}
|
|
1555
1654
|
}
|
|
1556
1655
|
(0, import_node_fs6.writeFileSync)(path, content, "utf-8");
|
|
1557
1656
|
}
|
|
1558
1657
|
|
|
1658
|
+
// src/adapters/llm.ts
|
|
1659
|
+
var DEFAULT_TIMEOUT_MS = 6e4;
|
|
1660
|
+
var OpenAIAdapter = class {
|
|
1661
|
+
apiKey;
|
|
1662
|
+
baseUrl;
|
|
1663
|
+
defaultModel;
|
|
1664
|
+
constructor(config) {
|
|
1665
|
+
if (!config.apiKey) throw new Error("OpenAI API key is required");
|
|
1666
|
+
this.apiKey = config.apiKey;
|
|
1667
|
+
this.baseUrl = (config.baseUrl ?? "https://api.openai.com").replace(/\/+$/, "");
|
|
1668
|
+
this.defaultModel = config.model ?? "gpt-4o-mini";
|
|
1669
|
+
}
|
|
1670
|
+
async complete(prompt, opts) {
|
|
1671
|
+
const response = await this.request({
|
|
1672
|
+
model: opts?.model ?? this.defaultModel,
|
|
1673
|
+
messages: [{ role: "user", content: prompt }],
|
|
1674
|
+
max_tokens: opts?.maxTokens ?? 2e3,
|
|
1675
|
+
temperature: opts?.temperature ?? 0.7
|
|
1676
|
+
}, opts?.timeoutMs);
|
|
1677
|
+
return response.choices?.[0]?.message?.content ?? "";
|
|
1678
|
+
}
|
|
1679
|
+
async json(prompt, opts) {
|
|
1680
|
+
const response = await this.request({
|
|
1681
|
+
model: opts?.model ?? this.defaultModel,
|
|
1682
|
+
messages: [{ role: "user", content: prompt }],
|
|
1683
|
+
max_tokens: opts?.maxTokens ?? 2e3,
|
|
1684
|
+
temperature: opts?.temperature ?? 0.3,
|
|
1685
|
+
response_format: { type: "json_object" }
|
|
1686
|
+
}, opts?.timeoutMs);
|
|
1687
|
+
const text = response.choices?.[0]?.message?.content ?? "{}";
|
|
1688
|
+
return JSON.parse(text);
|
|
1689
|
+
}
|
|
1690
|
+
async request(body, timeoutMs) {
|
|
1691
|
+
const res = await fetch(`${this.baseUrl}/v1/chat/completions`, {
|
|
1692
|
+
method: "POST",
|
|
1693
|
+
headers: {
|
|
1694
|
+
"Content-Type": "application/json",
|
|
1695
|
+
"Authorization": `Bearer ${this.apiKey}`
|
|
1696
|
+
},
|
|
1697
|
+
body: JSON.stringify(body),
|
|
1698
|
+
signal: AbortSignal.timeout(timeoutMs ?? DEFAULT_TIMEOUT_MS)
|
|
1699
|
+
});
|
|
1700
|
+
if (!res.ok) {
|
|
1701
|
+
const text = await res.text().catch(() => "unknown error");
|
|
1702
|
+
throw new Error(`OpenAI API error ${res.status}: ${text.slice(0, 200)}`);
|
|
1703
|
+
}
|
|
1704
|
+
return res.json();
|
|
1705
|
+
}
|
|
1706
|
+
};
|
|
1707
|
+
var AnthropicAdapter = class {
|
|
1708
|
+
apiKey;
|
|
1709
|
+
defaultModel;
|
|
1710
|
+
constructor(config) {
|
|
1711
|
+
if (!config.apiKey) throw new Error("Anthropic API key is required");
|
|
1712
|
+
this.apiKey = config.apiKey;
|
|
1713
|
+
this.defaultModel = config.model ?? "claude-sonnet-4-20250514";
|
|
1714
|
+
}
|
|
1715
|
+
async complete(prompt, opts) {
|
|
1716
|
+
const res = await fetch("https://api.anthropic.com/v1/messages", {
|
|
1717
|
+
method: "POST",
|
|
1718
|
+
headers: {
|
|
1719
|
+
"Content-Type": "application/json",
|
|
1720
|
+
"x-api-key": this.apiKey,
|
|
1721
|
+
"anthropic-version": "2023-06-01"
|
|
1722
|
+
},
|
|
1723
|
+
body: JSON.stringify({
|
|
1724
|
+
model: opts?.model ?? this.defaultModel,
|
|
1725
|
+
max_tokens: opts?.maxTokens ?? 2e3,
|
|
1726
|
+
messages: [{ role: "user", content: prompt }]
|
|
1727
|
+
}),
|
|
1728
|
+
signal: AbortSignal.timeout(opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS)
|
|
1729
|
+
});
|
|
1730
|
+
if (!res.ok) {
|
|
1731
|
+
const text = await res.text().catch(() => "unknown error");
|
|
1732
|
+
throw new Error(`Anthropic API error ${res.status}: ${text.slice(0, 200)}`);
|
|
1733
|
+
}
|
|
1734
|
+
const data = await res.json();
|
|
1735
|
+
return data.content?.[0]?.text ?? "";
|
|
1736
|
+
}
|
|
1737
|
+
async json(prompt, opts) {
|
|
1738
|
+
const text = await this.complete(
|
|
1739
|
+
`${prompt}
|
|
1740
|
+
|
|
1741
|
+
Respond with valid JSON only, no other text.`,
|
|
1742
|
+
{ ...opts, temperature: opts?.temperature ?? 0.3 }
|
|
1743
|
+
);
|
|
1744
|
+
try {
|
|
1745
|
+
return JSON.parse(text.trim());
|
|
1746
|
+
} catch {
|
|
1747
|
+
const match = text.match(/\{[\s\S]*?\}(?=\s*$|\s*[^}\]])/);
|
|
1748
|
+
const arrMatch = text.match(/\[[\s\S]*?\](?=\s*$|\s*[^}\]])/);
|
|
1749
|
+
const candidate = match?.[0] ?? arrMatch?.[0];
|
|
1750
|
+
if (!candidate) throw new Error("No JSON found in response");
|
|
1751
|
+
return JSON.parse(candidate);
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
};
|
|
1755
|
+
var OllamaAdapter = class {
|
|
1756
|
+
baseUrl;
|
|
1757
|
+
defaultModel;
|
|
1758
|
+
constructor(config) {
|
|
1759
|
+
this.baseUrl = (config?.baseUrl ?? "http://localhost:11434").replace(/\/+$/, "");
|
|
1760
|
+
this.defaultModel = config?.model ?? "llama3.1";
|
|
1761
|
+
}
|
|
1762
|
+
async complete(prompt, opts) {
|
|
1763
|
+
const res = await fetch(`${this.baseUrl}/api/generate`, {
|
|
1764
|
+
method: "POST",
|
|
1765
|
+
headers: { "Content-Type": "application/json" },
|
|
1766
|
+
body: JSON.stringify({
|
|
1767
|
+
model: opts?.model ?? this.defaultModel,
|
|
1768
|
+
prompt,
|
|
1769
|
+
stream: false,
|
|
1770
|
+
options: {
|
|
1771
|
+
num_predict: opts?.maxTokens ?? 2e3,
|
|
1772
|
+
temperature: opts?.temperature ?? 0.7
|
|
1773
|
+
}
|
|
1774
|
+
}),
|
|
1775
|
+
signal: AbortSignal.timeout(opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS)
|
|
1776
|
+
});
|
|
1777
|
+
if (!res.ok) {
|
|
1778
|
+
const text = await res.text().catch(() => "unknown error");
|
|
1779
|
+
throw new Error(`Ollama error ${res.status}: ${text.slice(0, 200)}`);
|
|
1780
|
+
}
|
|
1781
|
+
const data = await res.json();
|
|
1782
|
+
return data.response ?? "";
|
|
1783
|
+
}
|
|
1784
|
+
async json(prompt, opts) {
|
|
1785
|
+
const res = await fetch(`${this.baseUrl}/api/generate`, {
|
|
1786
|
+
method: "POST",
|
|
1787
|
+
headers: { "Content-Type": "application/json" },
|
|
1788
|
+
body: JSON.stringify({
|
|
1789
|
+
model: opts?.model ?? this.defaultModel,
|
|
1790
|
+
prompt: `${prompt}
|
|
1791
|
+
|
|
1792
|
+
Respond with valid JSON only.`,
|
|
1793
|
+
stream: false,
|
|
1794
|
+
format: "json",
|
|
1795
|
+
options: {
|
|
1796
|
+
num_predict: opts?.maxTokens ?? 2e3,
|
|
1797
|
+
temperature: opts?.temperature ?? 0.3
|
|
1798
|
+
}
|
|
1799
|
+
}),
|
|
1800
|
+
signal: AbortSignal.timeout(opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS)
|
|
1801
|
+
});
|
|
1802
|
+
if (!res.ok) {
|
|
1803
|
+
const text = await res.text().catch(() => "unknown error");
|
|
1804
|
+
throw new Error(`Ollama error ${res.status}: ${text.slice(0, 200)}`);
|
|
1805
|
+
}
|
|
1806
|
+
const data = await res.json();
|
|
1807
|
+
return JSON.parse(data.response ?? "{}");
|
|
1808
|
+
}
|
|
1809
|
+
};
|
|
1810
|
+
|
|
1559
1811
|
// src/cli/commands.ts
|
|
1812
|
+
function createAnalyzer(config) {
|
|
1813
|
+
switch (config.llm_provider) {
|
|
1814
|
+
case "anthropic":
|
|
1815
|
+
return { analyze: (p) => new AnthropicAdapter({ apiKey: config.llm_api_key }).complete(p) };
|
|
1816
|
+
case "ollama":
|
|
1817
|
+
return { analyze: (p) => new OllamaAdapter({ baseUrl: config.llm_base_url }).complete(p) };
|
|
1818
|
+
case "openai":
|
|
1819
|
+
case "openrouter":
|
|
1820
|
+
case "custom":
|
|
1821
|
+
default:
|
|
1822
|
+
return { analyze: (p) => new OpenAIAdapter({ apiKey: config.llm_api_key, baseUrl: config.llm_base_url }).complete(p) };
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1560
1825
|
async function start() {
|
|
1561
1826
|
const config = loadConfig();
|
|
1562
1827
|
const baseDir = getBecomeDir();
|
|
@@ -1569,7 +1834,14 @@ async function start() {
|
|
|
1569
1834
|
max_skills_per_call: config.max_skills_per_call,
|
|
1570
1835
|
auto_extract: config.auto_extract
|
|
1571
1836
|
};
|
|
1572
|
-
const
|
|
1837
|
+
const originalUrlPath = (0, import_node_path7.join)((0, import_node_os5.homedir)(), ".become", "state", "original_base_url.txt");
|
|
1838
|
+
let originalUpstreamUrl;
|
|
1839
|
+
if ((0, import_node_fs7.existsSync)(originalUrlPath)) {
|
|
1840
|
+
const saved = (0, import_node_fs7.readFileSync)(originalUrlPath, "utf-8").trim();
|
|
1841
|
+
if (saved) originalUpstreamUrl = saved;
|
|
1842
|
+
}
|
|
1843
|
+
const analyzer = createAnalyzer(config);
|
|
1844
|
+
const proxy = createProxyServer(proxyConfig, analyzer, originalUpstreamUrl);
|
|
1573
1845
|
await proxy.listen();
|
|
1574
1846
|
const dashboard = createDashboardServer({
|
|
1575
1847
|
store: proxy.store,
|
|
@@ -1624,15 +1896,24 @@ Connected to: ${config.agent_type}${config.openclaw_agent_id ? ` (agent: ${confi
|
|
|
1624
1896
|
console.log(`[become] ${s.requests_forwarded} requests forwarded, ${s.skills_injected} skills injected, ${s.lessons_extracted} lessons extracted`);
|
|
1625
1897
|
}
|
|
1626
1898
|
}, 6e4);
|
|
1627
|
-
|
|
1899
|
+
let shuttingDown = false;
|
|
1900
|
+
const shutdown = () => {
|
|
1901
|
+
if (shuttingDown) {
|
|
1902
|
+
process.exit(0);
|
|
1903
|
+
return;
|
|
1904
|
+
}
|
|
1905
|
+
shuttingDown = true;
|
|
1628
1906
|
clearInterval(activityInterval);
|
|
1629
1907
|
console.log("\nShutting down...");
|
|
1630
1908
|
try {
|
|
1631
1909
|
turnOff();
|
|
1632
1910
|
} catch {
|
|
1633
1911
|
}
|
|
1634
|
-
|
|
1635
|
-
|
|
1912
|
+
proxy.close().catch(() => {
|
|
1913
|
+
});
|
|
1914
|
+
dashboard.close().catch(() => {
|
|
1915
|
+
});
|
|
1916
|
+
setTimeout(() => process.exit(0), 500);
|
|
1636
1917
|
};
|
|
1637
1918
|
process.on("SIGINT", shutdown);
|
|
1638
1919
|
process.on("SIGTERM", shutdown);
|
|
@@ -1644,7 +1925,7 @@ Patching ${config.agent_type} config...`);
|
|
|
1644
1925
|
console.log(` baseUrl: ${config.llm_base_url} \u2192 localhost:${config.proxy_port}`);
|
|
1645
1926
|
switch (config.agent_type) {
|
|
1646
1927
|
case "openclaw":
|
|
1647
|
-
patchOpenClaw(config
|
|
1928
|
+
patchOpenClaw(config);
|
|
1648
1929
|
break;
|
|
1649
1930
|
case "ironclaw":
|
|
1650
1931
|
patchIronClaw(config);
|
|
@@ -1713,21 +1994,21 @@ Skills: ${approved} approved, ${pending} pending, ${rejected} rejected`);
|
|
|
1713
1994
|
}
|
|
1714
1995
|
|
|
1715
1996
|
// src/cli/init.ts
|
|
1716
|
-
var
|
|
1717
|
-
var
|
|
1997
|
+
var import_node_fs8 = require("fs");
|
|
1998
|
+
var import_node_path8 = require("path");
|
|
1718
1999
|
var import_node_url = require("url");
|
|
1719
2000
|
var import_meta = {};
|
|
1720
2001
|
var command = process.argv[2];
|
|
1721
2002
|
var VERSION = "unknown";
|
|
1722
2003
|
try {
|
|
1723
|
-
const dir = (0,
|
|
1724
|
-
const pkgPath = (0,
|
|
1725
|
-
VERSION = JSON.parse((0,
|
|
2004
|
+
const dir = (0, import_node_path8.dirname)((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
2005
|
+
const pkgPath = (0, import_node_path8.join)(dir, "..", "package.json");
|
|
2006
|
+
VERSION = JSON.parse((0, import_node_fs8.readFileSync)(pkgPath, "utf-8")).version;
|
|
1726
2007
|
} catch {
|
|
1727
2008
|
try {
|
|
1728
|
-
const dir = (0,
|
|
1729
|
-
const pkgPath = (0,
|
|
1730
|
-
VERSION = JSON.parse((0,
|
|
2009
|
+
const dir = (0, import_node_path8.dirname)((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
2010
|
+
const pkgPath = (0, import_node_path8.join)(dir, "..", "..", "package.json");
|
|
2011
|
+
VERSION = JSON.parse((0, import_node_fs8.readFileSync)(pkgPath, "utf-8")).version;
|
|
1731
2012
|
} catch {
|
|
1732
2013
|
}
|
|
1733
2014
|
}
|