@massa-ai/opencode-plugin 1.2.1
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/config-cli.js +1353 -0
- package/dist/index.js +14244 -0
- package/package.json +48 -0
|
@@ -0,0 +1,1353 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
// @bun
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
function __accessProp(key) {
|
|
10
|
+
return this[key];
|
|
11
|
+
}
|
|
12
|
+
var __toESMCache_node;
|
|
13
|
+
var __toESMCache_esm;
|
|
14
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
15
|
+
var canCache = mod != null && typeof mod === "object";
|
|
16
|
+
if (canCache) {
|
|
17
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
18
|
+
var cached = cache.get(mod);
|
|
19
|
+
if (cached)
|
|
20
|
+
return cached;
|
|
21
|
+
}
|
|
22
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
23
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
24
|
+
for (let key of __getOwnPropNames(mod))
|
|
25
|
+
if (!__hasOwnProp.call(to, key))
|
|
26
|
+
__defProp(to, key, {
|
|
27
|
+
get: __accessProp.bind(mod, key),
|
|
28
|
+
enumerable: true
|
|
29
|
+
});
|
|
30
|
+
if (canCache)
|
|
31
|
+
cache.set(mod, to);
|
|
32
|
+
return to;
|
|
33
|
+
};
|
|
34
|
+
var __toCommonJS = (from) => {
|
|
35
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
36
|
+
if (entry)
|
|
37
|
+
return entry;
|
|
38
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
39
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
40
|
+
for (var key of __getOwnPropNames(from))
|
|
41
|
+
if (!__hasOwnProp.call(entry, key))
|
|
42
|
+
__defProp(entry, key, {
|
|
43
|
+
get: __accessProp.bind(from, key),
|
|
44
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
__moduleCache.set(from, entry);
|
|
48
|
+
return entry;
|
|
49
|
+
};
|
|
50
|
+
var __moduleCache;
|
|
51
|
+
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
52
|
+
var __returnValue = (v) => v;
|
|
53
|
+
function __exportSetter(name, newValue) {
|
|
54
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
55
|
+
}
|
|
56
|
+
var __export = (target, all) => {
|
|
57
|
+
for (var name in all)
|
|
58
|
+
__defProp(target, name, {
|
|
59
|
+
get: all[name],
|
|
60
|
+
enumerable: true,
|
|
61
|
+
configurable: true,
|
|
62
|
+
set: __exportSetter.bind(all, name)
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
66
|
+
var __require = import.meta.require;
|
|
67
|
+
|
|
68
|
+
// ../../node_modules/dotenv/lib/main.js
|
|
69
|
+
var require_main = __commonJS((exports, module) => {
|
|
70
|
+
var fs = __require("fs");
|
|
71
|
+
var path = __require("path");
|
|
72
|
+
var os = __require("os");
|
|
73
|
+
var crypto = __require("crypto");
|
|
74
|
+
var TIPS = [
|
|
75
|
+
"\u25C8 encrypted .env [www.dotenvx.com]",
|
|
76
|
+
"\u25C8 secrets for agents [www.dotenvx.com]",
|
|
77
|
+
"\u2301 auth for agents [www.vestauth.com]",
|
|
78
|
+
"\u2318 custom filepath { path: '/custom/path/.env' }",
|
|
79
|
+
"\u2318 enable debugging { debug: true }",
|
|
80
|
+
"\u2318 override existing { override: true }",
|
|
81
|
+
"\u2318 suppress logs { quiet: true }",
|
|
82
|
+
"\u2318 multiple files { path: ['.env.local', '.env'] }"
|
|
83
|
+
];
|
|
84
|
+
function _getRandomTip() {
|
|
85
|
+
return TIPS[Math.floor(Math.random() * TIPS.length)];
|
|
86
|
+
}
|
|
87
|
+
function parseBoolean(value) {
|
|
88
|
+
if (typeof value === "string") {
|
|
89
|
+
return !["false", "0", "no", "off", ""].includes(value.toLowerCase());
|
|
90
|
+
}
|
|
91
|
+
return Boolean(value);
|
|
92
|
+
}
|
|
93
|
+
function supportsAnsi() {
|
|
94
|
+
return process.stdout.isTTY;
|
|
95
|
+
}
|
|
96
|
+
function dim(text) {
|
|
97
|
+
return supportsAnsi() ? `\x1B[2m${text}\x1B[0m` : text;
|
|
98
|
+
}
|
|
99
|
+
var LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg;
|
|
100
|
+
function parse(src) {
|
|
101
|
+
const obj = {};
|
|
102
|
+
let lines = src.toString();
|
|
103
|
+
lines = lines.replace(/\r\n?/mg, `
|
|
104
|
+
`);
|
|
105
|
+
let match;
|
|
106
|
+
while ((match = LINE.exec(lines)) != null) {
|
|
107
|
+
const key = match[1];
|
|
108
|
+
let value = match[2] || "";
|
|
109
|
+
value = value.trim();
|
|
110
|
+
const maybeQuote = value[0];
|
|
111
|
+
value = value.replace(/^(['"`])([\s\S]*)\1$/mg, "$2");
|
|
112
|
+
if (maybeQuote === '"') {
|
|
113
|
+
value = value.replace(/\\n/g, `
|
|
114
|
+
`);
|
|
115
|
+
value = value.replace(/\\r/g, "\r");
|
|
116
|
+
}
|
|
117
|
+
obj[key] = value;
|
|
118
|
+
}
|
|
119
|
+
return obj;
|
|
120
|
+
}
|
|
121
|
+
function _parseVault(options) {
|
|
122
|
+
options = options || {};
|
|
123
|
+
const vaultPath = _vaultPath(options);
|
|
124
|
+
options.path = vaultPath;
|
|
125
|
+
const result = DotenvModule.configDotenv(options);
|
|
126
|
+
if (!result.parsed) {
|
|
127
|
+
const err = new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`);
|
|
128
|
+
err.code = "MISSING_DATA";
|
|
129
|
+
throw err;
|
|
130
|
+
}
|
|
131
|
+
const keys = _dotenvKey(options).split(",");
|
|
132
|
+
const length = keys.length;
|
|
133
|
+
let decrypted;
|
|
134
|
+
for (let i = 0;i < length; i++) {
|
|
135
|
+
try {
|
|
136
|
+
const key = keys[i].trim();
|
|
137
|
+
const attrs = _instructions(result, key);
|
|
138
|
+
decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key);
|
|
139
|
+
break;
|
|
140
|
+
} catch (error) {
|
|
141
|
+
if (i + 1 >= length) {
|
|
142
|
+
throw error;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return DotenvModule.parse(decrypted);
|
|
147
|
+
}
|
|
148
|
+
function _warn(message) {
|
|
149
|
+
console.error(`\u26A0 ${message}`);
|
|
150
|
+
}
|
|
151
|
+
function _debug(message) {
|
|
152
|
+
console.log(`\u2506 ${message}`);
|
|
153
|
+
}
|
|
154
|
+
function _log(message) {
|
|
155
|
+
console.log(`\u25C7 ${message}`);
|
|
156
|
+
}
|
|
157
|
+
function _dotenvKey(options) {
|
|
158
|
+
if (options && options.DOTENV_KEY && options.DOTENV_KEY.length > 0) {
|
|
159
|
+
return options.DOTENV_KEY;
|
|
160
|
+
}
|
|
161
|
+
if (process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0) {
|
|
162
|
+
return process.env.DOTENV_KEY;
|
|
163
|
+
}
|
|
164
|
+
return "";
|
|
165
|
+
}
|
|
166
|
+
function _instructions(result, dotenvKey) {
|
|
167
|
+
let uri;
|
|
168
|
+
try {
|
|
169
|
+
uri = new URL(dotenvKey);
|
|
170
|
+
} catch (error) {
|
|
171
|
+
if (error.code === "ERR_INVALID_URL") {
|
|
172
|
+
const err = new Error("INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenvx.com/vault/.env.vault?environment=development");
|
|
173
|
+
err.code = "INVALID_DOTENV_KEY";
|
|
174
|
+
throw err;
|
|
175
|
+
}
|
|
176
|
+
throw error;
|
|
177
|
+
}
|
|
178
|
+
const key = uri.password;
|
|
179
|
+
if (!key) {
|
|
180
|
+
const err = new Error("INVALID_DOTENV_KEY: Missing key part");
|
|
181
|
+
err.code = "INVALID_DOTENV_KEY";
|
|
182
|
+
throw err;
|
|
183
|
+
}
|
|
184
|
+
const environment = uri.searchParams.get("environment");
|
|
185
|
+
if (!environment) {
|
|
186
|
+
const err = new Error("INVALID_DOTENV_KEY: Missing environment part");
|
|
187
|
+
err.code = "INVALID_DOTENV_KEY";
|
|
188
|
+
throw err;
|
|
189
|
+
}
|
|
190
|
+
const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`;
|
|
191
|
+
const ciphertext = result.parsed[environmentKey];
|
|
192
|
+
if (!ciphertext) {
|
|
193
|
+
const err = new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`);
|
|
194
|
+
err.code = "NOT_FOUND_DOTENV_ENVIRONMENT";
|
|
195
|
+
throw err;
|
|
196
|
+
}
|
|
197
|
+
return { ciphertext, key };
|
|
198
|
+
}
|
|
199
|
+
function _vaultPath(options) {
|
|
200
|
+
let possibleVaultPath = null;
|
|
201
|
+
if (options && options.path && options.path.length > 0) {
|
|
202
|
+
if (Array.isArray(options.path)) {
|
|
203
|
+
for (const filepath of options.path) {
|
|
204
|
+
if (fs.existsSync(filepath)) {
|
|
205
|
+
possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
} else {
|
|
209
|
+
possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
possibleVaultPath = path.resolve(process.cwd(), ".env.vault");
|
|
213
|
+
}
|
|
214
|
+
if (fs.existsSync(possibleVaultPath)) {
|
|
215
|
+
return possibleVaultPath;
|
|
216
|
+
}
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
function _resolveHome(envPath) {
|
|
220
|
+
return envPath[0] === "~" ? path.join(os.homedir(), envPath.slice(1)) : envPath;
|
|
221
|
+
}
|
|
222
|
+
function _configVault(options) {
|
|
223
|
+
const debug = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || options && options.debug);
|
|
224
|
+
const quiet = parseBoolean(process.env.DOTENV_CONFIG_QUIET || options && options.quiet);
|
|
225
|
+
if (debug || !quiet) {
|
|
226
|
+
_log("loading env from encrypted .env.vault");
|
|
227
|
+
}
|
|
228
|
+
const parsed = DotenvModule._parseVault(options);
|
|
229
|
+
let processEnv = process.env;
|
|
230
|
+
if (options && options.processEnv != null) {
|
|
231
|
+
processEnv = options.processEnv;
|
|
232
|
+
}
|
|
233
|
+
DotenvModule.populate(processEnv, parsed, options);
|
|
234
|
+
return { parsed };
|
|
235
|
+
}
|
|
236
|
+
function configDotenv(options) {
|
|
237
|
+
const dotenvPath = path.resolve(process.cwd(), ".env");
|
|
238
|
+
let encoding = "utf8";
|
|
239
|
+
let processEnv = process.env;
|
|
240
|
+
if (options && options.processEnv != null) {
|
|
241
|
+
processEnv = options.processEnv;
|
|
242
|
+
}
|
|
243
|
+
let debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || options && options.debug);
|
|
244
|
+
let quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || options && options.quiet);
|
|
245
|
+
if (options && options.encoding) {
|
|
246
|
+
encoding = options.encoding;
|
|
247
|
+
} else {
|
|
248
|
+
if (debug) {
|
|
249
|
+
_debug("no encoding is specified (UTF-8 is used by default)");
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
let optionPaths = [dotenvPath];
|
|
253
|
+
if (options && options.path) {
|
|
254
|
+
if (!Array.isArray(options.path)) {
|
|
255
|
+
optionPaths = [_resolveHome(options.path)];
|
|
256
|
+
} else {
|
|
257
|
+
optionPaths = [];
|
|
258
|
+
for (const filepath of options.path) {
|
|
259
|
+
optionPaths.push(_resolveHome(filepath));
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
let lastError;
|
|
264
|
+
const parsedAll = {};
|
|
265
|
+
for (const path2 of optionPaths) {
|
|
266
|
+
try {
|
|
267
|
+
const parsed = DotenvModule.parse(fs.readFileSync(path2, { encoding }));
|
|
268
|
+
DotenvModule.populate(parsedAll, parsed, options);
|
|
269
|
+
} catch (e) {
|
|
270
|
+
if (debug) {
|
|
271
|
+
_debug(`failed to load ${path2} ${e.message}`);
|
|
272
|
+
}
|
|
273
|
+
lastError = e;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
const populated = DotenvModule.populate(processEnv, parsedAll, options);
|
|
277
|
+
debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || debug);
|
|
278
|
+
quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || quiet);
|
|
279
|
+
if (debug || !quiet) {
|
|
280
|
+
const keysCount = Object.keys(populated).length;
|
|
281
|
+
const shortPaths = [];
|
|
282
|
+
for (const filePath of optionPaths) {
|
|
283
|
+
try {
|
|
284
|
+
const relative = path.relative(process.cwd(), filePath);
|
|
285
|
+
shortPaths.push(relative);
|
|
286
|
+
} catch (e) {
|
|
287
|
+
if (debug) {
|
|
288
|
+
_debug(`failed to load ${filePath} ${e.message}`);
|
|
289
|
+
}
|
|
290
|
+
lastError = e;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
_log(`injected env (${keysCount}) from ${shortPaths.join(",")} ${dim(`// tip: ${_getRandomTip()}`)}`);
|
|
294
|
+
}
|
|
295
|
+
if (lastError) {
|
|
296
|
+
return { parsed: parsedAll, error: lastError };
|
|
297
|
+
} else {
|
|
298
|
+
return { parsed: parsedAll };
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
function config(options) {
|
|
302
|
+
if (_dotenvKey(options).length === 0) {
|
|
303
|
+
return DotenvModule.configDotenv(options);
|
|
304
|
+
}
|
|
305
|
+
const vaultPath = _vaultPath(options);
|
|
306
|
+
if (!vaultPath) {
|
|
307
|
+
_warn(`you set DOTENV_KEY but you are missing a .env.vault file at ${vaultPath}`);
|
|
308
|
+
return DotenvModule.configDotenv(options);
|
|
309
|
+
}
|
|
310
|
+
return DotenvModule._configVault(options);
|
|
311
|
+
}
|
|
312
|
+
function decrypt(encrypted, keyStr) {
|
|
313
|
+
const key = Buffer.from(keyStr.slice(-64), "hex");
|
|
314
|
+
let ciphertext = Buffer.from(encrypted, "base64");
|
|
315
|
+
const nonce = ciphertext.subarray(0, 12);
|
|
316
|
+
const authTag = ciphertext.subarray(-16);
|
|
317
|
+
ciphertext = ciphertext.subarray(12, -16);
|
|
318
|
+
try {
|
|
319
|
+
const aesgcm = crypto.createDecipheriv("aes-256-gcm", key, nonce);
|
|
320
|
+
aesgcm.setAuthTag(authTag);
|
|
321
|
+
return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
|
|
322
|
+
} catch (error) {
|
|
323
|
+
const isRange = error instanceof RangeError;
|
|
324
|
+
const invalidKeyLength = error.message === "Invalid key length";
|
|
325
|
+
const decryptionFailed = error.message === "Unsupported state or unable to authenticate data";
|
|
326
|
+
if (isRange || invalidKeyLength) {
|
|
327
|
+
const err = new Error("INVALID_DOTENV_KEY: It must be 64 characters long (or more)");
|
|
328
|
+
err.code = "INVALID_DOTENV_KEY";
|
|
329
|
+
throw err;
|
|
330
|
+
} else if (decryptionFailed) {
|
|
331
|
+
const err = new Error("DECRYPTION_FAILED: Please check your DOTENV_KEY");
|
|
332
|
+
err.code = "DECRYPTION_FAILED";
|
|
333
|
+
throw err;
|
|
334
|
+
} else {
|
|
335
|
+
throw error;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
function populate(processEnv, parsed, options = {}) {
|
|
340
|
+
const debug = Boolean(options && options.debug);
|
|
341
|
+
const override = Boolean(options && options.override);
|
|
342
|
+
const populated = {};
|
|
343
|
+
if (typeof parsed !== "object") {
|
|
344
|
+
const err = new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");
|
|
345
|
+
err.code = "OBJECT_REQUIRED";
|
|
346
|
+
throw err;
|
|
347
|
+
}
|
|
348
|
+
for (const key of Object.keys(parsed)) {
|
|
349
|
+
if (Object.prototype.hasOwnProperty.call(processEnv, key)) {
|
|
350
|
+
if (override === true) {
|
|
351
|
+
processEnv[key] = parsed[key];
|
|
352
|
+
populated[key] = parsed[key];
|
|
353
|
+
}
|
|
354
|
+
if (debug) {
|
|
355
|
+
if (override === true) {
|
|
356
|
+
_debug(`"${key}" is already defined and WAS overwritten`);
|
|
357
|
+
} else {
|
|
358
|
+
_debug(`"${key}" is already defined and was NOT overwritten`);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
} else {
|
|
362
|
+
processEnv[key] = parsed[key];
|
|
363
|
+
populated[key] = parsed[key];
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return populated;
|
|
367
|
+
}
|
|
368
|
+
var DotenvModule = {
|
|
369
|
+
configDotenv,
|
|
370
|
+
_configVault,
|
|
371
|
+
_parseVault,
|
|
372
|
+
config,
|
|
373
|
+
decrypt,
|
|
374
|
+
parse,
|
|
375
|
+
populate
|
|
376
|
+
};
|
|
377
|
+
exports.configDotenv = DotenvModule.configDotenv;
|
|
378
|
+
exports._configVault = DotenvModule._configVault;
|
|
379
|
+
exports._parseVault = DotenvModule._parseVault;
|
|
380
|
+
exports.config = DotenvModule.config;
|
|
381
|
+
exports.decrypt = DotenvModule.decrypt;
|
|
382
|
+
exports.parse = DotenvModule.parse;
|
|
383
|
+
exports.populate = DotenvModule.populate;
|
|
384
|
+
module.exports = DotenvModule;
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
// ../../packages/shared/dist/config/xdg.js
|
|
388
|
+
import path from "path";
|
|
389
|
+
import os from "os";
|
|
390
|
+
function xdgEnv(name, fallback) {
|
|
391
|
+
const v = process.env[name];
|
|
392
|
+
return v && v.trim() ? v : fallback;
|
|
393
|
+
}
|
|
394
|
+
function xdgConfigHome() {
|
|
395
|
+
return xdgEnv("XDG_CONFIG_HOME", path.join(os.homedir(), ".config"));
|
|
396
|
+
}
|
|
397
|
+
function configDir(app) {
|
|
398
|
+
return path.join(xdgConfigHome(), app);
|
|
399
|
+
}
|
|
400
|
+
var init_xdg = () => {};
|
|
401
|
+
|
|
402
|
+
// ../../packages/shared/dist/config/massa-ai-config.js
|
|
403
|
+
import path2 from "path";
|
|
404
|
+
var defaultMassaAiConfig;
|
|
405
|
+
var init_massa_ai_config = __esm(() => {
|
|
406
|
+
init_xdg();
|
|
407
|
+
defaultMassaAiConfig = {
|
|
408
|
+
database: {
|
|
409
|
+
url: ""
|
|
410
|
+
},
|
|
411
|
+
embedding: {
|
|
412
|
+
provider: "ollama",
|
|
413
|
+
model: "nomic-embed-text:latest",
|
|
414
|
+
baseURL: "http://localhost:11434",
|
|
415
|
+
dimensions: 768
|
|
416
|
+
},
|
|
417
|
+
compression: {
|
|
418
|
+
defaultStrategy: "code_structure",
|
|
419
|
+
minTokensForCompression: 100,
|
|
420
|
+
targetCompressionRatio: 0.7
|
|
421
|
+
},
|
|
422
|
+
impact: {
|
|
423
|
+
bfsCteEnabled: false
|
|
424
|
+
},
|
|
425
|
+
capturePolicy: undefined,
|
|
426
|
+
cache: {
|
|
427
|
+
enabled: true,
|
|
428
|
+
l1MaxSizeMB: 100,
|
|
429
|
+
l2MaxSizeMB: 500,
|
|
430
|
+
defaultTTLSeconds: 3600
|
|
431
|
+
},
|
|
432
|
+
dataDir: path2.join(configDir("massa-ai"), "data"),
|
|
433
|
+
logging: {
|
|
434
|
+
level: "info",
|
|
435
|
+
enableMetrics: false
|
|
436
|
+
},
|
|
437
|
+
search: {
|
|
438
|
+
autoReindexMaxFiles: 200,
|
|
439
|
+
queryUnderstanding: {
|
|
440
|
+
enabled: false,
|
|
441
|
+
hydeEnabled: true,
|
|
442
|
+
cacheTtlMs: 300000,
|
|
443
|
+
cacheMaxSize: 256
|
|
444
|
+
},
|
|
445
|
+
rerank: {
|
|
446
|
+
enabled: false,
|
|
447
|
+
rerankWindow: 50
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
llm: {
|
|
451
|
+
enabled: false,
|
|
452
|
+
baseUrl: "http://localhost:11434/v1",
|
|
453
|
+
apiKey: "ollama",
|
|
454
|
+
model: "qwen2.5:7b-instruct",
|
|
455
|
+
codeModel: "qwen2.5-coder:7b",
|
|
456
|
+
temperature: 0.2,
|
|
457
|
+
maxOutputTokens: 8000,
|
|
458
|
+
timeoutMs: 90000,
|
|
459
|
+
disableThink: true
|
|
460
|
+
},
|
|
461
|
+
memory: {
|
|
462
|
+
decay: {
|
|
463
|
+
lambda: 0.02,
|
|
464
|
+
sigma: 0.6,
|
|
465
|
+
mu: 0.04,
|
|
466
|
+
coldThreshold: 0.2
|
|
467
|
+
},
|
|
468
|
+
bootstrap: {
|
|
469
|
+
enabled: true,
|
|
470
|
+
maxSeedMemories: 8,
|
|
471
|
+
centralityLimit: 10,
|
|
472
|
+
gitLogLimit: 20,
|
|
473
|
+
refreshEnabled: true
|
|
474
|
+
},
|
|
475
|
+
autoImprove: {
|
|
476
|
+
enabled: true,
|
|
477
|
+
reviewGate: false,
|
|
478
|
+
minObservations: 8,
|
|
479
|
+
minIntervalMs: 300000,
|
|
480
|
+
maxWindow: 16,
|
|
481
|
+
minQueryHits: 3,
|
|
482
|
+
minFileHits: 3,
|
|
483
|
+
minFixHits: 2
|
|
484
|
+
},
|
|
485
|
+
autoImportance: {
|
|
486
|
+
enabled: false
|
|
487
|
+
}
|
|
488
|
+
},
|
|
489
|
+
hooks: {
|
|
490
|
+
enabled: true,
|
|
491
|
+
maxPayloadBytes: 65536,
|
|
492
|
+
queue: {
|
|
493
|
+
maxPending: 256
|
|
494
|
+
},
|
|
495
|
+
bridge: {
|
|
496
|
+
enabled: true,
|
|
497
|
+
minObservations: 8,
|
|
498
|
+
minIntervalMs: 300000,
|
|
499
|
+
maxWindow: 8
|
|
500
|
+
}
|
|
501
|
+
},
|
|
502
|
+
synapse: {
|
|
503
|
+
enabled: true,
|
|
504
|
+
inhibition: {
|
|
505
|
+
diversityPenalty: { enabled: true, threshold: 0.85, lambda: 0.4, samePathPenalty: 0.15 },
|
|
506
|
+
temporalInhibition: { enabled: true, penaltyAgeMs: 3600000, penalty: 0.15 },
|
|
507
|
+
confidenceGate: {
|
|
508
|
+
enabled: true,
|
|
509
|
+
thresholds: { specific: 0.55, focused: 0.4, broad: 0.25 }
|
|
510
|
+
},
|
|
511
|
+
chainInhibition: { enabled: true }
|
|
512
|
+
},
|
|
513
|
+
scoring: {
|
|
514
|
+
attention: {
|
|
515
|
+
enabled: false,
|
|
516
|
+
rerankWindow: 50,
|
|
517
|
+
recencyHalfLifeMs: 7 * 24 * 60 * 60 * 1000,
|
|
518
|
+
semanticScale: 1,
|
|
519
|
+
weights: {
|
|
520
|
+
semantic: 0.25,
|
|
521
|
+
recency: 0.15,
|
|
522
|
+
accessHeat: 0.15,
|
|
523
|
+
taskAlign: 0.2,
|
|
524
|
+
agentAffinity: 0.1,
|
|
525
|
+
confidence: 0.15
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
},
|
|
529
|
+
metacognition: {
|
|
530
|
+
enabled: true,
|
|
531
|
+
lowConfidenceThreshold: 0.15,
|
|
532
|
+
definitiveTopScore: 0.8,
|
|
533
|
+
definitiveGap: 0.2
|
|
534
|
+
},
|
|
535
|
+
buffer: {
|
|
536
|
+
enabled: true,
|
|
537
|
+
maxSize: 20,
|
|
538
|
+
ttlMs: 900000,
|
|
539
|
+
hitBoost: 1.3,
|
|
540
|
+
matchThreshold: 0.4
|
|
541
|
+
}
|
|
542
|
+
},
|
|
543
|
+
handoffs: {
|
|
544
|
+
enabled: true
|
|
545
|
+
}
|
|
546
|
+
};
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
// ../../packages/shared/dist/config/config-loader.js
|
|
550
|
+
var exports_config_loader = {};
|
|
551
|
+
__export(exports_config_loader, {
|
|
552
|
+
saveConfig: () => saveConfig,
|
|
553
|
+
migrateDataDirOnce: () => migrateDataDirOnce,
|
|
554
|
+
loadConfigSafe: () => loadConfigSafe,
|
|
555
|
+
loadConfig: () => loadConfig,
|
|
556
|
+
initConfig: () => initConfig,
|
|
557
|
+
getConfigPath: () => getConfigPath,
|
|
558
|
+
getConfigForEnv: () => getConfigForEnv,
|
|
559
|
+
getConfigDir: () => getConfigDir,
|
|
560
|
+
configExists: () => configExists
|
|
561
|
+
});
|
|
562
|
+
import fs from "fs";
|
|
563
|
+
import path3 from "path";
|
|
564
|
+
import os2 from "os";
|
|
565
|
+
function getConfigDir() {
|
|
566
|
+
return CONFIG_DIR;
|
|
567
|
+
}
|
|
568
|
+
function getConfigPath() {
|
|
569
|
+
return CONFIG_FILE;
|
|
570
|
+
}
|
|
571
|
+
function configExists() {
|
|
572
|
+
return fs.existsSync(CONFIG_FILE);
|
|
573
|
+
}
|
|
574
|
+
function loadConfig() {
|
|
575
|
+
if (!fs.existsSync(CONFIG_FILE)) {
|
|
576
|
+
return defaultMassaAiConfig;
|
|
577
|
+
}
|
|
578
|
+
try {
|
|
579
|
+
const content = fs.readFileSync(CONFIG_FILE, "utf-8");
|
|
580
|
+
const userConfig = JSON.parse(content);
|
|
581
|
+
return {
|
|
582
|
+
...defaultMassaAiConfig,
|
|
583
|
+
...userConfig,
|
|
584
|
+
database: { ...defaultMassaAiConfig.database, ...userConfig.database },
|
|
585
|
+
embedding: { ...defaultMassaAiConfig.embedding, ...userConfig.embedding },
|
|
586
|
+
compression: { ...defaultMassaAiConfig.compression, ...userConfig.compression },
|
|
587
|
+
cache: { ...defaultMassaAiConfig.cache, ...userConfig.cache },
|
|
588
|
+
logging: { ...defaultMassaAiConfig.logging, ...userConfig.logging },
|
|
589
|
+
search: { ...defaultMassaAiConfig.search, ...userConfig.search },
|
|
590
|
+
llm: { ...defaultMassaAiConfig.llm, ...userConfig.llm },
|
|
591
|
+
memory: { ...defaultMassaAiConfig.memory, ...userConfig.memory },
|
|
592
|
+
hooks: { ...defaultMassaAiConfig.hooks, ...userConfig.hooks },
|
|
593
|
+
handoffs: { ...defaultMassaAiConfig.handoffs, ...userConfig.handoffs }
|
|
594
|
+
};
|
|
595
|
+
} catch (error) {
|
|
596
|
+
console.error(`Error loading config from ${CONFIG_FILE}:`, error);
|
|
597
|
+
return defaultMassaAiConfig;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
function loadConfigSafe() {
|
|
601
|
+
try {
|
|
602
|
+
return loadConfig();
|
|
603
|
+
} catch {
|
|
604
|
+
return defaultMassaAiConfig;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
function migrateDataDirOnce() {
|
|
608
|
+
if (migrationAttempted)
|
|
609
|
+
return;
|
|
610
|
+
migrationAttempted = true;
|
|
611
|
+
try {
|
|
612
|
+
const oldDir = path3.join(os2.homedir(), ".massa-ai-data");
|
|
613
|
+
const newDir = path3.join(getConfigDir(), "data");
|
|
614
|
+
if (fs.existsSync(newDir))
|
|
615
|
+
return;
|
|
616
|
+
if (!fs.existsSync(oldDir))
|
|
617
|
+
return;
|
|
618
|
+
fs.mkdirSync(path3.dirname(newDir), { recursive: true });
|
|
619
|
+
try {
|
|
620
|
+
fs.renameSync(oldDir, newDir);
|
|
621
|
+
console.warn(`[massa-ai] Migrated data directory: ${oldDir} -> ${newDir}`);
|
|
622
|
+
} catch (renameErr) {
|
|
623
|
+
console.error(`[massa-ai] Could not move data directory ${oldDir} -> ${newDir} ` + `(rename failed: ${renameErr?.code || renameErr?.message}). ` + `Move it manually, e.g.:
|
|
624
|
+
` + ` mv "${oldDir}" "${newDir}"`);
|
|
625
|
+
}
|
|
626
|
+
} catch (err) {
|
|
627
|
+
console.error(`[massa-ai] Data directory migration skipped:`, err);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
function saveConfig(config) {
|
|
631
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
632
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
633
|
+
}
|
|
634
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
635
|
+
}
|
|
636
|
+
function initConfig() {
|
|
637
|
+
if (!fs.existsSync(CONFIG_FILE)) {
|
|
638
|
+
saveConfig(defaultMassaAiConfig);
|
|
639
|
+
console.log(`Created default config at ${CONFIG_FILE}`);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
function getConfigForEnv() {
|
|
643
|
+
const config = loadConfig();
|
|
644
|
+
const env = {};
|
|
645
|
+
if (config.embedding.provider === "ollama") {
|
|
646
|
+
env.OLLAMA_EMBEDDING_MODEL = config.embedding.model;
|
|
647
|
+
env.OLLAMA_BASE_URL = config.embedding.baseURL || "http://localhost:11434";
|
|
648
|
+
if (config.embedding.dimensions) {
|
|
649
|
+
env.OLLAMA_EMBEDDING_DIMENSIONS = String(config.embedding.dimensions);
|
|
650
|
+
}
|
|
651
|
+
} else if (config.embedding.provider === "mistral") {
|
|
652
|
+
env.MISTRAL_API_KEY = config.embedding.apiKey || "";
|
|
653
|
+
env.MISTRAL_TEXT_EMBEDDING_MODEL = config.embedding.model;
|
|
654
|
+
} else if (config.embedding.provider === "openai") {
|
|
655
|
+
env.OPENAI_API_KEY = config.embedding.apiKey || "";
|
|
656
|
+
env.OPENAI_EMBEDDING_MODEL = config.embedding.model;
|
|
657
|
+
}
|
|
658
|
+
env.LOG_LEVEL = config.logging.level;
|
|
659
|
+
env.ENABLE_METRICS = String(config.logging.enableMetrics);
|
|
660
|
+
return env;
|
|
661
|
+
}
|
|
662
|
+
var CONFIG_DIR, CONFIG_FILE, migrationAttempted = false;
|
|
663
|
+
var init_config_loader = __esm(() => {
|
|
664
|
+
init_massa_ai_config();
|
|
665
|
+
init_xdg();
|
|
666
|
+
CONFIG_DIR = configDir("massa-ai");
|
|
667
|
+
CONFIG_FILE = path3.join(CONFIG_DIR, "config.json");
|
|
668
|
+
});
|
|
669
|
+
|
|
670
|
+
// ../../packages/shared/dist/env.js
|
|
671
|
+
var import_dotenv = __toESM(require_main(), 1);
|
|
672
|
+
import { existsSync } from "fs";
|
|
673
|
+
import { resolve, dirname } from "path";
|
|
674
|
+
function findEnvFile() {
|
|
675
|
+
let dir = process.cwd();
|
|
676
|
+
while (true) {
|
|
677
|
+
const envPath = resolve(dir, ".env");
|
|
678
|
+
if (existsSync(envPath)) {
|
|
679
|
+
return envPath;
|
|
680
|
+
}
|
|
681
|
+
const parent = dirname(dir);
|
|
682
|
+
if (parent === dir)
|
|
683
|
+
break;
|
|
684
|
+
dir = parent;
|
|
685
|
+
}
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
var envPath = findEnvFile();
|
|
689
|
+
import_dotenv.config({ path: envPath });
|
|
690
|
+
try {
|
|
691
|
+
const { loadConfigSafe: loadConfigSafe2, migrateDataDirOnce: migrateDataDirOnce2 } = (init_config_loader(), __toCommonJS(exports_config_loader));
|
|
692
|
+
migrateDataDirOnce2();
|
|
693
|
+
const cfg = loadConfigSafe2();
|
|
694
|
+
if (cfg.database?.url && !process.env.DATABASE_URL) {
|
|
695
|
+
process.env.DATABASE_URL = cfg.database.url;
|
|
696
|
+
}
|
|
697
|
+
if (cfg.llm?.apiKey && !process.env.RLM_LLM_API_KEY) {
|
|
698
|
+
process.env.RLM_LLM_API_KEY = cfg.llm.apiKey;
|
|
699
|
+
}
|
|
700
|
+
if (cfg.embedding?.apiKey && !process.env.OLLAMA_API_KEY) {
|
|
701
|
+
process.env.OLLAMA_API_KEY = cfg.embedding.apiKey;
|
|
702
|
+
}
|
|
703
|
+
} catch {}
|
|
704
|
+
|
|
705
|
+
// ../../packages/shared/dist/config/index.js
|
|
706
|
+
init_config_loader();
|
|
707
|
+
init_massa_ai_config();
|
|
708
|
+
init_config_loader();
|
|
709
|
+
import path4 from "path";
|
|
710
|
+
var DEFAULT_LLM_MODEL = "qwen2.5:7b-instruct";
|
|
711
|
+
var DEFAULT_LLM_CODE_MODEL = "qwen2.5-coder:7b";
|
|
712
|
+
function envNum(key, fallback) {
|
|
713
|
+
const s = process.env[key];
|
|
714
|
+
if (s === undefined || s === "")
|
|
715
|
+
return fallback;
|
|
716
|
+
const n = Number(s);
|
|
717
|
+
return Number.isFinite(n) ? n : fallback;
|
|
718
|
+
}
|
|
719
|
+
function envBool(key, fallback) {
|
|
720
|
+
const s = process.env[key];
|
|
721
|
+
if (s === undefined || s === "")
|
|
722
|
+
return fallback;
|
|
723
|
+
const lower = s.toLowerCase();
|
|
724
|
+
if (lower === "true" || lower === "1")
|
|
725
|
+
return true;
|
|
726
|
+
if (lower === "false" || lower === "0")
|
|
727
|
+
return false;
|
|
728
|
+
return fallback;
|
|
729
|
+
}
|
|
730
|
+
function envString(key, fallback) {
|
|
731
|
+
const s = process.env[key];
|
|
732
|
+
return s === undefined || s === "" ? fallback : s;
|
|
733
|
+
}
|
|
734
|
+
var MAX_IGNORE_PATTERNS = 1024;
|
|
735
|
+
function validateCapturePolicyConfig(raw) {
|
|
736
|
+
if (!raw || typeof raw !== "object")
|
|
737
|
+
throw new TypeError("capturePolicy must be an object");
|
|
738
|
+
const p = raw;
|
|
739
|
+
const allowedKeys = new Set(["rules", "maxMatchWork", "maxIgnorePatterns"]);
|
|
740
|
+
for (const key of Object.keys(p)) {
|
|
741
|
+
if (!allowedKeys.has(key)) {
|
|
742
|
+
throw new TypeError(`capturePolicy: unknown field "${key}" (denyUnknownFields=true)`);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
if (!Array.isArray(p.rules))
|
|
746
|
+
throw new TypeError("capturePolicy.rules must be an array");
|
|
747
|
+
const validDispositions = new Set(["Keep", "Drop", "MetadataOnly"]);
|
|
748
|
+
let dropCount = 0;
|
|
749
|
+
for (const rule of p.rules) {
|
|
750
|
+
if (!rule || typeof rule !== "object")
|
|
751
|
+
throw new TypeError("capturePolicy.rules[] must be objects");
|
|
752
|
+
if (typeof rule.pattern !== "string" || !rule.pattern) {
|
|
753
|
+
throw new TypeError("capturePolicy.rules[].pattern must be a non-empty string");
|
|
754
|
+
}
|
|
755
|
+
if (typeof rule.disposition !== "string" || !validDispositions.has(rule.disposition)) {
|
|
756
|
+
throw new TypeError(`capturePolicy.rules[].disposition must be Keep|Drop|MetadataOnly (got ${String(rule.disposition)})`);
|
|
757
|
+
}
|
|
758
|
+
if (rule.disposition === "Drop")
|
|
759
|
+
dropCount++;
|
|
760
|
+
}
|
|
761
|
+
const maxIgnore = typeof p.maxIgnorePatterns === "number" ? p.maxIgnorePatterns : MAX_IGNORE_PATTERNS;
|
|
762
|
+
if (dropCount > maxIgnore) {
|
|
763
|
+
throw new TypeError(`capturePolicy: ${dropCount} Drop rules exceed maxIgnorePatterns=${maxIgnore}`);
|
|
764
|
+
}
|
|
765
|
+
if (p.maxMatchWork !== undefined) {
|
|
766
|
+
if (typeof p.maxMatchWork !== "number" || p.maxMatchWork < 0) {
|
|
767
|
+
throw new TypeError("capturePolicy.maxMatchWork must be a non-negative number");
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
return {
|
|
771
|
+
rules: p.rules,
|
|
772
|
+
...p.maxMatchWork !== undefined && { maxMatchWork: p.maxMatchWork },
|
|
773
|
+
...p.maxIgnorePatterns !== undefined && { maxIgnorePatterns: p.maxIgnorePatterns }
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
function getGlobalDataDir() {
|
|
777
|
+
const envOverride = process.env.MASSA_AI_DATA_DIR;
|
|
778
|
+
if (envOverride && envOverride.trim())
|
|
779
|
+
return envOverride;
|
|
780
|
+
const fileConfig = loadConfigSafe();
|
|
781
|
+
if (fileConfig.dataDir)
|
|
782
|
+
return fileConfig.dataDir;
|
|
783
|
+
return path4.join(getConfigDir(), "data");
|
|
784
|
+
}
|
|
785
|
+
var DEFAULT_ALLOWED_EXTENSIONS = [
|
|
786
|
+
".ts",
|
|
787
|
+
".js",
|
|
788
|
+
".tsx",
|
|
789
|
+
".jsx",
|
|
790
|
+
".vue",
|
|
791
|
+
".dart",
|
|
792
|
+
".py",
|
|
793
|
+
".php",
|
|
794
|
+
".java",
|
|
795
|
+
".go",
|
|
796
|
+
".rs",
|
|
797
|
+
".cpp",
|
|
798
|
+
".c",
|
|
799
|
+
".h",
|
|
800
|
+
".md",
|
|
801
|
+
".json",
|
|
802
|
+
".yaml",
|
|
803
|
+
".yml",
|
|
804
|
+
".hpp",
|
|
805
|
+
".cs",
|
|
806
|
+
".rb",
|
|
807
|
+
".swift",
|
|
808
|
+
".kt",
|
|
809
|
+
".kts",
|
|
810
|
+
".scala",
|
|
811
|
+
".lua",
|
|
812
|
+
".zig",
|
|
813
|
+
".ex",
|
|
814
|
+
".exs",
|
|
815
|
+
".erl",
|
|
816
|
+
".clj",
|
|
817
|
+
".ml",
|
|
818
|
+
".hs"
|
|
819
|
+
];
|
|
820
|
+
var fileConfig = loadConfigSafe();
|
|
821
|
+
var fileCacheL1Bytes = fileConfig.cache?.l1MaxSizeMB ? fileConfig.cache.l1MaxSizeMB * 1024 * 1024 : undefined;
|
|
822
|
+
var fileCacheL2Bytes = fileConfig.cache?.l2MaxSizeMB ? fileConfig.cache.l2MaxSizeMB * 1024 * 1024 : undefined;
|
|
823
|
+
var defaultConfig = {
|
|
824
|
+
name: "massa-ai-server",
|
|
825
|
+
version: "1.0.0",
|
|
826
|
+
dataDir: getGlobalDataDir(),
|
|
827
|
+
cache: {
|
|
828
|
+
l1: {
|
|
829
|
+
maxSize: envNum("L1_CACHE_MAX_SIZE", fileCacheL1Bytes ?? 100 * 1024 * 1024),
|
|
830
|
+
defaultTTL: envNum("L1_CACHE_TTL", fileConfig.cache?.defaultTTLSeconds ?? 300)
|
|
831
|
+
},
|
|
832
|
+
l2: {
|
|
833
|
+
maxSize: envNum("L2_CACHE_MAX_SIZE", fileCacheL2Bytes ?? 500 * 1024 * 1024),
|
|
834
|
+
defaultTTL: envNum("L2_CACHE_TTL", fileConfig.cache?.defaultTTLSeconds ?? 3600)
|
|
835
|
+
},
|
|
836
|
+
embedding: {
|
|
837
|
+
maxAgeHours: 168
|
|
838
|
+
}
|
|
839
|
+
},
|
|
840
|
+
search: {
|
|
841
|
+
autoReindexMaxFiles: envNum("AUTOREINDEX_MAX_FILES", fileConfig.search?.autoReindexMaxFiles ?? 200),
|
|
842
|
+
queryUnderstanding: {
|
|
843
|
+
enabled: envBool("SEARCH_QUERY_UNDERSTANDING_ENABLED", fileConfig.search?.queryUnderstanding?.enabled ?? false),
|
|
844
|
+
hydeEnabled: envBool("SEARCH_QUERY_UNDERSTANDING_HYDE_ENABLED", fileConfig.search?.queryUnderstanding?.hydeEnabled ?? true),
|
|
845
|
+
cacheTtlMs: envNum("SEARCH_QUERY_UNDERSTANDING_CACHE_TTL_MS", fileConfig.search?.queryUnderstanding?.cacheTtlMs ?? 300000),
|
|
846
|
+
cacheMaxSize: envNum("SEARCH_QUERY_UNDERSTANDING_CACHE_MAX_SIZE", fileConfig.search?.queryUnderstanding?.cacheMaxSize ?? 256)
|
|
847
|
+
},
|
|
848
|
+
rerank: {
|
|
849
|
+
enabled: envBool("SEARCH_RERANK_ENABLED", fileConfig.search?.rerank?.enabled ?? false),
|
|
850
|
+
rerankWindow: envNum("SEARCH_RERANK_WINDOW", fileConfig.search?.rerank?.rerankWindow ?? 50)
|
|
851
|
+
}
|
|
852
|
+
},
|
|
853
|
+
llm: {
|
|
854
|
+
enabled: envBool("RLM_LLM_ENABLED", fileConfig.llm?.enabled ?? false),
|
|
855
|
+
baseUrl: envString("RLM_LLM_BASE_URL", fileConfig.llm?.baseUrl ?? "http://localhost:11434/v1"),
|
|
856
|
+
apiKey: envString("RLM_LLM_API_KEY", fileConfig.llm?.apiKey ?? "ollama"),
|
|
857
|
+
model: envString("RLM_LLM_MODEL", fileConfig.llm?.model ?? DEFAULT_LLM_MODEL),
|
|
858
|
+
codeModel: envString("RLM_LLM_CODE_MODEL", fileConfig.llm?.codeModel ?? DEFAULT_LLM_CODE_MODEL),
|
|
859
|
+
temperature: envNum("RLM_LLM_TEMPERATURE", fileConfig.llm?.temperature ?? 0.2),
|
|
860
|
+
maxOutputTokens: envNum("RLM_LLM_MAX_OUTPUT_TOKENS", fileConfig.llm?.maxOutputTokens ?? 8000),
|
|
861
|
+
timeoutMs: envNum("RLM_LLM_TIMEOUT_MS", fileConfig.llm?.timeoutMs ?? 90000),
|
|
862
|
+
disableThink: envBool("RLM_LLM_DISABLE_THINK", fileConfig.llm?.disableThink ?? true)
|
|
863
|
+
},
|
|
864
|
+
memory: {
|
|
865
|
+
decay: {
|
|
866
|
+
lambda: fileConfig.memory?.decay?.lambda ?? 0.02,
|
|
867
|
+
sigma: fileConfig.memory?.decay?.sigma ?? 0.6,
|
|
868
|
+
mu: fileConfig.memory?.decay?.mu ?? 0.04,
|
|
869
|
+
coldThreshold: fileConfig.memory?.decay?.coldThreshold ?? 0.2
|
|
870
|
+
},
|
|
871
|
+
bootstrap: {
|
|
872
|
+
enabled: envBool("BOOTSTRAP_ENABLED", fileConfig.memory?.bootstrap?.enabled ?? true),
|
|
873
|
+
maxSeedMemories: envNum("BOOTSTRAP_MAX_SEED_MEMORIES", fileConfig.memory?.bootstrap?.maxSeedMemories ?? 8),
|
|
874
|
+
centralityLimit: envNum("BOOTSTRAP_CENTRALITY_LIMIT", fileConfig.memory?.bootstrap?.centralityLimit ?? 10),
|
|
875
|
+
gitLogLimit: envNum("BOOTSTRAP_GIT_LOG_LIMIT", fileConfig.memory?.bootstrap?.gitLogLimit ?? 20),
|
|
876
|
+
refreshEnabled: envBool("BOOTSTRAP_REFRESH_ENABLED", fileConfig.memory?.bootstrap?.refreshEnabled ?? true)
|
|
877
|
+
},
|
|
878
|
+
autoImprove: {
|
|
879
|
+
enabled: envBool("AUTO_IMPROVE_ENABLED", fileConfig.memory?.autoImprove?.enabled ?? true),
|
|
880
|
+
reviewGate: envBool("AUTO_IMPROVE_REVIEW_GATE", fileConfig.memory?.autoImprove?.reviewGate ?? false),
|
|
881
|
+
minObservations: envNum("AUTO_IMPROVE_MIN_OBS", fileConfig.memory?.autoImprove?.minObservations ?? 8),
|
|
882
|
+
minIntervalMs: envNum("AUTO_IMPROVE_MIN_INTERVAL_MS", fileConfig.memory?.autoImprove?.minIntervalMs ?? 5 * 60 * 1000),
|
|
883
|
+
maxWindow: envNum("AUTO_IMPROVE_MAX_WINDOW", fileConfig.memory?.autoImprove?.maxWindow ?? 16),
|
|
884
|
+
minQueryHits: envNum("AUTO_IMPROVE_MIN_QUERY_HITS", fileConfig.memory?.autoImprove?.minQueryHits ?? 3),
|
|
885
|
+
minFileHits: envNum("AUTO_IMPROVE_MIN_FILE_HITS", fileConfig.memory?.autoImprove?.minFileHits ?? 3),
|
|
886
|
+
minFixHits: envNum("AUTO_IMPROVE_MIN_FIX_HITS", fileConfig.memory?.autoImprove?.minFixHits ?? 2)
|
|
887
|
+
},
|
|
888
|
+
autoImportance: {
|
|
889
|
+
enabled: envBool("AUTO_IMPORTANCE_ENABLED", fileConfig.memory?.autoImportance?.enabled ?? false)
|
|
890
|
+
}
|
|
891
|
+
},
|
|
892
|
+
hooks: {
|
|
893
|
+
enabled: envBool("HOOKS_ENABLED", fileConfig.hooks?.enabled ?? true),
|
|
894
|
+
maxPayloadBytes: envNum("HOOKS_MAX_PAYLOAD_BYTES", fileConfig.hooks?.maxPayloadBytes ?? 65536),
|
|
895
|
+
queue: {
|
|
896
|
+
maxPending: envNum("HOOKS_QUEUE_MAX_PENDING", fileConfig.hooks?.queue?.maxPending ?? 256)
|
|
897
|
+
},
|
|
898
|
+
bridge: {
|
|
899
|
+
enabled: envBool("HOOKS_BRIDGE_ENABLED", fileConfig.hooks?.bridge?.enabled ?? true),
|
|
900
|
+
minObservations: envNum("HOOKS_BRIDGE_MIN_OBS", fileConfig.hooks?.bridge?.minObservations ?? 8),
|
|
901
|
+
minIntervalMs: envNum("HOOKS_BRIDGE_MIN_INTERVAL_MS", fileConfig.hooks?.bridge?.minIntervalMs ?? 5 * 60 * 1000),
|
|
902
|
+
maxWindow: envNum("HOOKS_BRIDGE_MAX_WINDOW", fileConfig.hooks?.bridge?.maxWindow ?? 8)
|
|
903
|
+
}
|
|
904
|
+
},
|
|
905
|
+
handoffs: {
|
|
906
|
+
enabled: envBool("HANDOFFS_ENABLED", true)
|
|
907
|
+
},
|
|
908
|
+
compression: {
|
|
909
|
+
defaultStrategy: fileConfig.compression?.defaultStrategy ?? "code_structure",
|
|
910
|
+
minTokensForCompression: envNum("MIN_TOKENS_FOR_COMPRESSION", fileConfig.compression?.minTokensForCompression ?? 100),
|
|
911
|
+
targetCompressionRatio: envNum("TARGET_COMPRESSION_RATIO", fileConfig.compression?.targetCompressionRatio ?? 0.7),
|
|
912
|
+
prompt: process.env.RLM_LLM_PROMPT || fileConfig.compression?.prompt || undefined
|
|
913
|
+
},
|
|
914
|
+
impact: {
|
|
915
|
+
bfsCteEnabled: envBool("MASSA_AI_IMPACT_BFS_CTE", fileConfig.impact?.bfsCteEnabled ?? false)
|
|
916
|
+
},
|
|
917
|
+
capturePolicy: fileConfig.capturePolicy ? validateCapturePolicyConfig(fileConfig.capturePolicy) : undefined,
|
|
918
|
+
readFile: {
|
|
919
|
+
extraRoots: envString("MASSA_AI_READ_FILE_ROOTS", "").split(":").map((s) => s.trim()).filter((s) => s.length > 0)
|
|
920
|
+
},
|
|
921
|
+
filterValidation: {
|
|
922
|
+
maxFilterPatterns: envNum("MAX_FILTER_PATTERNS", 32)
|
|
923
|
+
},
|
|
924
|
+
rateLimit: {
|
|
925
|
+
requestsPerMinute: envNum("REQUESTS_PER_MINUTE", 60),
|
|
926
|
+
tokensPerMinute: envNum("TOKENS_PER_MINUTE", 1e5)
|
|
927
|
+
},
|
|
928
|
+
security: {
|
|
929
|
+
maxInputLength: envNum("MAX_INPUT_LENGTH", 1e5),
|
|
930
|
+
sanitizeInputs: process.env.SANITIZE_INPUTS !== "false",
|
|
931
|
+
maxIndexSize: 1e5,
|
|
932
|
+
maxFileSize: 1024 * 1024,
|
|
933
|
+
allowedExtensions: [...DEFAULT_ALLOWED_EXTENSIONS],
|
|
934
|
+
excludePatterns: [
|
|
935
|
+
"node_modules/**",
|
|
936
|
+
".git/**",
|
|
937
|
+
"dist/**",
|
|
938
|
+
"build/**",
|
|
939
|
+
".next/**",
|
|
940
|
+
"coverage/**",
|
|
941
|
+
"**/generated/**",
|
|
942
|
+
"*.min.js",
|
|
943
|
+
"*.min.css"
|
|
944
|
+
]
|
|
945
|
+
},
|
|
946
|
+
logging: {
|
|
947
|
+
level: process.env.LOG_LEVEL || fileConfig.logging?.level || "info",
|
|
948
|
+
enableMetrics: process.env.ENABLE_METRICS === "true" || process.env.ENABLE_METRICS === undefined && !!fileConfig.logging?.enableMetrics
|
|
949
|
+
},
|
|
950
|
+
synapse: {
|
|
951
|
+
enabled: process.env.SYNAPSE_ENABLED !== "false",
|
|
952
|
+
inhibition: {
|
|
953
|
+
diversityPenalty: {
|
|
954
|
+
enabled: true,
|
|
955
|
+
threshold: 0.85,
|
|
956
|
+
lambda: 0.4,
|
|
957
|
+
samePathPenalty: 0.15
|
|
958
|
+
},
|
|
959
|
+
temporalInhibition: {
|
|
960
|
+
enabled: true,
|
|
961
|
+
penaltyAgeMs: 3600000,
|
|
962
|
+
penalty: 0.15
|
|
963
|
+
},
|
|
964
|
+
confidenceGate: {
|
|
965
|
+
enabled: true,
|
|
966
|
+
thresholds: { specific: 0.55, focused: 0.4, broad: 0.25 }
|
|
967
|
+
},
|
|
968
|
+
chainInhibition: { enabled: true }
|
|
969
|
+
},
|
|
970
|
+
scoring: {
|
|
971
|
+
attention: {
|
|
972
|
+
enabled: process.env.SYNAPSE_ATTENTION_ENABLED === "true",
|
|
973
|
+
rerankWindow: 50,
|
|
974
|
+
recencyHalfLifeMs: 7 * 24 * 60 * 60 * 1000,
|
|
975
|
+
semanticScale: 1,
|
|
976
|
+
weights: {
|
|
977
|
+
semantic: 0.25,
|
|
978
|
+
recency: 0.15,
|
|
979
|
+
accessHeat: 0.15,
|
|
980
|
+
taskAlign: 0.2,
|
|
981
|
+
agentAffinity: 0.1,
|
|
982
|
+
confidence: 0.15
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
},
|
|
986
|
+
metacognition: {
|
|
987
|
+
enabled: true,
|
|
988
|
+
lowConfidenceThreshold: 0.15,
|
|
989
|
+
definitiveTopScore: 0.8,
|
|
990
|
+
definitiveGap: 0.2
|
|
991
|
+
},
|
|
992
|
+
buffer: {
|
|
993
|
+
enabled: true,
|
|
994
|
+
maxSize: 20,
|
|
995
|
+
ttlMs: 900000,
|
|
996
|
+
hitBoost: 1.3,
|
|
997
|
+
matchThreshold: 0.4
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
};
|
|
1001
|
+
|
|
1002
|
+
class Config {
|
|
1003
|
+
config;
|
|
1004
|
+
constructor(overrides) {
|
|
1005
|
+
this.config = this.mergeConfig(defaultConfig, overrides);
|
|
1006
|
+
this.validate();
|
|
1007
|
+
}
|
|
1008
|
+
mergeConfig(defaults, overrides) {
|
|
1009
|
+
if (!overrides)
|
|
1010
|
+
return defaults;
|
|
1011
|
+
return {
|
|
1012
|
+
...defaults,
|
|
1013
|
+
...overrides,
|
|
1014
|
+
cache: {
|
|
1015
|
+
l1: { ...defaults.cache.l1, ...overrides.cache?.l1 },
|
|
1016
|
+
l2: { ...defaults.cache.l2, ...overrides.cache?.l2 },
|
|
1017
|
+
embedding: {
|
|
1018
|
+
...defaults.cache.embedding,
|
|
1019
|
+
...overrides.cache?.embedding
|
|
1020
|
+
}
|
|
1021
|
+
},
|
|
1022
|
+
search: {
|
|
1023
|
+
...defaults.search,
|
|
1024
|
+
...overrides.search,
|
|
1025
|
+
queryUnderstanding: {
|
|
1026
|
+
...defaults.search.queryUnderstanding,
|
|
1027
|
+
...overrides.search?.queryUnderstanding
|
|
1028
|
+
},
|
|
1029
|
+
rerank: {
|
|
1030
|
+
...defaults.search.rerank,
|
|
1031
|
+
...overrides.search?.rerank
|
|
1032
|
+
}
|
|
1033
|
+
},
|
|
1034
|
+
llm: { ...defaults.llm, ...overrides.llm },
|
|
1035
|
+
memory: {
|
|
1036
|
+
...defaults.memory,
|
|
1037
|
+
...overrides.memory,
|
|
1038
|
+
decay: { ...defaults.memory.decay, ...overrides.memory?.decay },
|
|
1039
|
+
bootstrap: { ...defaults.memory.bootstrap, ...overrides.memory?.bootstrap },
|
|
1040
|
+
autoImprove: { ...defaults.memory.autoImprove, ...overrides.memory?.autoImprove },
|
|
1041
|
+
autoImportance: { ...defaults.memory.autoImportance, ...overrides.memory?.autoImportance }
|
|
1042
|
+
},
|
|
1043
|
+
hooks: {
|
|
1044
|
+
...defaults.hooks,
|
|
1045
|
+
...overrides.hooks,
|
|
1046
|
+
queue: { ...defaults.hooks.queue, ...overrides.hooks?.queue },
|
|
1047
|
+
bridge: { ...defaults.hooks.bridge, ...overrides.hooks?.bridge }
|
|
1048
|
+
},
|
|
1049
|
+
handoffs: {
|
|
1050
|
+
...defaults.handoffs,
|
|
1051
|
+
...overrides.handoffs
|
|
1052
|
+
},
|
|
1053
|
+
compression: {
|
|
1054
|
+
...defaults.compression,
|
|
1055
|
+
...overrides.compression
|
|
1056
|
+
},
|
|
1057
|
+
impact: {
|
|
1058
|
+
...defaults.impact,
|
|
1059
|
+
...overrides.impact
|
|
1060
|
+
},
|
|
1061
|
+
rateLimit: { ...defaults.rateLimit, ...overrides.rateLimit },
|
|
1062
|
+
security: { ...defaults.security, ...overrides.security },
|
|
1063
|
+
logging: { ...defaults.logging, ...overrides.logging },
|
|
1064
|
+
synapse: {
|
|
1065
|
+
...defaults.synapse,
|
|
1066
|
+
...overrides.synapse,
|
|
1067
|
+
inhibition: {
|
|
1068
|
+
...defaults.synapse.inhibition,
|
|
1069
|
+
...overrides.synapse?.inhibition,
|
|
1070
|
+
diversityPenalty: {
|
|
1071
|
+
...defaults.synapse.inhibition.diversityPenalty,
|
|
1072
|
+
...overrides.synapse?.inhibition?.diversityPenalty
|
|
1073
|
+
},
|
|
1074
|
+
temporalInhibition: {
|
|
1075
|
+
...defaults.synapse.inhibition.temporalInhibition,
|
|
1076
|
+
...overrides.synapse?.inhibition?.temporalInhibition
|
|
1077
|
+
},
|
|
1078
|
+
confidenceGate: {
|
|
1079
|
+
...defaults.synapse.inhibition.confidenceGate,
|
|
1080
|
+
...overrides.synapse?.inhibition?.confidenceGate,
|
|
1081
|
+
thresholds: {
|
|
1082
|
+
...defaults.synapse.inhibition.confidenceGate.thresholds,
|
|
1083
|
+
...overrides.synapse?.inhibition?.confidenceGate?.thresholds
|
|
1084
|
+
}
|
|
1085
|
+
},
|
|
1086
|
+
chainInhibition: {
|
|
1087
|
+
...defaults.synapse.inhibition.chainInhibition,
|
|
1088
|
+
...overrides.synapse?.inhibition?.chainInhibition
|
|
1089
|
+
}
|
|
1090
|
+
},
|
|
1091
|
+
scoring: {
|
|
1092
|
+
...defaults.synapse.scoring,
|
|
1093
|
+
...overrides.synapse?.scoring,
|
|
1094
|
+
attention: {
|
|
1095
|
+
...defaults.synapse.scoring.attention,
|
|
1096
|
+
...overrides.synapse?.scoring?.attention,
|
|
1097
|
+
weights: {
|
|
1098
|
+
...defaults.synapse.scoring.attention.weights,
|
|
1099
|
+
...overrides.synapse?.scoring?.attention?.weights
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
},
|
|
1103
|
+
metacognition: {
|
|
1104
|
+
...defaults.synapse.metacognition,
|
|
1105
|
+
...overrides.synapse?.metacognition
|
|
1106
|
+
},
|
|
1107
|
+
buffer: {
|
|
1108
|
+
...defaults.synapse.buffer,
|
|
1109
|
+
...overrides.synapse?.buffer
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1114
|
+
validate() {
|
|
1115
|
+
if (this.config.compression.targetCompressionRatio < 0 || this.config.compression.targetCompressionRatio > 1) {
|
|
1116
|
+
throw new Error("targetCompressionRatio must be between 0 and 1");
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
get(key) {
|
|
1120
|
+
return this.config[key];
|
|
1121
|
+
}
|
|
1122
|
+
getNested(path5) {
|
|
1123
|
+
return path5.split(".").reduce((obj, key) => obj?.[key], this.config);
|
|
1124
|
+
}
|
|
1125
|
+
getAll() {
|
|
1126
|
+
return { ...this.config };
|
|
1127
|
+
}
|
|
1128
|
+
set(key, value) {
|
|
1129
|
+
this.config[key] = value;
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
var config = new Config;
|
|
1133
|
+
|
|
1134
|
+
// src/config-cli.ts
|
|
1135
|
+
import { promises as fs2 } from "fs";
|
|
1136
|
+
import path5 from "path";
|
|
1137
|
+
import os3 from "os";
|
|
1138
|
+
import { fileURLToPath } from "url";
|
|
1139
|
+
var args = process.argv.slice(2);
|
|
1140
|
+
var command = args[0];
|
|
1141
|
+
var __dirname2 = path5.dirname(fileURLToPath(import.meta.url));
|
|
1142
|
+
function help() {
|
|
1143
|
+
console.log(`
|
|
1144
|
+
massa-ai-config - Configuration manager for massa-ai
|
|
1145
|
+
|
|
1146
|
+
Usage:
|
|
1147
|
+
massa-ai-config <command> [options]
|
|
1148
|
+
|
|
1149
|
+
Commands:
|
|
1150
|
+
init Initialize massa-ai configuration
|
|
1151
|
+
--ollama Use Ollama (local, default)
|
|
1152
|
+
--mistral <key> Use Mistral with API key
|
|
1153
|
+
--openai <key> Use OpenAI with API key
|
|
1154
|
+
|
|
1155
|
+
path Show config file path
|
|
1156
|
+
show Show current configuration
|
|
1157
|
+
set <key> <val> Set a configuration value
|
|
1158
|
+
use <provider> Switch embedding provider
|
|
1159
|
+
--api-key <key> API key (required for mistral/openai)
|
|
1160
|
+
--model <name> Model name
|
|
1161
|
+
--base-url <url> Base URL (for ollama)
|
|
1162
|
+
|
|
1163
|
+
agents Manage the 12 subagent specialist definitions
|
|
1164
|
+
agents install [--user|--project] Write 12 agent .md files
|
|
1165
|
+
agents uninstall [--user|--project] Remove only massa-ai-owned agents
|
|
1166
|
+
|
|
1167
|
+
Examples:
|
|
1168
|
+
massa-ai-config init
|
|
1169
|
+
massa-ai-config init --mistral your-api-key
|
|
1170
|
+
massa-ai-config use ollama --model nomic-embed-text:latest
|
|
1171
|
+
massa-ai-config use mistral --api-key your-key
|
|
1172
|
+
massa-ai-config set embedding.dimensions 1024
|
|
1173
|
+
massa-ai-config agents install --user
|
|
1174
|
+
`);
|
|
1175
|
+
}
|
|
1176
|
+
function parseOptions(args2) {
|
|
1177
|
+
const options = {};
|
|
1178
|
+
for (let i = 0;i < args2.length; i++) {
|
|
1179
|
+
if (args2[i].startsWith("--")) {
|
|
1180
|
+
const key = args2[i].slice(2);
|
|
1181
|
+
if (i + 1 < args2.length && !args2[i + 1].startsWith("--")) {
|
|
1182
|
+
options[key] = args2[i + 1];
|
|
1183
|
+
i++;
|
|
1184
|
+
} else {
|
|
1185
|
+
options[key] = true;
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
return options;
|
|
1190
|
+
}
|
|
1191
|
+
if (!command || command === "--help" || command === "-h") {
|
|
1192
|
+
help();
|
|
1193
|
+
process.exit(0);
|
|
1194
|
+
}
|
|
1195
|
+
var options = parseOptions(args.slice(1));
|
|
1196
|
+
switch (command) {
|
|
1197
|
+
case "init": {
|
|
1198
|
+
initConfig();
|
|
1199
|
+
if (options.mistral && typeof options.mistral === "string") {
|
|
1200
|
+
const config2 = loadConfig();
|
|
1201
|
+
config2.embedding = {
|
|
1202
|
+
provider: "mistral",
|
|
1203
|
+
model: "mistral-embed",
|
|
1204
|
+
apiKey: options.mistral,
|
|
1205
|
+
dimensions: 1024
|
|
1206
|
+
};
|
|
1207
|
+
saveConfig(config2);
|
|
1208
|
+
console.log("\u2713 Configured for Mistral embeddings");
|
|
1209
|
+
} else if (options.openai && typeof options.openai === "string") {
|
|
1210
|
+
const config2 = loadConfig();
|
|
1211
|
+
config2.embedding = {
|
|
1212
|
+
provider: "openai",
|
|
1213
|
+
model: "text-embedding-3-small",
|
|
1214
|
+
apiKey: options.openai,
|
|
1215
|
+
dimensions: 1536
|
|
1216
|
+
};
|
|
1217
|
+
saveConfig(config2);
|
|
1218
|
+
console.log("\u2713 Configured for OpenAI embeddings");
|
|
1219
|
+
} else {
|
|
1220
|
+
console.log("\u2713 Configured for Ollama (local) embeddings");
|
|
1221
|
+
}
|
|
1222
|
+
console.log(`
|
|
1223
|
+
Config file: ${getConfigPath()}`);
|
|
1224
|
+
break;
|
|
1225
|
+
}
|
|
1226
|
+
case "path": {
|
|
1227
|
+
console.log(getConfigPath());
|
|
1228
|
+
break;
|
|
1229
|
+
}
|
|
1230
|
+
case "show": {
|
|
1231
|
+
if (!configExists()) {
|
|
1232
|
+
console.log("No config file found. Run `massa-ai-config init` to create one.");
|
|
1233
|
+
console.log(`
|
|
1234
|
+
Using defaults:`);
|
|
1235
|
+
console.log(JSON.stringify(defaultMassaAiConfig, null, 2));
|
|
1236
|
+
process.exit(0);
|
|
1237
|
+
}
|
|
1238
|
+
const config2 = loadConfig();
|
|
1239
|
+
console.log(JSON.stringify(config2, null, 2));
|
|
1240
|
+
break;
|
|
1241
|
+
}
|
|
1242
|
+
case "set": {
|
|
1243
|
+
const key = args[1];
|
|
1244
|
+
const value = args[2];
|
|
1245
|
+
if (!key || !value) {
|
|
1246
|
+
console.error("Usage: massa-ai-config set <key> <value>");
|
|
1247
|
+
process.exit(1);
|
|
1248
|
+
}
|
|
1249
|
+
const config2 = loadConfig();
|
|
1250
|
+
const keys = key.split(".");
|
|
1251
|
+
let obj = config2;
|
|
1252
|
+
for (let i = 0;i < keys.length - 1; i++) {
|
|
1253
|
+
obj = obj[keys[i]];
|
|
1254
|
+
}
|
|
1255
|
+
const parsedValue = isNaN(Number(value)) ? value : Number(value);
|
|
1256
|
+
obj[keys[keys.length - 1]] = parsedValue;
|
|
1257
|
+
saveConfig(config2);
|
|
1258
|
+
console.log(`\u2713 Set ${key} = ${value}`);
|
|
1259
|
+
break;
|
|
1260
|
+
}
|
|
1261
|
+
case "use": {
|
|
1262
|
+
const provider = args[1];
|
|
1263
|
+
if (!provider || !["ollama", "mistral", "openai"].includes(provider)) {
|
|
1264
|
+
console.error("Provider must be: ollama, mistral, or openai");
|
|
1265
|
+
process.exit(1);
|
|
1266
|
+
}
|
|
1267
|
+
const config2 = loadConfig();
|
|
1268
|
+
if (provider === "ollama") {
|
|
1269
|
+
config2.embedding = {
|
|
1270
|
+
provider: "ollama",
|
|
1271
|
+
model: options.model || "nomic-embed-text:latest",
|
|
1272
|
+
baseURL: options["base-url"] || "http://localhost:11434",
|
|
1273
|
+
dimensions: 768
|
|
1274
|
+
};
|
|
1275
|
+
} else if (provider === "mistral") {
|
|
1276
|
+
if (!options["api-key"]) {
|
|
1277
|
+
console.error("Error: --api-key required for Mistral");
|
|
1278
|
+
process.exit(1);
|
|
1279
|
+
}
|
|
1280
|
+
config2.embedding = {
|
|
1281
|
+
provider: "mistral",
|
|
1282
|
+
model: options.model || "mistral-embed",
|
|
1283
|
+
apiKey: options["api-key"],
|
|
1284
|
+
dimensions: 1024
|
|
1285
|
+
};
|
|
1286
|
+
} else if (provider === "openai") {
|
|
1287
|
+
if (!options["api-key"]) {
|
|
1288
|
+
console.error("Error: --api-key required for OpenAI");
|
|
1289
|
+
process.exit(1);
|
|
1290
|
+
}
|
|
1291
|
+
config2.embedding = {
|
|
1292
|
+
provider: "openai",
|
|
1293
|
+
model: options.model || "text-embedding-3-small",
|
|
1294
|
+
apiKey: options["api-key"],
|
|
1295
|
+
dimensions: 1536
|
|
1296
|
+
};
|
|
1297
|
+
}
|
|
1298
|
+
saveConfig(config2);
|
|
1299
|
+
console.log(`\u2713 Switched to ${provider} embeddings`);
|
|
1300
|
+
console.log(` Model: ${config2.embedding.model}`);
|
|
1301
|
+
break;
|
|
1302
|
+
}
|
|
1303
|
+
case "agents": {
|
|
1304
|
+
const subcommand = args[1];
|
|
1305
|
+
if (subcommand !== "install" && subcommand !== "uninstall") {
|
|
1306
|
+
console.error("Usage: massa-ai-config agents <install|uninstall> [--user|--project]");
|
|
1307
|
+
process.exit(1);
|
|
1308
|
+
}
|
|
1309
|
+
const scope = typeof options.project === "boolean" ? "project" : "user";
|
|
1310
|
+
const agentsDir = scope === "project" ? path5.join(process.cwd(), ".opencode/agents") : path5.join(process.env.XDG_CONFIG_HOME && process.env.XDG_CONFIG_HOME.trim() || path5.join(os3.homedir(), ".config"), "opencode", "agents");
|
|
1311
|
+
const sourceAgentsDir = path5.resolve(__dirname2, "..", "agents");
|
|
1312
|
+
if (subcommand === "install") {
|
|
1313
|
+
await fs2.mkdir(agentsDir, { recursive: true });
|
|
1314
|
+
let count = 0;
|
|
1315
|
+
const entries = await fs2.readdir(sourceAgentsDir);
|
|
1316
|
+
for (const entry of entries) {
|
|
1317
|
+
if (!entry.startsWith("massa-ai-") || !entry.endsWith(".md"))
|
|
1318
|
+
continue;
|
|
1319
|
+
const src = path5.join(sourceAgentsDir, entry);
|
|
1320
|
+
const dest = path5.join(agentsDir, entry);
|
|
1321
|
+
await fs2.copyFile(src, dest);
|
|
1322
|
+
count++;
|
|
1323
|
+
}
|
|
1324
|
+
console.log(`+ ${count} subagent specialists: investigator, planner, builder, reviewer, context-curator, verification-agent, requirements-analyst, architecture-specialist, test-engineer, documentation-agent, audit-specialist, mobile-specialist`);
|
|
1325
|
+
console.log(` written to: ${agentsDir}`);
|
|
1326
|
+
} else {
|
|
1327
|
+
let removed = 0;
|
|
1328
|
+
try {
|
|
1329
|
+
const entries = await fs2.readdir(agentsDir);
|
|
1330
|
+
for (const entry of entries) {
|
|
1331
|
+
if (!entry.startsWith("massa-ai-") || !entry.endsWith(".md"))
|
|
1332
|
+
continue;
|
|
1333
|
+
const filePath = path5.join(agentsDir, entry);
|
|
1334
|
+
const content = await fs2.readFile(filePath, "utf8");
|
|
1335
|
+
if (content.includes("massa-ai-owned: true")) {
|
|
1336
|
+
await fs2.unlink(filePath);
|
|
1337
|
+
removed++;
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
} catch (e) {
|
|
1341
|
+
if (e.code !== "ENOENT")
|
|
1342
|
+
throw e;
|
|
1343
|
+
}
|
|
1344
|
+
console.log(`- removed ${removed} massa-ai-owned agent files from ${agentsDir}`);
|
|
1345
|
+
console.log(" User agents preserved.");
|
|
1346
|
+
}
|
|
1347
|
+
break;
|
|
1348
|
+
}
|
|
1349
|
+
default:
|
|
1350
|
+
console.error(`Unknown command: ${command}`);
|
|
1351
|
+
help();
|
|
1352
|
+
process.exit(1);
|
|
1353
|
+
}
|