@proxysoul/soulforge 2.18.3 → 2.18.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +107 -32
- package/dist/workers/intelligence.worker.js +43 -15
- package/package.json +1 -1
- package/scripts/launcher.mjs +31 -0
package/dist/index.js
CHANGED
|
@@ -5202,25 +5202,56 @@ function loadConfig() {
|
|
|
5202
5202
|
if (!existsSync10(configDir2)) {
|
|
5203
5203
|
mkdirSync8(configDir2, { recursive: true, mode: 448 });
|
|
5204
5204
|
}
|
|
5205
|
-
if (!existsSync10(configFile)) {
|
|
5206
|
-
writeFileSync7(configFile, JSON.stringify(DEFAULT_CONFIG, null, 2));
|
|
5207
|
-
if (!_presetOverlay)
|
|
5208
|
-
return DEFAULT_CONFIG;
|
|
5209
|
-
}
|
|
5210
5205
|
let userConfig = {};
|
|
5211
|
-
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5206
|
+
let fileExists = existsSync10(configFile);
|
|
5207
|
+
if (!fileExists) {
|
|
5208
|
+
writeFileSync7(configFile, JSON.stringify(DEFAULT_CONFIG, null, 2));
|
|
5209
|
+
fileExists = true;
|
|
5210
|
+
} else {
|
|
5211
|
+
try {
|
|
5212
|
+
userConfig = JSON.parse(readFileSync8(configFile, "utf-8"));
|
|
5213
|
+
} catch (err2) {
|
|
5214
|
+
logBackgroundError("config", `Failed to parse ${configFile}: ${err2 instanceof Error ? err2.message : String(err2)} \u2014 using defaults`);
|
|
5215
|
+
userConfig = {};
|
|
5216
|
+
}
|
|
5217
5217
|
}
|
|
5218
5218
|
let merged = { ...DEFAULT_CONFIG };
|
|
5219
5219
|
if (_presetOverlay)
|
|
5220
5220
|
merged = applyConfigPatch(merged, _presetOverlay);
|
|
5221
|
-
|
|
5221
|
+
const userPatch = diffAgainstDefaults(userConfig);
|
|
5222
|
+
if (Object.keys(userPatch).length > 0) {
|
|
5223
|
+
merged = applyConfigPatch(merged, userPatch);
|
|
5224
|
+
}
|
|
5222
5225
|
return merged;
|
|
5223
5226
|
}
|
|
5227
|
+
function diffAgainstDefaults(userConfig) {
|
|
5228
|
+
const out2 = {};
|
|
5229
|
+
const defaults = DEFAULT_CONFIG;
|
|
5230
|
+
const nested = new Set(NESTED_KEYS);
|
|
5231
|
+
for (const [key, value] of Object.entries(userConfig)) {
|
|
5232
|
+
if (value === undefined)
|
|
5233
|
+
continue;
|
|
5234
|
+
const def = defaults[key];
|
|
5235
|
+
if (nested.has(key) && value && typeof value === "object" && !Array.isArray(value) && def && typeof def === "object" && !Array.isArray(def)) {
|
|
5236
|
+
const subPatch = {};
|
|
5237
|
+
const defRec = def;
|
|
5238
|
+
for (const [subKey, subValue] of Object.entries(value)) {
|
|
5239
|
+
if (subValue === undefined)
|
|
5240
|
+
continue;
|
|
5241
|
+
if (JSON.stringify(subValue) !== JSON.stringify(defRec[subKey])) {
|
|
5242
|
+
subPatch[subKey] = subValue;
|
|
5243
|
+
}
|
|
5244
|
+
}
|
|
5245
|
+
if (Object.keys(subPatch).length > 0)
|
|
5246
|
+
out2[key] = subPatch;
|
|
5247
|
+
continue;
|
|
5248
|
+
}
|
|
5249
|
+
if (JSON.stringify(value) !== JSON.stringify(def)) {
|
|
5250
|
+
out2[key] = value;
|
|
5251
|
+
}
|
|
5252
|
+
}
|
|
5253
|
+
return out2;
|
|
5254
|
+
}
|
|
5224
5255
|
function loadProjectConfig(cwd) {
|
|
5225
5256
|
const projectFile = join11(cwd, ".soulforge", "config.json");
|
|
5226
5257
|
if (!existsSync10(projectFile))
|
|
@@ -71714,7 +71745,7 @@ var package_default;
|
|
|
71714
71745
|
var init_package = __esm(() => {
|
|
71715
71746
|
package_default = {
|
|
71716
71747
|
name: "@proxysoul/soulforge",
|
|
71717
|
-
version: "2.18.
|
|
71748
|
+
version: "2.18.4",
|
|
71718
71749
|
description: "Graph-powered code intelligence \u2014 multi-agent coding with codebase-aware AI",
|
|
71719
71750
|
repository: {
|
|
71720
71751
|
type: "git",
|
|
@@ -74060,6 +74091,17 @@ function createReasoningFetchWrapper(reasoningBody) {
|
|
|
74060
74091
|
}
|
|
74061
74092
|
|
|
74062
74093
|
// src/core/llm/providers/custom.ts
|
|
74094
|
+
function normalizeBaseURLPath(baseURL) {
|
|
74095
|
+
return baseURL.replace(/\/v1(?:\/)?$/i, "").replace(/\/+$/, "");
|
|
74096
|
+
}
|
|
74097
|
+
function resolveModelsAPIUrl(config2) {
|
|
74098
|
+
if (config2.modelsAPI === false)
|
|
74099
|
+
return null;
|
|
74100
|
+
if (config2.modelsAPI)
|
|
74101
|
+
return config2.modelsAPI;
|
|
74102
|
+
const normalized = normalizeBaseURLPath(config2.baseURL);
|
|
74103
|
+
return `${normalized}/models`;
|
|
74104
|
+
}
|
|
74063
74105
|
function normalizeModels(models) {
|
|
74064
74106
|
if (!models || models.length === 0)
|
|
74065
74107
|
return [];
|
|
@@ -74097,22 +74139,41 @@ function buildCustomProvider(config2) {
|
|
|
74097
74139
|
return client.chatModel(modelId);
|
|
74098
74140
|
},
|
|
74099
74141
|
async fetchModels() {
|
|
74100
|
-
|
|
74142
|
+
const modelsUrl = resolveModelsAPIUrl(config2);
|
|
74143
|
+
if (!modelsUrl)
|
|
74101
74144
|
return null;
|
|
74102
74145
|
const apiKey = envVar ? getProviderApiKey(envVar) ?? "" : "";
|
|
74103
74146
|
const headers = { "Content-Type": "application/json" };
|
|
74104
74147
|
if (apiKey)
|
|
74105
74148
|
headers.Authorization = `Bearer ${apiKey}`;
|
|
74106
|
-
|
|
74107
|
-
|
|
74108
|
-
|
|
74109
|
-
|
|
74149
|
+
let res;
|
|
74150
|
+
try {
|
|
74151
|
+
res = await fetch(modelsUrl, {
|
|
74152
|
+
headers,
|
|
74153
|
+
signal: AbortSignal.timeout(2000)
|
|
74154
|
+
});
|
|
74155
|
+
} catch {
|
|
74156
|
+
return null;
|
|
74157
|
+
}
|
|
74110
74158
|
if (!res.ok)
|
|
74111
74159
|
return null;
|
|
74112
|
-
|
|
74113
|
-
|
|
74160
|
+
let parsed;
|
|
74161
|
+
try {
|
|
74162
|
+
parsed = await res.json();
|
|
74163
|
+
} catch {
|
|
74114
74164
|
return null;
|
|
74115
|
-
|
|
74165
|
+
}
|
|
74166
|
+
if (!Array.isArray(parsed.data))
|
|
74167
|
+
return null;
|
|
74168
|
+
return parsed.data.map((m) => {
|
|
74169
|
+
const rawContext = m.context_length ?? m.max_context_length ?? m.model_info?.max_input_tokens ?? m.meta?.n_ctx_train;
|
|
74170
|
+
const contextWindow = typeof rawContext === "number" ? rawContext : typeof rawContext === "string" ? Number(rawContext) : undefined;
|
|
74171
|
+
return {
|
|
74172
|
+
id: m.id,
|
|
74173
|
+
name: m.id,
|
|
74174
|
+
...contextWindow !== undefined && !Number.isNaN(contextWindow) ? { contextWindow } : {}
|
|
74175
|
+
};
|
|
74176
|
+
});
|
|
74116
74177
|
},
|
|
74117
74178
|
fallbackModels: normalizeModels(config2.models),
|
|
74118
74179
|
contextWindows: [],
|
|
@@ -468144,17 +468205,14 @@ function expandEnv(value) {
|
|
|
468144
468205
|
return value;
|
|
468145
468206
|
}
|
|
468146
468207
|
function validatePreset(raw2, origin) {
|
|
468147
|
-
|
|
468148
|
-
|
|
468149
|
-
|
|
468150
|
-
|
|
468151
|
-
|
|
468152
|
-
throw new Error(`Preset at ${origin}:
|
|
468153
|
-
}
|
|
468154
|
-
if (typeof obj.version !== "string" || !/^\d+\.\d+\.\d+$/.test(obj.version)) {
|
|
468155
|
-
throw new Error(`Preset at ${origin}: invalid or missing "version" (semver required)`);
|
|
468208
|
+
const expanded = expandEnv(raw2);
|
|
468209
|
+
const parsed = PresetSchema.safeParse(expanded);
|
|
468210
|
+
if (!parsed.success) {
|
|
468211
|
+
const issue2 = parsed.error.issues[0];
|
|
468212
|
+
const path = issue2?.path.length ? issue2.path.join(".") : "<root>";
|
|
468213
|
+
throw new Error(`Preset at ${origin}: ${path} \u2014 ${issue2?.message ?? "invalid shape"}`);
|
|
468156
468214
|
}
|
|
468157
|
-
return
|
|
468215
|
+
return parsed.data;
|
|
468158
468216
|
}
|
|
468159
468217
|
function cacheFile(name39, version2) {
|
|
468160
468218
|
return join55(getCacheDir(), `${name39}@${version2}.json`);
|
|
@@ -468249,11 +468307,28 @@ async function resolvePresets(specs, opts = {}) {
|
|
|
468249
468307
|
failures
|
|
468250
468308
|
};
|
|
468251
468309
|
}
|
|
468252
|
-
var NETWORK_TIMEOUT_MS2 = 1e4, MAX_PRESET_BYTES;
|
|
468310
|
+
var NETWORK_TIMEOUT_MS2 = 1e4, MAX_PRESET_BYTES, PresetSchema;
|
|
468253
468311
|
var init_loader3 = __esm(() => {
|
|
468312
|
+
init_zod();
|
|
468254
468313
|
init_platform();
|
|
468255
468314
|
init_registry2();
|
|
468256
468315
|
MAX_PRESET_BYTES = 512 * 1024;
|
|
468316
|
+
PresetSchema = exports_external.object({
|
|
468317
|
+
name: exports_external.string().regex(/^[a-z0-9][a-z0-9-]*$/, "name must be lowercase, start with [a-z0-9], hyphen-separated"),
|
|
468318
|
+
version: exports_external.string().regex(/^\d+\.\d+\.\d+$/, "version must be semver (x.y.z)"),
|
|
468319
|
+
description: exports_external.string().optional(),
|
|
468320
|
+
author: exports_external.string().optional(),
|
|
468321
|
+
homepage: exports_external.string().optional(),
|
|
468322
|
+
tags: exports_external.array(exports_external.string()).optional(),
|
|
468323
|
+
router: exports_external.record(exports_external.string(), exports_external.unknown()).optional(),
|
|
468324
|
+
routerRules: exports_external.unknown().optional(),
|
|
468325
|
+
providers: exports_external.unknown().optional(),
|
|
468326
|
+
theme: exports_external.unknown().optional(),
|
|
468327
|
+
themes: exports_external.record(exports_external.string(), exports_external.unknown()).optional(),
|
|
468328
|
+
hooks: exports_external.record(exports_external.string(), exports_external.unknown()).optional(),
|
|
468329
|
+
prompts: exports_external.record(exports_external.string(), exports_external.unknown()).optional(),
|
|
468330
|
+
config: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
468331
|
+
}).passthrough();
|
|
468257
468332
|
});
|
|
468258
468333
|
|
|
468259
468334
|
// src/core/presets/merge.ts
|
|
@@ -29346,30 +29346,58 @@ function loadConfig() {
|
|
|
29346
29346
|
mode: 448
|
|
29347
29347
|
});
|
|
29348
29348
|
}
|
|
29349
|
-
if (!existsSync7(configFile)) {
|
|
29350
|
-
writeFileSync3(configFile, JSON.stringify(DEFAULT_CONFIG, null, 2));
|
|
29351
|
-
if (!_presetOverlay)
|
|
29352
|
-
return DEFAULT_CONFIG;
|
|
29353
|
-
}
|
|
29354
29349
|
let userConfig = {};
|
|
29355
|
-
|
|
29356
|
-
|
|
29357
|
-
|
|
29358
|
-
|
|
29359
|
-
|
|
29360
|
-
|
|
29350
|
+
let fileExists = existsSync7(configFile);
|
|
29351
|
+
if (!fileExists) {
|
|
29352
|
+
writeFileSync3(configFile, JSON.stringify(DEFAULT_CONFIG, null, 2));
|
|
29353
|
+
fileExists = true;
|
|
29354
|
+
} else {
|
|
29355
|
+
try {
|
|
29356
|
+
userConfig = JSON.parse(readFileSync4(configFile, "utf-8"));
|
|
29357
|
+
} catch (err2) {
|
|
29358
|
+
logBackgroundError("config", `Failed to parse ${configFile}: ${err2 instanceof Error ? err2.message : String(err2)} \u2014 using defaults`);
|
|
29359
|
+
userConfig = {};
|
|
29360
|
+
}
|
|
29361
29361
|
}
|
|
29362
29362
|
let merged = {
|
|
29363
29363
|
...DEFAULT_CONFIG
|
|
29364
29364
|
};
|
|
29365
29365
|
if (_presetOverlay)
|
|
29366
29366
|
merged = applyConfigPatch(merged, _presetOverlay);
|
|
29367
|
-
|
|
29368
|
-
|
|
29369
|
-
|
|
29370
|
-
}
|
|
29367
|
+
const userPatch = diffAgainstDefaults(userConfig);
|
|
29368
|
+
if (Object.keys(userPatch).length > 0) {
|
|
29369
|
+
merged = applyConfigPatch(merged, userPatch);
|
|
29370
|
+
}
|
|
29371
29371
|
return merged;
|
|
29372
29372
|
}
|
|
29373
|
+
function diffAgainstDefaults(userConfig) {
|
|
29374
|
+
const out2 = {};
|
|
29375
|
+
const defaults = DEFAULT_CONFIG;
|
|
29376
|
+
const nested = new Set(NESTED_KEYS);
|
|
29377
|
+
for (const [key2, value] of Object.entries(userConfig)) {
|
|
29378
|
+
if (value === undefined)
|
|
29379
|
+
continue;
|
|
29380
|
+
const def = defaults[key2];
|
|
29381
|
+
if (nested.has(key2) && value && typeof value === "object" && !Array.isArray(value) && def && typeof def === "object" && !Array.isArray(def)) {
|
|
29382
|
+
const subPatch = {};
|
|
29383
|
+
const defRec = def;
|
|
29384
|
+
for (const [subKey, subValue] of Object.entries(value)) {
|
|
29385
|
+
if (subValue === undefined)
|
|
29386
|
+
continue;
|
|
29387
|
+
if (JSON.stringify(subValue) !== JSON.stringify(defRec[subKey])) {
|
|
29388
|
+
subPatch[subKey] = subValue;
|
|
29389
|
+
}
|
|
29390
|
+
}
|
|
29391
|
+
if (Object.keys(subPatch).length > 0)
|
|
29392
|
+
out2[key2] = subPatch;
|
|
29393
|
+
continue;
|
|
29394
|
+
}
|
|
29395
|
+
if (JSON.stringify(value) !== JSON.stringify(def)) {
|
|
29396
|
+
out2[key2] = value;
|
|
29397
|
+
}
|
|
29398
|
+
}
|
|
29399
|
+
return out2;
|
|
29400
|
+
}
|
|
29373
29401
|
function loadProjectConfig(cwd) {
|
|
29374
29402
|
const projectFile = join9(cwd, ".soulforge", "config.json");
|
|
29375
29403
|
if (!existsSync7(projectFile))
|
package/package.json
CHANGED
package/scripts/launcher.mjs
CHANGED
|
@@ -78,12 +78,43 @@ if (!existsSync(entry)) {
|
|
|
78
78
|
process.exit(1);
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
// detached:true puts the child in its own process group (POSIX) / detaches
|
|
82
|
+
// from the parent console (Windows). The child's cleanup path calls
|
|
83
|
+
// `kill(-pid, SIGTERM)` to reap orphaned grandchildren — without a separate
|
|
84
|
+
// group that signal would also terminate this launcher, causing zsh/bash to
|
|
85
|
+
// print "terminated soulforge" and scroll past the child's exit banner.
|
|
81
86
|
const child = spawn(bun, [entry, ...process.argv.slice(2)], {
|
|
82
87
|
stdio: "inherit",
|
|
88
|
+
detached: !isWindows,
|
|
83
89
|
windowsHide: false,
|
|
84
90
|
});
|
|
91
|
+
|
|
92
|
+
// Forward terminal signals to the child's group. On POSIX with detached:true
|
|
93
|
+
// the TTY no longer broadcasts SIGINT to the child automatically, so we relay.
|
|
94
|
+
// On Windows the console still routes Ctrl+C/Break to the child; these
|
|
95
|
+
// handlers are harmless no-ops there (signal forwarding via process.kill on
|
|
96
|
+
// Windows just terminates — child handles its own console events).
|
|
97
|
+
const FORWARDED = ["SIGINT", "SIGTERM", "SIGHUP"];
|
|
98
|
+
for (const sig of FORWARDED) {
|
|
99
|
+
process.on(sig, () => {
|
|
100
|
+
try {
|
|
101
|
+
if (isWindows) {
|
|
102
|
+
// Windows: signal the child directly; no process-group concept.
|
|
103
|
+
child.kill(sig);
|
|
104
|
+
} else {
|
|
105
|
+
// POSIX: signal the child's process group so its own children get it too.
|
|
106
|
+
process.kill(-child.pid, sig);
|
|
107
|
+
}
|
|
108
|
+
} catch {
|
|
109
|
+
// Child already gone — let our own exit logic run.
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
85
114
|
child.on("exit", (code, signal) => {
|
|
86
115
|
if (signal) {
|
|
116
|
+
// Re-raise so the parent shell sees the correct exit status, but only
|
|
117
|
+
// for genuine signal terminations — clean exits with code 0 fall through.
|
|
87
118
|
process.kill(process.pid, signal);
|
|
88
119
|
} else {
|
|
89
120
|
process.exit(code ?? 0);
|