@openclawcity/become 1.0.13 → 1.0.19
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 +463 -151
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +463 -151
- 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,187 @@ 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
|
-
|
|
167
|
+
const originalUrl = readSafe(ORIGINAL_URL_PATH);
|
|
168
|
+
const patchInfo = readSafe(PATCHED_PROVIDER_PATH);
|
|
169
|
+
if (!originalUrl || !patchInfo) {
|
|
170
|
+
cleanState();
|
|
171
|
+
return;
|
|
169
172
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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");
|
|
182
|
+
}
|
|
183
|
+
}
|
|
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
|
+
}
|
|
177
191
|
}
|
|
178
192
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
193
|
+
cleanLegacy();
|
|
194
|
+
cleanState();
|
|
195
|
+
restartGateway();
|
|
196
|
+
}
|
|
197
|
+
function cleanLegacy() {
|
|
198
|
+
if ((0, import_node_fs2.existsSync)(OPENCLAW_CONFIG)) {
|
|
199
|
+
try {
|
|
200
|
+
const config = parseConfig((0, import_node_fs2.readFileSync)(OPENCLAW_CONFIG, "utf-8"));
|
|
201
|
+
let changed = false;
|
|
202
|
+
if (config.models?.providers?.become) {
|
|
203
|
+
delete config.models.providers.become;
|
|
204
|
+
changed = true;
|
|
189
205
|
}
|
|
190
|
-
|
|
191
|
-
if (
|
|
192
|
-
config.agents.defaults.model.primary =
|
|
206
|
+
const primary = config.agents?.defaults?.model?.primary ?? "";
|
|
207
|
+
if (primary.startsWith("become/")) {
|
|
208
|
+
config.agents.defaults.model.primary = "openrouter/" + primary.slice("become/".length);
|
|
209
|
+
changed = true;
|
|
210
|
+
}
|
|
211
|
+
for (const prov of Object.values(config.models?.providers ?? {})) {
|
|
212
|
+
if (prov && typeof prov === "object" && "_originalModel" in prov) {
|
|
213
|
+
delete prov._originalModel;
|
|
214
|
+
changed = true;
|
|
215
|
+
}
|
|
193
216
|
}
|
|
217
|
+
if (changed) (0, import_node_fs2.writeFileSync)(OPENCLAW_CONFIG, JSON.stringify(config, null, 2), "utf-8");
|
|
218
|
+
} catch {
|
|
194
219
|
}
|
|
195
220
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
221
|
+
try {
|
|
222
|
+
const clawConfig = parseConfig((0, import_node_fs2.readFileSync)(OPENCLAW_CONFIG, "utf-8"));
|
|
223
|
+
const modelsJsonPath = getModelsJsonPath(clawConfig);
|
|
224
|
+
if (modelsJsonPath && (0, import_node_fs2.existsSync)(modelsJsonPath)) {
|
|
225
|
+
const models = JSON.parse((0, import_node_fs2.readFileSync)(modelsJsonPath, "utf-8"));
|
|
226
|
+
let changed = false;
|
|
227
|
+
if (models.providers?.become) {
|
|
228
|
+
delete models.providers.become;
|
|
229
|
+
changed = true;
|
|
230
|
+
}
|
|
231
|
+
if (changed) (0, import_node_fs2.writeFileSync)(modelsJsonPath, JSON.stringify(models, null, 2), "utf-8");
|
|
202
232
|
}
|
|
233
|
+
} catch {
|
|
203
234
|
}
|
|
204
|
-
(0, import_node_fs2.writeFileSync)(OPENCLAW_CONFIG, JSON.stringify(config, null, 2), "utf-8");
|
|
205
|
-
restartGateway();
|
|
206
235
|
}
|
|
207
236
|
function listOpenClawAgents() {
|
|
208
237
|
if (!(0, import_node_fs2.existsSync)(OPENCLAW_CONFIG)) return [];
|
|
209
238
|
try {
|
|
210
|
-
const config =
|
|
239
|
+
const config = parseConfig((0, import_node_fs2.readFileSync)(OPENCLAW_CONFIG, "utf-8"));
|
|
211
240
|
const agents = config.agents?.list ?? [];
|
|
212
|
-
const defaultModel =
|
|
241
|
+
const defaultModel = config.agents?.defaults?.model?.primary ?? "unknown";
|
|
213
242
|
if (agents.length === 0) {
|
|
214
243
|
return [{ id: "_defaults", model: defaultModel }];
|
|
215
244
|
}
|
|
216
245
|
return agents.map((a) => ({
|
|
217
246
|
id: a.id,
|
|
218
|
-
model:
|
|
247
|
+
model: a.model ?? defaultModel
|
|
219
248
|
}));
|
|
220
249
|
} catch {
|
|
221
250
|
return [];
|
|
222
251
|
}
|
|
223
252
|
}
|
|
224
|
-
function
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
253
|
+
function getModelsJsonPath(clawConfig) {
|
|
254
|
+
const agentList = clawConfig.agents?.list ?? [];
|
|
255
|
+
const defaultAgent = agentList.find((a) => a.default) ?? agentList[0];
|
|
256
|
+
if (defaultAgent?.agentDir) {
|
|
257
|
+
return (0, import_node_path2.join)(defaultAgent.agentDir.replace("~", (0, import_node_os2.homedir)()), "models.json");
|
|
258
|
+
}
|
|
259
|
+
const mainPath = (0, import_node_path2.join)((0, import_node_os2.homedir)(), ".openclaw", "agents", "main", "agent", "models.json");
|
|
260
|
+
if ((0, import_node_fs2.existsSync)(mainPath)) return mainPath;
|
|
261
|
+
return null;
|
|
229
262
|
}
|
|
230
|
-
function
|
|
263
|
+
function parseConfig(raw) {
|
|
231
264
|
const stripped = raw.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "").replace(/,\s*([\]}])/g, "$1");
|
|
232
265
|
return JSON.parse(stripped);
|
|
233
266
|
}
|
|
234
|
-
function
|
|
267
|
+
function readSafe(path) {
|
|
235
268
|
try {
|
|
236
269
|
return (0, import_node_fs2.existsSync)(path) ? (0, import_node_fs2.readFileSync)(path, "utf-8").trim() : "";
|
|
237
270
|
} catch {
|
|
238
271
|
return "";
|
|
239
272
|
}
|
|
240
273
|
}
|
|
274
|
+
function cleanState() {
|
|
275
|
+
for (const f of [ORIGINAL_URL_PATH, PATCHED_PROVIDER_PATH]) {
|
|
276
|
+
try {
|
|
277
|
+
(0, import_node_fs2.writeFileSync)(f, "", "utf-8");
|
|
278
|
+
} catch {
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
241
282
|
function restartGateway() {
|
|
242
283
|
console.log("Restarting OpenClaw gateway...");
|
|
243
284
|
try {
|
|
@@ -323,6 +364,11 @@ Proxy port (default 30001): `);
|
|
|
323
364
|
}
|
|
324
365
|
}
|
|
325
366
|
|
|
367
|
+
// src/cli/commands.ts
|
|
368
|
+
var import_node_fs7 = require("fs");
|
|
369
|
+
var import_node_path7 = require("path");
|
|
370
|
+
var import_node_os5 = require("os");
|
|
371
|
+
|
|
326
372
|
// src/proxy/server.ts
|
|
327
373
|
var import_node_http = require("http");
|
|
328
374
|
|
|
@@ -749,7 +795,7 @@ Rules:
|
|
|
749
795
|
|
|
750
796
|
// src/proxy/server.ts
|
|
751
797
|
var SKILL_CACHE_TTL_MS = 5e3;
|
|
752
|
-
function createProxyServer(config, analyzer) {
|
|
798
|
+
function createProxyServer(config, analyzer, overrideUpstreamUrl) {
|
|
753
799
|
const store = new FileSkillStore({ baseDir: config.baseDir });
|
|
754
800
|
const trust = new TrustManager(config.baseDir);
|
|
755
801
|
const extractor = analyzer ? new LessonExtractor(store, trust, analyzer) : null;
|
|
@@ -796,7 +842,7 @@ function createProxyServer(config, analyzer) {
|
|
|
796
842
|
stats.skills_injected++;
|
|
797
843
|
}
|
|
798
844
|
}
|
|
799
|
-
const upstreamUrl = buildUpstreamUrl(config, req.url);
|
|
845
|
+
const upstreamUrl = buildUpstreamUrl(overrideUpstreamUrl ?? config.llm_base_url, req.url);
|
|
800
846
|
const upstreamHeaders = buildUpstreamHeaders(config, req.headers);
|
|
801
847
|
const isStreaming = body.stream === true;
|
|
802
848
|
const modifiedBody = JSON.stringify(body);
|
|
@@ -880,8 +926,8 @@ function readBody(req) {
|
|
|
880
926
|
req.on("error", reject);
|
|
881
927
|
});
|
|
882
928
|
}
|
|
883
|
-
function buildUpstreamUrl(
|
|
884
|
-
const base =
|
|
929
|
+
function buildUpstreamUrl(baseUrl, path) {
|
|
930
|
+
const base = baseUrl.replace(/\/+$/, "");
|
|
885
931
|
return `${base}${path}`;
|
|
886
932
|
}
|
|
887
933
|
function buildUpstreamHeaders(config, incomingHeaders) {
|
|
@@ -1433,49 +1479,88 @@ var import_node_fs5 = require("fs");
|
|
|
1433
1479
|
var import_node_path5 = require("path");
|
|
1434
1480
|
var import_node_os3 = require("os");
|
|
1435
1481
|
var import_node_child_process2 = require("child_process");
|
|
1436
|
-
var IRONCLAW_ENV = (0, import_node_path5.join)((0, import_node_os3.homedir)(), ".ironclaw", ".env");
|
|
1482
|
+
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
1483
|
var BACKUP_PATH2 = (0, import_node_path5.join)((0, import_node_os3.homedir)(), ".become", "state", "original_ironclaw.env");
|
|
1438
1484
|
function patchIronClaw(config) {
|
|
1439
1485
|
if (!(0, import_node_fs5.existsSync)(IRONCLAW_ENV)) {
|
|
1440
1486
|
throw new Error(`IronClaw .env not found at ${IRONCLAW_ENV}`);
|
|
1441
1487
|
}
|
|
1488
|
+
if ((0, import_node_fs5.existsSync)(BACKUP_PATH2)) {
|
|
1489
|
+
console.log("become is already connected to IronClaw. Run `become off` first.");
|
|
1490
|
+
return;
|
|
1491
|
+
}
|
|
1442
1492
|
(0, import_node_fs5.mkdirSync)((0, import_node_path5.join)((0, import_node_os3.homedir)(), ".become", "state"), { recursive: true });
|
|
1443
1493
|
(0, import_node_fs5.copyFileSync)(IRONCLAW_ENV, BACKUP_PATH2);
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1494
|
+
const content = (0, import_node_fs5.readFileSync)(IRONCLAW_ENV, "utf-8");
|
|
1495
|
+
const backendMatch = content.match(/^LLM_BACKEND=(.+)$/m);
|
|
1496
|
+
const backend = backendMatch?.[1]?.trim().toLowerCase() ?? "openai_compatible";
|
|
1497
|
+
const proxyUrl = `http://127.0.0.1:${config.proxy_port}`;
|
|
1498
|
+
const vars = {};
|
|
1499
|
+
switch (backend) {
|
|
1500
|
+
case "anthropic":
|
|
1501
|
+
vars["ANTHROPIC_BASE_URL"] = proxyUrl;
|
|
1502
|
+
break;
|
|
1503
|
+
case "ollama":
|
|
1504
|
+
vars["OLLAMA_BASE_URL"] = proxyUrl;
|
|
1505
|
+
break;
|
|
1506
|
+
case "nearai":
|
|
1507
|
+
case "near_ai":
|
|
1508
|
+
case "near":
|
|
1509
|
+
vars["NEARAI_BASE_URL"] = proxyUrl;
|
|
1510
|
+
break;
|
|
1511
|
+
default:
|
|
1512
|
+
vars["LLM_BASE_URL"] = proxyUrl;
|
|
1513
|
+
break;
|
|
1454
1514
|
}
|
|
1515
|
+
patchDotEnv(IRONCLAW_ENV, vars);
|
|
1516
|
+
console.log(` backend: ${backend}`);
|
|
1517
|
+
console.log(` patched: ${Object.keys(vars).join(", ")} -> localhost:${config.proxy_port}`);
|
|
1518
|
+
restartIronClaw();
|
|
1455
1519
|
}
|
|
1456
1520
|
function restoreIronClaw() {
|
|
1457
1521
|
if (!(0, import_node_fs5.existsSync)(BACKUP_PATH2)) {
|
|
1458
|
-
|
|
1522
|
+
return;
|
|
1459
1523
|
}
|
|
1460
1524
|
(0, import_node_fs5.copyFileSync)(BACKUP_PATH2, IRONCLAW_ENV);
|
|
1525
|
+
try {
|
|
1526
|
+
(0, import_node_fs5.unlinkSync)(BACKUP_PATH2);
|
|
1527
|
+
} catch {
|
|
1528
|
+
}
|
|
1529
|
+
restartIronClaw();
|
|
1530
|
+
}
|
|
1531
|
+
function restartIronClaw() {
|
|
1461
1532
|
console.log("Restarting IronClaw...");
|
|
1462
1533
|
try {
|
|
1463
|
-
(0, import_node_child_process2.execSync)("ironclaw service
|
|
1534
|
+
(0, import_node_child_process2.execSync)("ironclaw service stop", { stdio: "pipe", timeout: 1e4 });
|
|
1535
|
+
(0, import_node_child_process2.execSync)("ironclaw service start", { stdio: "pipe", timeout: 1e4 });
|
|
1464
1536
|
console.log("IronClaw restarted.");
|
|
1537
|
+
return;
|
|
1538
|
+
} catch {
|
|
1539
|
+
}
|
|
1540
|
+
try {
|
|
1541
|
+
(0, import_node_child_process2.execSync)("launchctl kickstart -k gui/$(id -u)/com.ironclaw.daemon", { stdio: "pipe", timeout: 1e4 });
|
|
1542
|
+
console.log("IronClaw restarted via launchctl.");
|
|
1543
|
+
return;
|
|
1465
1544
|
} catch {
|
|
1466
|
-
console.log("\n*** IronClaw needs a manual restart. ***");
|
|
1467
|
-
console.log("*** Run: ironclaw service restart ***\n");
|
|
1468
1545
|
}
|
|
1546
|
+
try {
|
|
1547
|
+
(0, import_node_child_process2.execSync)("systemctl --user restart ironclaw", { stdio: "pipe", timeout: 1e4 });
|
|
1548
|
+
console.log("IronClaw restarted via systemd.");
|
|
1549
|
+
return;
|
|
1550
|
+
} catch {
|
|
1551
|
+
}
|
|
1552
|
+
console.log("\n*** IronClaw needs a manual restart. ***");
|
|
1553
|
+
console.log("*** Run: ironclaw service stop && ironclaw service start ***\n");
|
|
1469
1554
|
}
|
|
1470
1555
|
function patchDotEnv(path, vars) {
|
|
1471
|
-
let content = (0, import_node_fs5.readFileSync)(path, "utf-8");
|
|
1556
|
+
let content = (0, import_node_fs5.existsSync)(path) ? (0, import_node_fs5.readFileSync)(path, "utf-8") : "";
|
|
1472
1557
|
for (const [key, value] of Object.entries(vars)) {
|
|
1473
1558
|
const regex = new RegExp(`^${key}=.*$`, "m");
|
|
1474
1559
|
if (regex.test(content)) {
|
|
1475
1560
|
content = content.replace(regex, `${key}=${value}`);
|
|
1476
1561
|
} else {
|
|
1477
|
-
content
|
|
1478
|
-
|
|
1562
|
+
content = content.trimEnd() + (content.length > 0 ? "\n" : "") + `${key}=${value}
|
|
1563
|
+
`;
|
|
1479
1564
|
}
|
|
1480
1565
|
}
|
|
1481
1566
|
(0, import_node_fs5.writeFileSync)(path, content, "utf-8");
|
|
@@ -1487,40 +1572,88 @@ var import_node_path6 = require("path");
|
|
|
1487
1572
|
var import_node_os4 = require("os");
|
|
1488
1573
|
var import_node_child_process3 = require("child_process");
|
|
1489
1574
|
var BACKUP_PATH3 = (0, import_node_path6.join)((0, import_node_os4.homedir)(), ".become", "state", "original_nanoclaw.env");
|
|
1575
|
+
var PATCHED_ENV_PATH_FILE = (0, import_node_path6.join)((0, import_node_os4.homedir)(), ".become", "state", "nanoclaw_env_path.txt");
|
|
1576
|
+
var NANOCLAW_URL_VAR = "ANTHROPIC_BASE_URL";
|
|
1490
1577
|
function patchNanoClaw(config) {
|
|
1491
1578
|
const envPath = findNanoClawEnv();
|
|
1492
1579
|
if (!envPath) {
|
|
1493
|
-
throw new Error(
|
|
1580
|
+
throw new Error(
|
|
1581
|
+
`Could not find NanoClaw .env file.
|
|
1582
|
+
NanoClaw stores .env in its project root (where you cloned it).
|
|
1583
|
+
Set ${NANOCLAW_URL_VAR}=http://127.0.0.1:${config.proxy_port} manually in your NanoClaw .env file.`
|
|
1584
|
+
);
|
|
1585
|
+
}
|
|
1586
|
+
if ((0, import_node_fs6.existsSync)(BACKUP_PATH3)) {
|
|
1587
|
+
console.log("become is already connected to NanoClaw. Run `become off` first.");
|
|
1588
|
+
return;
|
|
1494
1589
|
}
|
|
1495
1590
|
(0, import_node_fs6.mkdirSync)((0, import_node_path6.join)((0, import_node_os4.homedir)(), ".become", "state"), { recursive: true });
|
|
1496
1591
|
(0, import_node_fs6.copyFileSync)(envPath, BACKUP_PATH3);
|
|
1592
|
+
(0, import_node_fs6.writeFileSync)(PATCHED_ENV_PATH_FILE, envPath, "utf-8");
|
|
1497
1593
|
patchDotEnv2(envPath, {
|
|
1498
|
-
|
|
1594
|
+
[NANOCLAW_URL_VAR]: `http://127.0.0.1:${config.proxy_port}`
|
|
1499
1595
|
});
|
|
1596
|
+
console.log(` env file: ${envPath}`);
|
|
1597
|
+
console.log(` patched: ${NANOCLAW_URL_VAR} -> localhost:${config.proxy_port}`);
|
|
1500
1598
|
restartNanoClaw();
|
|
1501
1599
|
}
|
|
1502
1600
|
function restoreNanoClaw() {
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1601
|
+
if (!(0, import_node_fs6.existsSync)(BACKUP_PATH3)) {
|
|
1602
|
+
return;
|
|
1603
|
+
}
|
|
1604
|
+
let envPath = null;
|
|
1605
|
+
if ((0, import_node_fs6.existsSync)(PATCHED_ENV_PATH_FILE)) {
|
|
1606
|
+
envPath = (0, import_node_fs6.readFileSync)(PATCHED_ENV_PATH_FILE, "utf-8").trim();
|
|
1607
|
+
}
|
|
1608
|
+
if (!envPath) {
|
|
1609
|
+
envPath = findNanoClawEnv();
|
|
1610
|
+
}
|
|
1611
|
+
if (!envPath) {
|
|
1612
|
+
console.log("Warning: Cannot find NanoClaw .env to restore. Backup is at " + BACKUP_PATH3);
|
|
1613
|
+
return;
|
|
1506
1614
|
}
|
|
1507
1615
|
(0, import_node_fs6.copyFileSync)(BACKUP_PATH3, envPath);
|
|
1616
|
+
try {
|
|
1617
|
+
(0, import_node_fs6.unlinkSync)(BACKUP_PATH3);
|
|
1618
|
+
} catch {
|
|
1619
|
+
}
|
|
1620
|
+
try {
|
|
1621
|
+
(0, import_node_fs6.unlinkSync)(PATCHED_ENV_PATH_FILE);
|
|
1622
|
+
} catch {
|
|
1623
|
+
}
|
|
1508
1624
|
restartNanoClaw();
|
|
1509
1625
|
}
|
|
1510
1626
|
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");
|
|
1627
|
+
const candidates = [];
|
|
1628
|
+
const plistPath = (0, import_node_path6.join)((0, import_node_os4.homedir)(), "Library", "LaunchAgents", "com.nanoclaw.plist");
|
|
1516
1629
|
if ((0, import_node_fs6.existsSync)(plistPath)) {
|
|
1517
1630
|
try {
|
|
1518
1631
|
const plist = (0, import_node_fs6.readFileSync)(plistPath, "utf-8");
|
|
1519
|
-
const match = plist.match(/<string>([^<]
|
|
1520
|
-
if (match) candidates.
|
|
1632
|
+
const match = plist.match(/<key>WorkingDirectory<\/key>\s*<string>([^<]+)<\/string>/);
|
|
1633
|
+
if (match) candidates.push((0, import_node_path6.join)(match[1], ".env"));
|
|
1521
1634
|
} catch {
|
|
1522
1635
|
}
|
|
1523
1636
|
}
|
|
1637
|
+
const userUnit = (0, import_node_path6.join)((0, import_node_os4.homedir)(), ".config", "systemd", "user", "nanoclaw.service");
|
|
1638
|
+
if ((0, import_node_fs6.existsSync)(userUnit)) {
|
|
1639
|
+
try {
|
|
1640
|
+
const unit = (0, import_node_fs6.readFileSync)(userUnit, "utf-8");
|
|
1641
|
+
const match = unit.match(/WorkingDirectory=(.+)/);
|
|
1642
|
+
if (match) candidates.push((0, import_node_path6.join)(match[1].trim(), ".env"));
|
|
1643
|
+
} catch {
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
const rootUnit = "/etc/systemd/system/nanoclaw.service";
|
|
1647
|
+
if ((0, import_node_fs6.existsSync)(rootUnit)) {
|
|
1648
|
+
try {
|
|
1649
|
+
const unit = (0, import_node_fs6.readFileSync)(rootUnit, "utf-8");
|
|
1650
|
+
const match = unit.match(/WorkingDirectory=(.+)/);
|
|
1651
|
+
if (match) candidates.push((0, import_node_path6.join)(match[1].trim(), ".env"));
|
|
1652
|
+
} catch {
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
candidates.push((0, import_node_path6.join)((0, import_node_os4.homedir)(), "nanoclaw", ".env"));
|
|
1656
|
+
candidates.push("/opt/nanoclaw/.env");
|
|
1524
1657
|
for (const path of candidates) {
|
|
1525
1658
|
if ((0, import_node_fs6.existsSync)(path)) return path;
|
|
1526
1659
|
}
|
|
@@ -1528,35 +1661,207 @@ function findNanoClawEnv() {
|
|
|
1528
1661
|
}
|
|
1529
1662
|
function restartNanoClaw() {
|
|
1530
1663
|
console.log("Restarting NanoClaw...");
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
console.log("NanoClaw restarted.");
|
|
1534
|
-
} catch {
|
|
1664
|
+
const plistPath = (0, import_node_path6.join)((0, import_node_os4.homedir)(), "Library", "LaunchAgents", "com.nanoclaw.plist");
|
|
1665
|
+
if ((0, import_node_fs6.existsSync)(plistPath)) {
|
|
1535
1666
|
try {
|
|
1536
|
-
(0, import_node_child_process3.execSync)(
|
|
1667
|
+
(0, import_node_child_process3.execSync)(`launchctl unload "${plistPath}"`, { stdio: "pipe", timeout: 1e4 });
|
|
1668
|
+
(0, import_node_child_process3.execSync)(`launchctl load "${plistPath}"`, { stdio: "pipe", timeout: 1e4 });
|
|
1537
1669
|
console.log("NanoClaw restarted.");
|
|
1670
|
+
return;
|
|
1538
1671
|
} 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
1672
|
}
|
|
1543
1673
|
}
|
|
1674
|
+
try {
|
|
1675
|
+
(0, import_node_child_process3.execSync)("systemctl --user restart nanoclaw", { stdio: "pipe", timeout: 1e4 });
|
|
1676
|
+
console.log("NanoClaw restarted.");
|
|
1677
|
+
return;
|
|
1678
|
+
} catch {
|
|
1679
|
+
}
|
|
1680
|
+
console.log("\n*** NanoClaw needs a manual restart. ***");
|
|
1681
|
+
console.log("*** macOS: launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist && launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist ***");
|
|
1682
|
+
console.log("*** Linux: systemctl --user restart nanoclaw ***\n");
|
|
1544
1683
|
}
|
|
1545
1684
|
function patchDotEnv2(path, vars) {
|
|
1546
|
-
let content = (0, import_node_fs6.readFileSync)(path, "utf-8");
|
|
1685
|
+
let content = (0, import_node_fs6.existsSync)(path) ? (0, import_node_fs6.readFileSync)(path, "utf-8") : "";
|
|
1547
1686
|
for (const [key, value] of Object.entries(vars)) {
|
|
1548
1687
|
const regex = new RegExp(`^${key}=.*$`, "m");
|
|
1549
1688
|
if (regex.test(content)) {
|
|
1550
1689
|
content = content.replace(regex, `${key}=${value}`);
|
|
1551
1690
|
} else {
|
|
1552
|
-
content
|
|
1553
|
-
|
|
1691
|
+
content = content.trimEnd() + (content.length > 0 ? "\n" : "") + `${key}=${value}
|
|
1692
|
+
`;
|
|
1554
1693
|
}
|
|
1555
1694
|
}
|
|
1556
1695
|
(0, import_node_fs6.writeFileSync)(path, content, "utf-8");
|
|
1557
1696
|
}
|
|
1558
1697
|
|
|
1698
|
+
// src/adapters/llm.ts
|
|
1699
|
+
var DEFAULT_TIMEOUT_MS = 6e4;
|
|
1700
|
+
var OpenAIAdapter = class {
|
|
1701
|
+
apiKey;
|
|
1702
|
+
baseUrl;
|
|
1703
|
+
defaultModel;
|
|
1704
|
+
constructor(config) {
|
|
1705
|
+
if (!config.apiKey) throw new Error("OpenAI API key is required");
|
|
1706
|
+
this.apiKey = config.apiKey;
|
|
1707
|
+
this.baseUrl = (config.baseUrl ?? "https://api.openai.com").replace(/\/+$/, "");
|
|
1708
|
+
this.defaultModel = config.model ?? "gpt-4o-mini";
|
|
1709
|
+
}
|
|
1710
|
+
async complete(prompt, opts) {
|
|
1711
|
+
const response = await this.request({
|
|
1712
|
+
model: opts?.model ?? this.defaultModel,
|
|
1713
|
+
messages: [{ role: "user", content: prompt }],
|
|
1714
|
+
max_tokens: opts?.maxTokens ?? 2e3,
|
|
1715
|
+
temperature: opts?.temperature ?? 0.7
|
|
1716
|
+
}, opts?.timeoutMs);
|
|
1717
|
+
return response.choices?.[0]?.message?.content ?? "";
|
|
1718
|
+
}
|
|
1719
|
+
async json(prompt, opts) {
|
|
1720
|
+
const response = await this.request({
|
|
1721
|
+
model: opts?.model ?? this.defaultModel,
|
|
1722
|
+
messages: [{ role: "user", content: prompt }],
|
|
1723
|
+
max_tokens: opts?.maxTokens ?? 2e3,
|
|
1724
|
+
temperature: opts?.temperature ?? 0.3,
|
|
1725
|
+
response_format: { type: "json_object" }
|
|
1726
|
+
}, opts?.timeoutMs);
|
|
1727
|
+
const text = response.choices?.[0]?.message?.content ?? "{}";
|
|
1728
|
+
return JSON.parse(text);
|
|
1729
|
+
}
|
|
1730
|
+
async request(body, timeoutMs) {
|
|
1731
|
+
const res = await fetch(`${this.baseUrl}/v1/chat/completions`, {
|
|
1732
|
+
method: "POST",
|
|
1733
|
+
headers: {
|
|
1734
|
+
"Content-Type": "application/json",
|
|
1735
|
+
"Authorization": `Bearer ${this.apiKey}`
|
|
1736
|
+
},
|
|
1737
|
+
body: JSON.stringify(body),
|
|
1738
|
+
signal: AbortSignal.timeout(timeoutMs ?? DEFAULT_TIMEOUT_MS)
|
|
1739
|
+
});
|
|
1740
|
+
if (!res.ok) {
|
|
1741
|
+
const text = await res.text().catch(() => "unknown error");
|
|
1742
|
+
throw new Error(`OpenAI API error ${res.status}: ${text.slice(0, 200)}`);
|
|
1743
|
+
}
|
|
1744
|
+
return res.json();
|
|
1745
|
+
}
|
|
1746
|
+
};
|
|
1747
|
+
var AnthropicAdapter = class {
|
|
1748
|
+
apiKey;
|
|
1749
|
+
defaultModel;
|
|
1750
|
+
constructor(config) {
|
|
1751
|
+
if (!config.apiKey) throw new Error("Anthropic API key is required");
|
|
1752
|
+
this.apiKey = config.apiKey;
|
|
1753
|
+
this.defaultModel = config.model ?? "claude-sonnet-4-20250514";
|
|
1754
|
+
}
|
|
1755
|
+
async complete(prompt, opts) {
|
|
1756
|
+
const res = await fetch("https://api.anthropic.com/v1/messages", {
|
|
1757
|
+
method: "POST",
|
|
1758
|
+
headers: {
|
|
1759
|
+
"Content-Type": "application/json",
|
|
1760
|
+
"x-api-key": this.apiKey,
|
|
1761
|
+
"anthropic-version": "2023-06-01"
|
|
1762
|
+
},
|
|
1763
|
+
body: JSON.stringify({
|
|
1764
|
+
model: opts?.model ?? this.defaultModel,
|
|
1765
|
+
max_tokens: opts?.maxTokens ?? 2e3,
|
|
1766
|
+
messages: [{ role: "user", content: prompt }]
|
|
1767
|
+
}),
|
|
1768
|
+
signal: AbortSignal.timeout(opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS)
|
|
1769
|
+
});
|
|
1770
|
+
if (!res.ok) {
|
|
1771
|
+
const text = await res.text().catch(() => "unknown error");
|
|
1772
|
+
throw new Error(`Anthropic API error ${res.status}: ${text.slice(0, 200)}`);
|
|
1773
|
+
}
|
|
1774
|
+
const data = await res.json();
|
|
1775
|
+
return data.content?.[0]?.text ?? "";
|
|
1776
|
+
}
|
|
1777
|
+
async json(prompt, opts) {
|
|
1778
|
+
const text = await this.complete(
|
|
1779
|
+
`${prompt}
|
|
1780
|
+
|
|
1781
|
+
Respond with valid JSON only, no other text.`,
|
|
1782
|
+
{ ...opts, temperature: opts?.temperature ?? 0.3 }
|
|
1783
|
+
);
|
|
1784
|
+
try {
|
|
1785
|
+
return JSON.parse(text.trim());
|
|
1786
|
+
} catch {
|
|
1787
|
+
const match = text.match(/\{[\s\S]*?\}(?=\s*$|\s*[^}\]])/);
|
|
1788
|
+
const arrMatch = text.match(/\[[\s\S]*?\](?=\s*$|\s*[^}\]])/);
|
|
1789
|
+
const candidate = match?.[0] ?? arrMatch?.[0];
|
|
1790
|
+
if (!candidate) throw new Error("No JSON found in response");
|
|
1791
|
+
return JSON.parse(candidate);
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
};
|
|
1795
|
+
var OllamaAdapter = class {
|
|
1796
|
+
baseUrl;
|
|
1797
|
+
defaultModel;
|
|
1798
|
+
constructor(config) {
|
|
1799
|
+
this.baseUrl = (config?.baseUrl ?? "http://localhost:11434").replace(/\/+$/, "");
|
|
1800
|
+
this.defaultModel = config?.model ?? "llama3.1";
|
|
1801
|
+
}
|
|
1802
|
+
async complete(prompt, opts) {
|
|
1803
|
+
const res = await fetch(`${this.baseUrl}/api/generate`, {
|
|
1804
|
+
method: "POST",
|
|
1805
|
+
headers: { "Content-Type": "application/json" },
|
|
1806
|
+
body: JSON.stringify({
|
|
1807
|
+
model: opts?.model ?? this.defaultModel,
|
|
1808
|
+
prompt,
|
|
1809
|
+
stream: false,
|
|
1810
|
+
options: {
|
|
1811
|
+
num_predict: opts?.maxTokens ?? 2e3,
|
|
1812
|
+
temperature: opts?.temperature ?? 0.7
|
|
1813
|
+
}
|
|
1814
|
+
}),
|
|
1815
|
+
signal: AbortSignal.timeout(opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS)
|
|
1816
|
+
});
|
|
1817
|
+
if (!res.ok) {
|
|
1818
|
+
const text = await res.text().catch(() => "unknown error");
|
|
1819
|
+
throw new Error(`Ollama error ${res.status}: ${text.slice(0, 200)}`);
|
|
1820
|
+
}
|
|
1821
|
+
const data = await res.json();
|
|
1822
|
+
return data.response ?? "";
|
|
1823
|
+
}
|
|
1824
|
+
async json(prompt, opts) {
|
|
1825
|
+
const res = await fetch(`${this.baseUrl}/api/generate`, {
|
|
1826
|
+
method: "POST",
|
|
1827
|
+
headers: { "Content-Type": "application/json" },
|
|
1828
|
+
body: JSON.stringify({
|
|
1829
|
+
model: opts?.model ?? this.defaultModel,
|
|
1830
|
+
prompt: `${prompt}
|
|
1831
|
+
|
|
1832
|
+
Respond with valid JSON only.`,
|
|
1833
|
+
stream: false,
|
|
1834
|
+
format: "json",
|
|
1835
|
+
options: {
|
|
1836
|
+
num_predict: opts?.maxTokens ?? 2e3,
|
|
1837
|
+
temperature: opts?.temperature ?? 0.3
|
|
1838
|
+
}
|
|
1839
|
+
}),
|
|
1840
|
+
signal: AbortSignal.timeout(opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS)
|
|
1841
|
+
});
|
|
1842
|
+
if (!res.ok) {
|
|
1843
|
+
const text = await res.text().catch(() => "unknown error");
|
|
1844
|
+
throw new Error(`Ollama error ${res.status}: ${text.slice(0, 200)}`);
|
|
1845
|
+
}
|
|
1846
|
+
const data = await res.json();
|
|
1847
|
+
return JSON.parse(data.response ?? "{}");
|
|
1848
|
+
}
|
|
1849
|
+
};
|
|
1850
|
+
|
|
1559
1851
|
// src/cli/commands.ts
|
|
1852
|
+
function createAnalyzer(config) {
|
|
1853
|
+
switch (config.llm_provider) {
|
|
1854
|
+
case "anthropic":
|
|
1855
|
+
return { analyze: (p) => new AnthropicAdapter({ apiKey: config.llm_api_key }).complete(p) };
|
|
1856
|
+
case "ollama":
|
|
1857
|
+
return { analyze: (p) => new OllamaAdapter({ baseUrl: config.llm_base_url }).complete(p) };
|
|
1858
|
+
case "openai":
|
|
1859
|
+
case "openrouter":
|
|
1860
|
+
case "custom":
|
|
1861
|
+
default:
|
|
1862
|
+
return { analyze: (p) => new OpenAIAdapter({ apiKey: config.llm_api_key, baseUrl: config.llm_base_url }).complete(p) };
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1560
1865
|
async function start() {
|
|
1561
1866
|
const config = loadConfig();
|
|
1562
1867
|
const baseDir = getBecomeDir();
|
|
@@ -1569,7 +1874,14 @@ async function start() {
|
|
|
1569
1874
|
max_skills_per_call: config.max_skills_per_call,
|
|
1570
1875
|
auto_extract: config.auto_extract
|
|
1571
1876
|
};
|
|
1572
|
-
const
|
|
1877
|
+
const originalUrlPath = (0, import_node_path7.join)((0, import_node_os5.homedir)(), ".become", "state", "original_base_url.txt");
|
|
1878
|
+
let originalUpstreamUrl;
|
|
1879
|
+
if ((0, import_node_fs7.existsSync)(originalUrlPath)) {
|
|
1880
|
+
const saved = (0, import_node_fs7.readFileSync)(originalUrlPath, "utf-8").trim();
|
|
1881
|
+
if (saved) originalUpstreamUrl = saved;
|
|
1882
|
+
}
|
|
1883
|
+
const analyzer = createAnalyzer(config);
|
|
1884
|
+
const proxy = createProxyServer(proxyConfig, analyzer, originalUpstreamUrl);
|
|
1573
1885
|
await proxy.listen();
|
|
1574
1886
|
const dashboard = createDashboardServer({
|
|
1575
1887
|
store: proxy.store,
|
|
@@ -1653,7 +1965,7 @@ Patching ${config.agent_type} config...`);
|
|
|
1653
1965
|
console.log(` baseUrl: ${config.llm_base_url} \u2192 localhost:${config.proxy_port}`);
|
|
1654
1966
|
switch (config.agent_type) {
|
|
1655
1967
|
case "openclaw":
|
|
1656
|
-
patchOpenClaw(config
|
|
1968
|
+
patchOpenClaw(config);
|
|
1657
1969
|
break;
|
|
1658
1970
|
case "ironclaw":
|
|
1659
1971
|
patchIronClaw(config);
|
|
@@ -1722,21 +2034,21 @@ Skills: ${approved} approved, ${pending} pending, ${rejected} rejected`);
|
|
|
1722
2034
|
}
|
|
1723
2035
|
|
|
1724
2036
|
// src/cli/init.ts
|
|
1725
|
-
var
|
|
1726
|
-
var
|
|
2037
|
+
var import_node_fs8 = require("fs");
|
|
2038
|
+
var import_node_path8 = require("path");
|
|
1727
2039
|
var import_node_url = require("url");
|
|
1728
2040
|
var import_meta = {};
|
|
1729
2041
|
var command = process.argv[2];
|
|
1730
2042
|
var VERSION = "unknown";
|
|
1731
2043
|
try {
|
|
1732
|
-
const dir = (0,
|
|
1733
|
-
const pkgPath = (0,
|
|
1734
|
-
VERSION = JSON.parse((0,
|
|
2044
|
+
const dir = (0, import_node_path8.dirname)((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
2045
|
+
const pkgPath = (0, import_node_path8.join)(dir, "..", "package.json");
|
|
2046
|
+
VERSION = JSON.parse((0, import_node_fs8.readFileSync)(pkgPath, "utf-8")).version;
|
|
1735
2047
|
} catch {
|
|
1736
2048
|
try {
|
|
1737
|
-
const dir = (0,
|
|
1738
|
-
const pkgPath = (0,
|
|
1739
|
-
VERSION = JSON.parse((0,
|
|
2049
|
+
const dir = (0, import_node_path8.dirname)((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
2050
|
+
const pkgPath = (0, import_node_path8.join)(dir, "..", "..", "package.json");
|
|
2051
|
+
VERSION = JSON.parse((0, import_node_fs8.readFileSync)(pkgPath, "utf-8")).version;
|
|
1740
2052
|
} catch {
|
|
1741
2053
|
}
|
|
1742
2054
|
}
|