oh-my-opencode-slim 0.8.2 → 0.8.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/README.md +80 -21
- package/dist/cli/config-io.d.ts +1 -5
- package/dist/cli/config-manager.d.ts +0 -8
- package/dist/cli/custom-skills.d.ts +2 -2
- package/dist/cli/index.js +209 -2817
- package/dist/cli/paths.d.ts +12 -0
- package/dist/cli/providers.d.ts +23 -123
- package/dist/cli/types.d.ts +2 -102
- package/dist/config/loader.d.ts +2 -1
- package/dist/config/schema.d.ts +3 -0
- package/dist/hooks/foreground-fallback/index.d.ts +72 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/index.js +1261 -179
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/lsp/config-store.d.ts +29 -0
- package/dist/tools/lsp/constants.d.ts +18 -2
- package/dist/tools/lsp/index.d.ts +1 -0
- package/dist/tools/lsp/types.d.ts +7 -0
- package/dist/tools/lsp/utils.d.ts +14 -1
- package/oh-my-opencode-slim.schema.json +448 -0
- package/package.json +6 -2
- package/src/skills/cartography/SKILL.md +23 -0
package/dist/index.js
CHANGED
|
@@ -3037,7 +3037,7 @@ var require_main = __commonJS((exports) => {
|
|
|
3037
3037
|
var ril_1 = require_ril();
|
|
3038
3038
|
ril_1.default.install();
|
|
3039
3039
|
var path6 = __require("path");
|
|
3040
|
-
var
|
|
3040
|
+
var os3 = __require("os");
|
|
3041
3041
|
var crypto_1 = __require("crypto");
|
|
3042
3042
|
var net_1 = __require("net");
|
|
3043
3043
|
var api_1 = require_api();
|
|
@@ -3180,7 +3180,7 @@ var require_main = __commonJS((exports) => {
|
|
|
3180
3180
|
if (XDG_RUNTIME_DIR) {
|
|
3181
3181
|
result = path6.join(XDG_RUNTIME_DIR, `vscode-ipc-${randomSuffix}.sock`);
|
|
3182
3182
|
} else {
|
|
3183
|
-
result = path6.join(
|
|
3183
|
+
result = path6.join(os3.tmpdir(), `vscode-${randomSuffix}.sock`);
|
|
3184
3184
|
}
|
|
3185
3185
|
const limit = safeIpcPathLengths.get(process.platform);
|
|
3186
3186
|
if (limit !== undefined && result.length > limit) {
|
|
@@ -3277,6 +3277,243 @@ var require_main = __commonJS((exports) => {
|
|
|
3277
3277
|
exports.createMessageConnection = createMessageConnection;
|
|
3278
3278
|
});
|
|
3279
3279
|
|
|
3280
|
+
// node_modules/isexe/dist/commonjs/index.min.js
|
|
3281
|
+
var require_index_min = __commonJS((exports) => {
|
|
3282
|
+
var a = (t, e) => () => (e || t((e = { exports: {} }).exports, e), e.exports);
|
|
3283
|
+
var _ = a((i) => {
|
|
3284
|
+
Object.defineProperty(i, "__esModule", { value: true });
|
|
3285
|
+
i.sync = i.isexe = undefined;
|
|
3286
|
+
var M = __require("fs"), x = __require("fs/promises"), q = async (t, e = {}) => {
|
|
3287
|
+
let { ignoreErrors: r = false } = e;
|
|
3288
|
+
try {
|
|
3289
|
+
return d(await (0, x.stat)(t), e);
|
|
3290
|
+
} catch (s) {
|
|
3291
|
+
let n = s;
|
|
3292
|
+
if (r || n.code === "EACCES")
|
|
3293
|
+
return false;
|
|
3294
|
+
throw n;
|
|
3295
|
+
}
|
|
3296
|
+
};
|
|
3297
|
+
i.isexe = q;
|
|
3298
|
+
var m = (t, e = {}) => {
|
|
3299
|
+
let { ignoreErrors: r = false } = e;
|
|
3300
|
+
try {
|
|
3301
|
+
return d((0, M.statSync)(t), e);
|
|
3302
|
+
} catch (s) {
|
|
3303
|
+
let n = s;
|
|
3304
|
+
if (r || n.code === "EACCES")
|
|
3305
|
+
return false;
|
|
3306
|
+
throw n;
|
|
3307
|
+
}
|
|
3308
|
+
};
|
|
3309
|
+
i.sync = m;
|
|
3310
|
+
var d = (t, e) => t.isFile() && A(t, e), A = (t, e) => {
|
|
3311
|
+
let r = e.uid ?? process.getuid?.(), s = e.groups ?? process.getgroups?.() ?? [], n = e.gid ?? process.getgid?.() ?? s[0];
|
|
3312
|
+
if (r === undefined || n === undefined)
|
|
3313
|
+
throw new Error("cannot get uid or gid");
|
|
3314
|
+
let u = new Set([n, ...s]), c = t.mode, S = t.uid, P = t.gid, f = parseInt("100", 8), l = parseInt("010", 8), j = parseInt("001", 8), C = f | l;
|
|
3315
|
+
return !!(c & j || c & l && u.has(P) || c & f && S === r || c & C && r === 0);
|
|
3316
|
+
};
|
|
3317
|
+
});
|
|
3318
|
+
var g = a((o) => {
|
|
3319
|
+
Object.defineProperty(o, "__esModule", { value: true });
|
|
3320
|
+
o.sync = o.isexe = undefined;
|
|
3321
|
+
var T = __require("fs"), I = __require("fs/promises"), D = __require("path"), F = async (t, e = {}) => {
|
|
3322
|
+
let { ignoreErrors: r = false } = e;
|
|
3323
|
+
try {
|
|
3324
|
+
return y(await (0, I.stat)(t), t, e);
|
|
3325
|
+
} catch (s) {
|
|
3326
|
+
let n = s;
|
|
3327
|
+
if (r || n.code === "EACCES")
|
|
3328
|
+
return false;
|
|
3329
|
+
throw n;
|
|
3330
|
+
}
|
|
3331
|
+
};
|
|
3332
|
+
o.isexe = F;
|
|
3333
|
+
var L = (t, e = {}) => {
|
|
3334
|
+
let { ignoreErrors: r = false } = e;
|
|
3335
|
+
try {
|
|
3336
|
+
return y((0, T.statSync)(t), t, e);
|
|
3337
|
+
} catch (s) {
|
|
3338
|
+
let n = s;
|
|
3339
|
+
if (r || n.code === "EACCES")
|
|
3340
|
+
return false;
|
|
3341
|
+
throw n;
|
|
3342
|
+
}
|
|
3343
|
+
};
|
|
3344
|
+
o.sync = L;
|
|
3345
|
+
var B = (t, e) => {
|
|
3346
|
+
let { pathExt: r = process.env.PATHEXT || "" } = e, s = r.split(D.delimiter);
|
|
3347
|
+
if (s.indexOf("") !== -1)
|
|
3348
|
+
return true;
|
|
3349
|
+
for (let n of s) {
|
|
3350
|
+
let u = n.toLowerCase(), c = t.substring(t.length - u.length).toLowerCase();
|
|
3351
|
+
if (u && c === u)
|
|
3352
|
+
return true;
|
|
3353
|
+
}
|
|
3354
|
+
return false;
|
|
3355
|
+
}, y = (t, e, r) => t.isFile() && B(e, r);
|
|
3356
|
+
});
|
|
3357
|
+
var p = a((h) => {
|
|
3358
|
+
Object.defineProperty(h, "__esModule", { value: true });
|
|
3359
|
+
});
|
|
3360
|
+
var v = exports && exports.__createBinding || (Object.create ? function(t, e, r, s) {
|
|
3361
|
+
s === undefined && (s = r);
|
|
3362
|
+
var n = Object.getOwnPropertyDescriptor(e, r);
|
|
3363
|
+
(!n || ("get" in n ? !e.__esModule : n.writable || n.configurable)) && (n = { enumerable: true, get: function() {
|
|
3364
|
+
return e[r];
|
|
3365
|
+
} }), Object.defineProperty(t, s, n);
|
|
3366
|
+
} : function(t, e, r, s) {
|
|
3367
|
+
s === undefined && (s = r), t[s] = e[r];
|
|
3368
|
+
});
|
|
3369
|
+
var G = exports && exports.__setModuleDefault || (Object.create ? function(t, e) {
|
|
3370
|
+
Object.defineProperty(t, "default", { enumerable: true, value: e });
|
|
3371
|
+
} : function(t, e) {
|
|
3372
|
+
t.default = e;
|
|
3373
|
+
});
|
|
3374
|
+
var w = exports && exports.__importStar || function() {
|
|
3375
|
+
var t = function(e) {
|
|
3376
|
+
return t = Object.getOwnPropertyNames || function(r) {
|
|
3377
|
+
var s = [];
|
|
3378
|
+
for (var n in r)
|
|
3379
|
+
Object.prototype.hasOwnProperty.call(r, n) && (s[s.length] = n);
|
|
3380
|
+
return s;
|
|
3381
|
+
}, t(e);
|
|
3382
|
+
};
|
|
3383
|
+
return function(e) {
|
|
3384
|
+
if (e && e.__esModule)
|
|
3385
|
+
return e;
|
|
3386
|
+
var r = {};
|
|
3387
|
+
if (e != null)
|
|
3388
|
+
for (var s = t(e), n = 0;n < s.length; n++)
|
|
3389
|
+
s[n] !== "default" && v(r, e, s[n]);
|
|
3390
|
+
return G(r, e), r;
|
|
3391
|
+
};
|
|
3392
|
+
}();
|
|
3393
|
+
var X = exports && exports.__exportStar || function(t, e) {
|
|
3394
|
+
for (var r in t)
|
|
3395
|
+
r !== "default" && !Object.prototype.hasOwnProperty.call(e, r) && v(e, t, r);
|
|
3396
|
+
};
|
|
3397
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3398
|
+
exports.sync = exports.isexe = exports.posix = exports.win32 = undefined;
|
|
3399
|
+
var E = w(_());
|
|
3400
|
+
exports.posix = E;
|
|
3401
|
+
var O = w(g());
|
|
3402
|
+
exports.win32 = O;
|
|
3403
|
+
X(p(), exports);
|
|
3404
|
+
var H = process.env._ISEXE_TEST_PLATFORM_ || process.platform;
|
|
3405
|
+
var b = H === "win32" ? O : E;
|
|
3406
|
+
exports.isexe = b.isexe;
|
|
3407
|
+
exports.sync = b.sync;
|
|
3408
|
+
});
|
|
3409
|
+
|
|
3410
|
+
// node_modules/which/lib/index.js
|
|
3411
|
+
var require_lib = __commonJS((exports, module) => {
|
|
3412
|
+
var { isexe, sync: isexeSync } = require_index_min();
|
|
3413
|
+
var { join: join11, delimiter, sep, posix } = __require("path");
|
|
3414
|
+
var isWindows = process.platform === "win32";
|
|
3415
|
+
var rSlash = new RegExp(`[${posix.sep}${sep === posix.sep ? "" : sep}]`.replace(/(\\)/g, "\\$1"));
|
|
3416
|
+
var rRel = new RegExp(`^\\.${rSlash.source}`);
|
|
3417
|
+
var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
|
|
3418
|
+
var getPathInfo = (cmd, {
|
|
3419
|
+
path: optPath = process.env.PATH,
|
|
3420
|
+
pathExt: optPathExt = process.env.PATHEXT,
|
|
3421
|
+
delimiter: optDelimiter = delimiter
|
|
3422
|
+
}) => {
|
|
3423
|
+
const pathEnv = cmd.match(rSlash) ? [""] : [
|
|
3424
|
+
...isWindows ? [process.cwd()] : [],
|
|
3425
|
+
...(optPath || "").split(optDelimiter)
|
|
3426
|
+
];
|
|
3427
|
+
if (isWindows) {
|
|
3428
|
+
const pathExtExe = optPathExt || [".EXE", ".CMD", ".BAT", ".COM"].join(optDelimiter);
|
|
3429
|
+
const pathExt = pathExtExe.split(optDelimiter).flatMap((item) => [item, item.toLowerCase()]);
|
|
3430
|
+
if (cmd.includes(".") && pathExt[0] !== "") {
|
|
3431
|
+
pathExt.unshift("");
|
|
3432
|
+
}
|
|
3433
|
+
return { pathEnv, pathExt, pathExtExe };
|
|
3434
|
+
}
|
|
3435
|
+
return { pathEnv, pathExt: [""] };
|
|
3436
|
+
};
|
|
3437
|
+
var getPathPart = (raw, cmd) => {
|
|
3438
|
+
const pathPart = /^".*"$/.test(raw) ? raw.slice(1, -1) : raw;
|
|
3439
|
+
const prefix = !pathPart && rRel.test(cmd) ? cmd.slice(0, 2) : "";
|
|
3440
|
+
return prefix + join11(pathPart, cmd);
|
|
3441
|
+
};
|
|
3442
|
+
var which = async (cmd, opt = {}) => {
|
|
3443
|
+
const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
|
|
3444
|
+
const found = [];
|
|
3445
|
+
for (const envPart of pathEnv) {
|
|
3446
|
+
const p = getPathPart(envPart, cmd);
|
|
3447
|
+
for (const ext of pathExt) {
|
|
3448
|
+
const withExt = p + ext;
|
|
3449
|
+
const is = await isexe(withExt, { pathExt: pathExtExe, ignoreErrors: true });
|
|
3450
|
+
if (is) {
|
|
3451
|
+
if (!opt.all) {
|
|
3452
|
+
return withExt;
|
|
3453
|
+
}
|
|
3454
|
+
found.push(withExt);
|
|
3455
|
+
}
|
|
3456
|
+
}
|
|
3457
|
+
}
|
|
3458
|
+
if (opt.all && found.length) {
|
|
3459
|
+
return found;
|
|
3460
|
+
}
|
|
3461
|
+
if (opt.nothrow) {
|
|
3462
|
+
return null;
|
|
3463
|
+
}
|
|
3464
|
+
throw getNotFoundError(cmd);
|
|
3465
|
+
};
|
|
3466
|
+
var whichSync = (cmd, opt = {}) => {
|
|
3467
|
+
const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
|
|
3468
|
+
const found = [];
|
|
3469
|
+
for (const pathEnvPart of pathEnv) {
|
|
3470
|
+
const p = getPathPart(pathEnvPart, cmd);
|
|
3471
|
+
for (const ext of pathExt) {
|
|
3472
|
+
const withExt = p + ext;
|
|
3473
|
+
const is = isexeSync(withExt, { pathExt: pathExtExe, ignoreErrors: true });
|
|
3474
|
+
if (is) {
|
|
3475
|
+
if (!opt.all) {
|
|
3476
|
+
return withExt;
|
|
3477
|
+
}
|
|
3478
|
+
found.push(withExt);
|
|
3479
|
+
}
|
|
3480
|
+
}
|
|
3481
|
+
}
|
|
3482
|
+
if (opt.all && found.length) {
|
|
3483
|
+
return found;
|
|
3484
|
+
}
|
|
3485
|
+
if (opt.nothrow) {
|
|
3486
|
+
return null;
|
|
3487
|
+
}
|
|
3488
|
+
throw getNotFoundError(cmd);
|
|
3489
|
+
};
|
|
3490
|
+
module.exports = which;
|
|
3491
|
+
which.sync = whichSync;
|
|
3492
|
+
});
|
|
3493
|
+
|
|
3494
|
+
// src/cli/paths.ts
|
|
3495
|
+
import { homedir } from "os";
|
|
3496
|
+
import { dirname, join } from "path";
|
|
3497
|
+
function getDefaultOpenCodeConfigDir() {
|
|
3498
|
+
const userConfigDir = process.env.XDG_CONFIG_HOME ? process.env.XDG_CONFIG_HOME : join(homedir(), ".config");
|
|
3499
|
+
return join(userConfigDir, "opencode");
|
|
3500
|
+
}
|
|
3501
|
+
function getCustomOpenCodeConfigDir() {
|
|
3502
|
+
const configDir = process.env.OPENCODE_CONFIG_DIR?.trim();
|
|
3503
|
+
return configDir || undefined;
|
|
3504
|
+
}
|
|
3505
|
+
function getConfigDir() {
|
|
3506
|
+
const customConfigDir = getCustomOpenCodeConfigDir();
|
|
3507
|
+
if (customConfigDir) {
|
|
3508
|
+
return customConfigDir;
|
|
3509
|
+
}
|
|
3510
|
+
return getDefaultOpenCodeConfigDir();
|
|
3511
|
+
}
|
|
3512
|
+
function getOpenCodeConfigPaths() {
|
|
3513
|
+
const configDir = getDefaultOpenCodeConfigDir();
|
|
3514
|
+
return [join(configDir, "opencode.json"), join(configDir, "opencode.jsonc")];
|
|
3515
|
+
}
|
|
3516
|
+
|
|
3280
3517
|
// src/cli/custom-skills.ts
|
|
3281
3518
|
var CUSTOM_SKILLS = [
|
|
3282
3519
|
{
|
|
@@ -3377,11 +3614,11 @@ var SUBAGENT_DELEGATION_RULES = {
|
|
|
3377
3614
|
};
|
|
3378
3615
|
var DEFAULT_MODELS = {
|
|
3379
3616
|
orchestrator: undefined,
|
|
3380
|
-
oracle: "openai/gpt-5.
|
|
3381
|
-
librarian: "openai/gpt-5.
|
|
3382
|
-
explorer: "openai/gpt-5.
|
|
3383
|
-
designer: "
|
|
3384
|
-
fixer: "openai/gpt-5.
|
|
3617
|
+
oracle: "openai/gpt-5.4",
|
|
3618
|
+
librarian: "openai/gpt-5.4-mini",
|
|
3619
|
+
explorer: "openai/gpt-5.4-mini",
|
|
3620
|
+
designer: "openai/gpt-5.4-mini",
|
|
3621
|
+
fixer: "openai/gpt-5.4-mini"
|
|
3385
3622
|
};
|
|
3386
3623
|
var POLL_INTERVAL_BACKGROUND_MS = 2000;
|
|
3387
3624
|
var DEFAULT_TIMEOUT_MS = 2 * 60 * 1000;
|
|
@@ -3389,21 +3626,8 @@ var MAX_POLL_TIME_MS = 5 * 60 * 1000;
|
|
|
3389
3626
|
var FALLBACK_FAILOVER_TIMEOUT_MS = 15000;
|
|
3390
3627
|
// src/config/loader.ts
|
|
3391
3628
|
import * as fs from "fs";
|
|
3392
|
-
import * as os from "os";
|
|
3393
3629
|
import * as path from "path";
|
|
3394
3630
|
|
|
3395
|
-
// src/cli/paths.ts
|
|
3396
|
-
import { homedir } from "os";
|
|
3397
|
-
import { join } from "path";
|
|
3398
|
-
function getConfigDir() {
|
|
3399
|
-
const userConfigDir = process.env.XDG_CONFIG_HOME ? process.env.XDG_CONFIG_HOME : join(homedir(), ".config");
|
|
3400
|
-
return join(userConfigDir, "opencode");
|
|
3401
|
-
}
|
|
3402
|
-
function getOpenCodeConfigPaths() {
|
|
3403
|
-
const configDir = getConfigDir();
|
|
3404
|
-
return [join(configDir, "opencode.json"), join(configDir, "opencode.jsonc")];
|
|
3405
|
-
}
|
|
3406
|
-
|
|
3407
3631
|
// src/config/agent-mcps.ts
|
|
3408
3632
|
var DEFAULT_AGENT_MCPS = {
|
|
3409
3633
|
orchestrator: ["websearch"],
|
|
@@ -5682,7 +5906,7 @@ class Doc {
|
|
|
5682
5906
|
var version = {
|
|
5683
5907
|
major: 4,
|
|
5684
5908
|
minor: 3,
|
|
5685
|
-
patch:
|
|
5909
|
+
patch: 6
|
|
5686
5910
|
};
|
|
5687
5911
|
|
|
5688
5912
|
// node_modules/zod/v4/core/schemas.js
|
|
@@ -6968,7 +7192,7 @@ var $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
|
|
|
6968
7192
|
if (keyResult instanceof Promise) {
|
|
6969
7193
|
throw new Error("Async schemas not supported in object keys currently");
|
|
6970
7194
|
}
|
|
6971
|
-
const checkNumericKey = typeof key === "string" && number.test(key) && keyResult.issues.length
|
|
7195
|
+
const checkNumericKey = typeof key === "string" && number.test(key) && keyResult.issues.length;
|
|
6972
7196
|
if (checkNumericKey) {
|
|
6973
7197
|
const retryResult = def.keyType._zod.run({ value: Number(key), issues: [] }, ctx);
|
|
6974
7198
|
if (retryResult instanceof Promise) {
|
|
@@ -14339,7 +14563,7 @@ function finalize(ctx, schema) {
|
|
|
14339
14563
|
}
|
|
14340
14564
|
}
|
|
14341
14565
|
}
|
|
14342
|
-
if (refSchema.$ref) {
|
|
14566
|
+
if (refSchema.$ref && refSeen.def) {
|
|
14343
14567
|
for (const key in schema2) {
|
|
14344
14568
|
if (key === "$ref" || key === "allOf")
|
|
14345
14569
|
continue;
|
|
@@ -17049,10 +17273,12 @@ var BackgroundTaskConfigSchema = exports_external.object({
|
|
|
17049
17273
|
var FailoverConfigSchema = exports_external.object({
|
|
17050
17274
|
enabled: exports_external.boolean().default(true),
|
|
17051
17275
|
timeoutMs: exports_external.number().min(0).default(15000),
|
|
17276
|
+
retryDelayMs: exports_external.number().min(0).default(500),
|
|
17052
17277
|
chains: FallbackChainsSchema.default({})
|
|
17053
17278
|
});
|
|
17054
17279
|
var PluginConfigSchema = exports_external.object({
|
|
17055
17280
|
preset: exports_external.string().optional(),
|
|
17281
|
+
setDefaultAgent: exports_external.boolean().optional(),
|
|
17056
17282
|
scoringEngineVersion: exports_external.enum(["v1", "v2-shadow", "v2"]).optional(),
|
|
17057
17283
|
balanceProviderUsage: exports_external.boolean().optional(),
|
|
17058
17284
|
manualPlan: ManualPlanSchema.optional(),
|
|
@@ -17066,9 +17292,6 @@ var PluginConfigSchema = exports_external.object({
|
|
|
17066
17292
|
|
|
17067
17293
|
// src/config/loader.ts
|
|
17068
17294
|
var PROMPTS_DIR_NAME = "oh-my-opencode-slim";
|
|
17069
|
-
function getUserConfigDir() {
|
|
17070
|
-
return process.env.XDG_CONFIG_HOME || path.join(os.homedir(), ".config");
|
|
17071
|
-
}
|
|
17072
17295
|
function loadConfigFromPath(configPath) {
|
|
17073
17296
|
try {
|
|
17074
17297
|
const content = fs.readFileSync(configPath, "utf-8");
|
|
@@ -17116,7 +17339,7 @@ function deepMerge(base, override) {
|
|
|
17116
17339
|
return result;
|
|
17117
17340
|
}
|
|
17118
17341
|
function loadPluginConfig(directory) {
|
|
17119
|
-
const userConfigBasePath = path.join(
|
|
17342
|
+
const userConfigBasePath = path.join(getConfigDir(), "oh-my-opencode-slim");
|
|
17120
17343
|
const projectConfigBasePath = path.join(directory, ".opencode", "oh-my-opencode-slim");
|
|
17121
17344
|
const userConfigPath = findConfigPath(userConfigBasePath);
|
|
17122
17345
|
const projectConfigPath = findConfigPath(projectConfigBasePath);
|
|
@@ -17149,7 +17372,7 @@ function loadPluginConfig(directory) {
|
|
|
17149
17372
|
}
|
|
17150
17373
|
function loadAgentPrompt(agentName, preset) {
|
|
17151
17374
|
const presetDirName = preset && /^[a-zA-Z0-9_-]+$/.test(preset) ? preset : undefined;
|
|
17152
|
-
const promptsDir = path.join(
|
|
17375
|
+
const promptsDir = path.join(getConfigDir(), PROMPTS_DIR_NAME);
|
|
17153
17376
|
const promptSearchDirs = presetDirName ? [path.join(promptsDir, presetDirName), promptsDir] : [promptsDir];
|
|
17154
17377
|
const result = {};
|
|
17155
17378
|
const readFirstPrompt = (fileName, errorPrefix) => {
|
|
@@ -17700,9 +17923,9 @@ function getAgentConfigs(config2) {
|
|
|
17700
17923
|
|
|
17701
17924
|
// src/utils/logger.ts
|
|
17702
17925
|
import * as fs2 from "fs";
|
|
17703
|
-
import * as
|
|
17926
|
+
import * as os from "os";
|
|
17704
17927
|
import * as path2 from "path";
|
|
17705
|
-
var logFile = path2.join(
|
|
17928
|
+
var logFile = path2.join(os.tmpdir(), "oh-my-opencode-slim.log");
|
|
17706
17929
|
function log(message, data) {
|
|
17707
17930
|
try {
|
|
17708
17931
|
const timestamp = new Date().toISOString();
|
|
@@ -18191,14 +18414,23 @@ class BackgroundTaskManager {
|
|
|
18191
18414
|
await this.client.session.prompt(args);
|
|
18192
18415
|
return;
|
|
18193
18416
|
}
|
|
18194
|
-
|
|
18195
|
-
|
|
18196
|
-
|
|
18197
|
-
|
|
18198
|
-
|
|
18199
|
-
|
|
18200
|
-
|
|
18201
|
-
|
|
18417
|
+
const sessionId = args.path.id;
|
|
18418
|
+
let timer;
|
|
18419
|
+
try {
|
|
18420
|
+
const promptPromise = this.client.session.prompt(args);
|
|
18421
|
+
promptPromise.catch(() => {});
|
|
18422
|
+
await Promise.race([
|
|
18423
|
+
promptPromise,
|
|
18424
|
+
new Promise((_, reject) => {
|
|
18425
|
+
timer = setTimeout(() => {
|
|
18426
|
+
this.client.session.abort({ path: { id: sessionId } }).catch(() => {});
|
|
18427
|
+
reject(new Error(`Prompt timed out after ${timeoutMs}ms`));
|
|
18428
|
+
}, timeoutMs);
|
|
18429
|
+
})
|
|
18430
|
+
]);
|
|
18431
|
+
} finally {
|
|
18432
|
+
clearTimeout(timer);
|
|
18433
|
+
}
|
|
18202
18434
|
}
|
|
18203
18435
|
calculateToolPermissions(agentName) {
|
|
18204
18436
|
const allowedSubagents = this.getSubagentRules(agentName);
|
|
@@ -18242,11 +18474,15 @@ class BackgroundTaskManager {
|
|
|
18242
18474
|
});
|
|
18243
18475
|
const fallbackEnabled = this.config?.fallback?.enabled ?? true;
|
|
18244
18476
|
const timeoutMs = fallbackEnabled ? this.config?.fallback?.timeoutMs ?? FALLBACK_FAILOVER_TIMEOUT_MS : 0;
|
|
18477
|
+
const retryDelayMs = this.config?.fallback?.retryDelayMs ?? 500;
|
|
18245
18478
|
const chain = fallbackEnabled ? this.resolveFallbackChain(task.agent) : [];
|
|
18246
18479
|
const attemptModels = chain.length > 0 ? chain : [undefined];
|
|
18247
18480
|
const errors3 = [];
|
|
18248
18481
|
let succeeded = false;
|
|
18249
|
-
|
|
18482
|
+
const sessionId = session.data.id;
|
|
18483
|
+
for (let i = 0;i < attemptModels.length; i++) {
|
|
18484
|
+
const model = attemptModels[i];
|
|
18485
|
+
const modelLabel = model ?? "default-model";
|
|
18250
18486
|
try {
|
|
18251
18487
|
const body = {
|
|
18252
18488
|
...basePromptBody,
|
|
@@ -18259,8 +18495,11 @@ class BackgroundTaskManager {
|
|
|
18259
18495
|
}
|
|
18260
18496
|
body.model = ref;
|
|
18261
18497
|
}
|
|
18498
|
+
if (i > 0) {
|
|
18499
|
+
log(`[background-manager] fallback attempt ${i + 1}/${attemptModels.length}: ${modelLabel}`, { taskId: task.id });
|
|
18500
|
+
}
|
|
18262
18501
|
await this.promptWithTimeout({
|
|
18263
|
-
path: { id:
|
|
18502
|
+
path: { id: sessionId },
|
|
18264
18503
|
body,
|
|
18265
18504
|
query: promptQuery
|
|
18266
18505
|
}, timeoutMs);
|
|
@@ -18268,10 +18507,17 @@ class BackgroundTaskManager {
|
|
|
18268
18507
|
break;
|
|
18269
18508
|
} catch (error48) {
|
|
18270
18509
|
const msg = error48 instanceof Error ? error48.message : String(error48);
|
|
18271
|
-
|
|
18272
|
-
|
|
18273
|
-
|
|
18274
|
-
|
|
18510
|
+
errors3.push(`${modelLabel}: ${msg}`);
|
|
18511
|
+
log(`[background-manager] model failed: ${modelLabel} \u2014 ${msg}`, {
|
|
18512
|
+
taskId: task.id
|
|
18513
|
+
});
|
|
18514
|
+
if (i < attemptModels.length - 1) {
|
|
18515
|
+
try {
|
|
18516
|
+
await this.client.session.abort({
|
|
18517
|
+
path: { id: sessionId }
|
|
18518
|
+
});
|
|
18519
|
+
await new Promise((r) => setTimeout(r, retryDelayMs));
|
|
18520
|
+
} catch {}
|
|
18275
18521
|
}
|
|
18276
18522
|
}
|
|
18277
18523
|
}
|
|
@@ -18639,19 +18885,17 @@ class TmuxSessionManager {
|
|
|
18639
18885
|
// src/hooks/auto-update-checker/cache.ts
|
|
18640
18886
|
import * as fs3 from "fs";
|
|
18641
18887
|
import * as path4 from "path";
|
|
18642
|
-
// src/cli/dynamic-model-selection.ts
|
|
18643
|
-
var FREE_BIASED_PROVIDERS = new Set(["opencode"]);
|
|
18644
18888
|
// src/hooks/auto-update-checker/constants.ts
|
|
18645
|
-
import * as
|
|
18889
|
+
import * as os2 from "os";
|
|
18646
18890
|
import * as path3 from "path";
|
|
18647
18891
|
var PACKAGE_NAME = "oh-my-opencode-slim";
|
|
18648
18892
|
var NPM_REGISTRY_URL = `https://registry.npmjs.org/-/package/${PACKAGE_NAME}/dist-tags`;
|
|
18649
18893
|
var NPM_FETCH_TIMEOUT = 5000;
|
|
18650
18894
|
function getCacheDir() {
|
|
18651
18895
|
if (process.platform === "win32") {
|
|
18652
|
-
return path3.join(process.env.LOCALAPPDATA ??
|
|
18896
|
+
return path3.join(process.env.LOCALAPPDATA ?? os2.homedir(), "opencode");
|
|
18653
18897
|
}
|
|
18654
|
-
return path3.join(
|
|
18898
|
+
return path3.join(os2.homedir(), ".cache", "opencode");
|
|
18655
18899
|
}
|
|
18656
18900
|
var CACHE_DIR = getCacheDir();
|
|
18657
18901
|
var INSTALLED_PACKAGE_JSON = path3.join(CACHE_DIR, "node_modules", PACKAGE_NAME, "package.json");
|
|
@@ -19188,6 +19432,216 @@ ${buildRetryGuidance(detected)}`;
|
|
|
19188
19432
|
}
|
|
19189
19433
|
};
|
|
19190
19434
|
}
|
|
19435
|
+
// src/hooks/foreground-fallback/index.ts
|
|
19436
|
+
var RATE_LIMIT_PATTERNS = [
|
|
19437
|
+
/\b429\b/,
|
|
19438
|
+
/rate.?limit/i,
|
|
19439
|
+
/too many requests/i,
|
|
19440
|
+
/quota.?exceeded/i,
|
|
19441
|
+
/usage.?exceeded/i,
|
|
19442
|
+
/usage limit/i,
|
|
19443
|
+
/overloaded/i,
|
|
19444
|
+
/resource.?exhausted/i,
|
|
19445
|
+
/insufficient.?quota/i,
|
|
19446
|
+
/high concurrency/i,
|
|
19447
|
+
/reduce concurrency/i
|
|
19448
|
+
];
|
|
19449
|
+
function isRateLimitError(error48) {
|
|
19450
|
+
if (!error48 || typeof error48 !== "object")
|
|
19451
|
+
return false;
|
|
19452
|
+
const err = error48;
|
|
19453
|
+
const text = [
|
|
19454
|
+
err.message ?? "",
|
|
19455
|
+
String(err.data?.statusCode ?? ""),
|
|
19456
|
+
err.data?.message ?? "",
|
|
19457
|
+
err.data?.responseBody ?? ""
|
|
19458
|
+
].join(" ");
|
|
19459
|
+
return RATE_LIMIT_PATTERNS.some((p) => p.test(text));
|
|
19460
|
+
}
|
|
19461
|
+
function parseModel(model) {
|
|
19462
|
+
const slash = model.indexOf("/");
|
|
19463
|
+
if (slash <= 0 || slash >= model.length - 1)
|
|
19464
|
+
return null;
|
|
19465
|
+
return { providerID: model.slice(0, slash), modelID: model.slice(slash + 1) };
|
|
19466
|
+
}
|
|
19467
|
+
var DEDUP_WINDOW_MS = 5000;
|
|
19468
|
+
|
|
19469
|
+
class ForegroundFallbackManager {
|
|
19470
|
+
client;
|
|
19471
|
+
chains;
|
|
19472
|
+
enabled;
|
|
19473
|
+
sessionModel = new Map;
|
|
19474
|
+
sessionAgent = new Map;
|
|
19475
|
+
sessionTried = new Map;
|
|
19476
|
+
inProgress = new Set;
|
|
19477
|
+
lastTrigger = new Map;
|
|
19478
|
+
constructor(client, chains, enabled) {
|
|
19479
|
+
this.client = client;
|
|
19480
|
+
this.chains = chains;
|
|
19481
|
+
this.enabled = enabled;
|
|
19482
|
+
}
|
|
19483
|
+
async handleEvent(rawEvent) {
|
|
19484
|
+
if (!this.enabled)
|
|
19485
|
+
return;
|
|
19486
|
+
const event = rawEvent;
|
|
19487
|
+
if (!event?.type)
|
|
19488
|
+
return;
|
|
19489
|
+
switch (event.type) {
|
|
19490
|
+
case "message.updated": {
|
|
19491
|
+
const info = event.properties?.info;
|
|
19492
|
+
if (!info)
|
|
19493
|
+
break;
|
|
19494
|
+
const sessionID = info.sessionID;
|
|
19495
|
+
if (!sessionID)
|
|
19496
|
+
break;
|
|
19497
|
+
if (typeof info.agent === "string") {
|
|
19498
|
+
this.sessionAgent.set(sessionID, info.agent);
|
|
19499
|
+
}
|
|
19500
|
+
if (typeof info.providerID === "string" && typeof info.modelID === "string") {
|
|
19501
|
+
this.sessionModel.set(sessionID, `${info.providerID}/${info.modelID}`);
|
|
19502
|
+
}
|
|
19503
|
+
if (info.error && isRateLimitError(info.error)) {
|
|
19504
|
+
await this.tryFallback(sessionID);
|
|
19505
|
+
}
|
|
19506
|
+
break;
|
|
19507
|
+
}
|
|
19508
|
+
case "session.error": {
|
|
19509
|
+
const props = event.properties;
|
|
19510
|
+
if (props?.sessionID && props.error && isRateLimitError(props.error)) {
|
|
19511
|
+
await this.tryFallback(props.sessionID);
|
|
19512
|
+
}
|
|
19513
|
+
break;
|
|
19514
|
+
}
|
|
19515
|
+
case "session.status": {
|
|
19516
|
+
const props = event.properties;
|
|
19517
|
+
if (!props?.sessionID || props.status?.type !== "retry")
|
|
19518
|
+
break;
|
|
19519
|
+
const msg = props.status.message?.toLowerCase() ?? "";
|
|
19520
|
+
if (msg.includes("rate limit") || msg.includes("usage limit") || msg.includes("usage exceeded") || msg.includes("quota exceeded") || msg.includes("high concurrency") || msg.includes("reduce concurrency")) {
|
|
19521
|
+
await this.tryFallback(props.sessionID);
|
|
19522
|
+
}
|
|
19523
|
+
break;
|
|
19524
|
+
}
|
|
19525
|
+
case "subagent.session.created": {
|
|
19526
|
+
const props = event.properties;
|
|
19527
|
+
if (props?.sessionID && typeof props.agentName === "string") {
|
|
19528
|
+
this.sessionAgent.set(props.sessionID, props.agentName);
|
|
19529
|
+
}
|
|
19530
|
+
break;
|
|
19531
|
+
}
|
|
19532
|
+
case "session.deleted": {
|
|
19533
|
+
const props = event.properties;
|
|
19534
|
+
const id = props?.info?.id ?? props?.sessionID;
|
|
19535
|
+
if (id) {
|
|
19536
|
+
this.sessionModel.delete(id);
|
|
19537
|
+
this.sessionAgent.delete(id);
|
|
19538
|
+
this.sessionTried.delete(id);
|
|
19539
|
+
this.inProgress.delete(id);
|
|
19540
|
+
this.lastTrigger.delete(id);
|
|
19541
|
+
}
|
|
19542
|
+
break;
|
|
19543
|
+
}
|
|
19544
|
+
}
|
|
19545
|
+
}
|
|
19546
|
+
async tryFallback(sessionID) {
|
|
19547
|
+
if (!sessionID)
|
|
19548
|
+
return;
|
|
19549
|
+
if (this.inProgress.has(sessionID))
|
|
19550
|
+
return;
|
|
19551
|
+
const now = Date.now();
|
|
19552
|
+
if (now - (this.lastTrigger.get(sessionID) ?? 0) < DEDUP_WINDOW_MS)
|
|
19553
|
+
return;
|
|
19554
|
+
this.lastTrigger.set(sessionID, now);
|
|
19555
|
+
this.inProgress.add(sessionID);
|
|
19556
|
+
try {
|
|
19557
|
+
const currentModel = this.sessionModel.get(sessionID);
|
|
19558
|
+
const agentName = this.sessionAgent.get(sessionID);
|
|
19559
|
+
const chain = this.resolveChain(agentName, currentModel);
|
|
19560
|
+
if (!chain.length) {
|
|
19561
|
+
log("[foreground-fallback] no chain configured", { sessionID, agentName });
|
|
19562
|
+
return;
|
|
19563
|
+
}
|
|
19564
|
+
if (!this.sessionTried.has(sessionID)) {
|
|
19565
|
+
this.sessionTried.set(sessionID, new Set);
|
|
19566
|
+
}
|
|
19567
|
+
const tried = this.sessionTried.get(sessionID);
|
|
19568
|
+
if (currentModel)
|
|
19569
|
+
tried.add(currentModel);
|
|
19570
|
+
const nextModel = chain.find((m) => !tried.has(m));
|
|
19571
|
+
if (!nextModel) {
|
|
19572
|
+
log("[foreground-fallback] fallback chain exhausted", {
|
|
19573
|
+
sessionID,
|
|
19574
|
+
agentName,
|
|
19575
|
+
tried: [...tried]
|
|
19576
|
+
});
|
|
19577
|
+
return;
|
|
19578
|
+
}
|
|
19579
|
+
tried.add(nextModel);
|
|
19580
|
+
const ref = parseModel(nextModel);
|
|
19581
|
+
if (!ref) {
|
|
19582
|
+
log("[foreground-fallback] invalid model format", {
|
|
19583
|
+
sessionID,
|
|
19584
|
+
nextModel
|
|
19585
|
+
});
|
|
19586
|
+
return;
|
|
19587
|
+
}
|
|
19588
|
+
const result = await this.client.session.messages({
|
|
19589
|
+
path: { id: sessionID }
|
|
19590
|
+
});
|
|
19591
|
+
const messages = result.data ?? [];
|
|
19592
|
+
const lastUser = [...messages].reverse().find((m) => m.info.role === "user");
|
|
19593
|
+
if (!lastUser) {
|
|
19594
|
+
log("[foreground-fallback] no user message found", { sessionID });
|
|
19595
|
+
return;
|
|
19596
|
+
}
|
|
19597
|
+
try {
|
|
19598
|
+
await this.client.session.abort({ path: { id: sessionID } });
|
|
19599
|
+
} catch {}
|
|
19600
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
19601
|
+
const sessionClient = this.client.session;
|
|
19602
|
+
await sessionClient.promptAsync({
|
|
19603
|
+
path: { id: sessionID },
|
|
19604
|
+
body: { parts: lastUser.parts, model: ref }
|
|
19605
|
+
});
|
|
19606
|
+
this.sessionModel.set(sessionID, nextModel);
|
|
19607
|
+
log("[foreground-fallback] switched to fallback model", {
|
|
19608
|
+
sessionID,
|
|
19609
|
+
agentName,
|
|
19610
|
+
from: currentModel,
|
|
19611
|
+
to: nextModel
|
|
19612
|
+
});
|
|
19613
|
+
} catch (err) {
|
|
19614
|
+
log("[foreground-fallback] fallback attempt failed", {
|
|
19615
|
+
sessionID,
|
|
19616
|
+
error: err instanceof Error ? err.message : String(err)
|
|
19617
|
+
});
|
|
19618
|
+
} finally {
|
|
19619
|
+
this.inProgress.delete(sessionID);
|
|
19620
|
+
}
|
|
19621
|
+
}
|
|
19622
|
+
resolveChain(agentName, currentModel) {
|
|
19623
|
+
if (agentName) {
|
|
19624
|
+
return this.chains[agentName] ?? [];
|
|
19625
|
+
}
|
|
19626
|
+
if (currentModel) {
|
|
19627
|
+
for (const chain of Object.values(this.chains)) {
|
|
19628
|
+
if (chain.includes(currentModel))
|
|
19629
|
+
return chain;
|
|
19630
|
+
}
|
|
19631
|
+
}
|
|
19632
|
+
const all = [];
|
|
19633
|
+
const seen = new Set;
|
|
19634
|
+
for (const chain of Object.values(this.chains)) {
|
|
19635
|
+
for (const m of chain) {
|
|
19636
|
+
if (!seen.has(m)) {
|
|
19637
|
+
seen.add(m);
|
|
19638
|
+
all.push(m);
|
|
19639
|
+
}
|
|
19640
|
+
}
|
|
19641
|
+
}
|
|
19642
|
+
return all;
|
|
19643
|
+
}
|
|
19644
|
+
}
|
|
19191
19645
|
// src/hooks/json-error-recovery/hook.ts
|
|
19192
19646
|
var JSON_ERROR_TOOL_EXCLUDE_LIST = [
|
|
19193
19647
|
"bash",
|
|
@@ -31658,12 +32112,12 @@ var {spawn: spawn3 } = globalThis.Bun;
|
|
|
31658
32112
|
// src/tools/ast-grep/constants.ts
|
|
31659
32113
|
import { existsSync as existsSync5, statSync as statSync2 } from "fs";
|
|
31660
32114
|
import { createRequire as createRequire2 } from "module";
|
|
31661
|
-
import { dirname as
|
|
32115
|
+
import { dirname as dirname3, join as join8 } from "path";
|
|
31662
32116
|
|
|
31663
32117
|
// src/tools/ast-grep/downloader.ts
|
|
31664
32118
|
import { chmodSync, existsSync as existsSync4, mkdirSync, unlinkSync } from "fs";
|
|
31665
32119
|
import { createRequire } from "module";
|
|
31666
|
-
import { homedir as
|
|
32120
|
+
import { homedir as homedir3 } from "os";
|
|
31667
32121
|
import { join as join7 } from "path";
|
|
31668
32122
|
var REPO = "ast-grep/ast-grep";
|
|
31669
32123
|
var DEFAULT_VERSION = "0.40.0";
|
|
@@ -31688,11 +32142,11 @@ var PLATFORM_MAP = {
|
|
|
31688
32142
|
function getCacheDir2() {
|
|
31689
32143
|
if (process.platform === "win32") {
|
|
31690
32144
|
const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
|
|
31691
|
-
const base2 = localAppData || join7(
|
|
32145
|
+
const base2 = localAppData || join7(homedir3(), "AppData", "Local");
|
|
31692
32146
|
return join7(base2, "oh-my-opencode-slim", "bin");
|
|
31693
32147
|
}
|
|
31694
32148
|
const xdgCache = process.env.XDG_CACHE_HOME;
|
|
31695
|
-
const base = xdgCache || join7(
|
|
32149
|
+
const base = xdgCache || join7(homedir3(), ".cache");
|
|
31696
32150
|
return join7(base, "oh-my-opencode-slim", "bin");
|
|
31697
32151
|
}
|
|
31698
32152
|
function getBinaryName() {
|
|
@@ -31715,8 +32169,8 @@ async function downloadAstGrep(version3 = DEFAULT_VERSION) {
|
|
|
31715
32169
|
if (existsSync4(binaryPath)) {
|
|
31716
32170
|
return binaryPath;
|
|
31717
32171
|
}
|
|
31718
|
-
const { arch, os:
|
|
31719
|
-
const assetName = `app-${arch}-${
|
|
32172
|
+
const { arch, os: os3 } = platformInfo;
|
|
32173
|
+
const assetName = `app-${arch}-${os3}.zip`;
|
|
31720
32174
|
const downloadUrl = `https://github.com/${REPO}/releases/download/${version3}/${assetName}`;
|
|
31721
32175
|
console.log(`[oh-my-opencode-slim] Downloading ast-grep binary...`);
|
|
31722
32176
|
try {
|
|
@@ -31815,7 +32269,7 @@ function findSgCliPathSync() {
|
|
|
31815
32269
|
try {
|
|
31816
32270
|
const require2 = createRequire2(import.meta.url);
|
|
31817
32271
|
const cliPkgPath = require2.resolve("@ast-grep/cli/package.json");
|
|
31818
|
-
const cliDir =
|
|
32272
|
+
const cliDir = dirname3(cliPkgPath);
|
|
31819
32273
|
const sgPath = join8(cliDir, binaryName);
|
|
31820
32274
|
if (existsSync5(sgPath) && isValidBinary(sgPath)) {
|
|
31821
32275
|
return sgPath;
|
|
@@ -31826,7 +32280,7 @@ function findSgCliPathSync() {
|
|
|
31826
32280
|
try {
|
|
31827
32281
|
const require2 = createRequire2(import.meta.url);
|
|
31828
32282
|
const pkgPath = require2.resolve(`${platformPkg}/package.json`);
|
|
31829
|
-
const pkgDir =
|
|
32283
|
+
const pkgDir = dirname3(pkgPath);
|
|
31830
32284
|
const astGrepName = process.platform === "win32" ? "ast-grep.exe" : "ast-grep";
|
|
31831
32285
|
const binaryPath = join8(pkgDir, astGrepName);
|
|
31832
32286
|
if (existsSync5(binaryPath) && isValidBinary(binaryPath)) {
|
|
@@ -32316,7 +32770,7 @@ var {spawn: spawn4 } = globalThis.Bun;
|
|
|
32316
32770
|
// src/tools/grep/constants.ts
|
|
32317
32771
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
32318
32772
|
import { existsSync as existsSync8 } from "fs";
|
|
32319
|
-
import { dirname as
|
|
32773
|
+
import { dirname as dirname4, join as join10 } from "path";
|
|
32320
32774
|
|
|
32321
32775
|
// src/tools/grep/downloader.ts
|
|
32322
32776
|
import {
|
|
@@ -32361,7 +32815,7 @@ function getDataDir() {
|
|
|
32361
32815
|
}
|
|
32362
32816
|
function getOpenCodeBundledRg() {
|
|
32363
32817
|
const execPath = process.execPath;
|
|
32364
|
-
const execDir =
|
|
32818
|
+
const execDir = dirname4(execPath);
|
|
32365
32819
|
const isWindows = process.platform === "win32";
|
|
32366
32820
|
const rgName = isWindows ? "rg.exe" : "rg";
|
|
32367
32821
|
const candidates = [
|
|
@@ -32634,17 +33088,47 @@ var grep = tool({
|
|
|
32634
33088
|
// src/tools/lsp/client.ts
|
|
32635
33089
|
var import_node = __toESM(require_main(), 1);
|
|
32636
33090
|
import { readFileSync as readFileSync4 } from "fs";
|
|
32637
|
-
import { extname, resolve } from "path";
|
|
33091
|
+
import { extname, resolve as resolve2 } from "path";
|
|
32638
33092
|
import { Readable, Writable } from "stream";
|
|
32639
33093
|
import { pathToFileURL } from "url";
|
|
32640
33094
|
var {spawn: spawn5 } = globalThis.Bun;
|
|
32641
33095
|
|
|
32642
33096
|
// src/tools/lsp/config.ts
|
|
32643
|
-
|
|
32644
|
-
import {
|
|
33097
|
+
var import_which = __toESM(require_lib(), 1);
|
|
33098
|
+
import { existsSync as existsSync10 } from "fs";
|
|
33099
|
+
import { homedir as homedir4 } from "os";
|
|
32645
33100
|
import { join as join11 } from "path";
|
|
32646
33101
|
|
|
33102
|
+
// src/tools/lsp/config-store.ts
|
|
33103
|
+
var userConfig = new Map;
|
|
33104
|
+
function setUserLspConfig(config3) {
|
|
33105
|
+
userConfig.clear();
|
|
33106
|
+
if (config3) {
|
|
33107
|
+
for (const [id, server] of Object.entries(config3)) {
|
|
33108
|
+
if (server && typeof server === "object") {
|
|
33109
|
+
const s = server;
|
|
33110
|
+
userConfig.set(id, {
|
|
33111
|
+
id,
|
|
33112
|
+
command: s.command,
|
|
33113
|
+
extensions: s.extensions,
|
|
33114
|
+
disabled: s.disabled,
|
|
33115
|
+
env: s.env,
|
|
33116
|
+
initialization: s.initialization
|
|
33117
|
+
});
|
|
33118
|
+
}
|
|
33119
|
+
}
|
|
33120
|
+
}
|
|
33121
|
+
}
|
|
33122
|
+
function getAllUserLspConfigs() {
|
|
33123
|
+
return new Map(userConfig);
|
|
33124
|
+
}
|
|
33125
|
+
function hasUserLspConfig() {
|
|
33126
|
+
return userConfig.size > 0;
|
|
33127
|
+
}
|
|
33128
|
+
|
|
32647
33129
|
// src/tools/lsp/constants.ts
|
|
33130
|
+
import { existsSync as existsSync9, readdirSync as readdirSync2, statSync as statSync3 } from "fs";
|
|
33131
|
+
import { dirname as dirname5, resolve } from "path";
|
|
32648
33132
|
var SEVERITY_MAP = {
|
|
32649
33133
|
1: "error",
|
|
32650
33134
|
2: "warning",
|
|
@@ -32653,22 +33137,76 @@ var SEVERITY_MAP = {
|
|
|
32653
33137
|
};
|
|
32654
33138
|
var DEFAULT_MAX_REFERENCES = 200;
|
|
32655
33139
|
var DEFAULT_MAX_DIAGNOSTICS = 200;
|
|
33140
|
+
var LOCK_FILE_PATTERNS = [
|
|
33141
|
+
"package-lock.json",
|
|
33142
|
+
"bun.lockb",
|
|
33143
|
+
"bun.lock",
|
|
33144
|
+
"pnpm-lock.yaml",
|
|
33145
|
+
"yarn.lock"
|
|
33146
|
+
];
|
|
33147
|
+
function* walkUpDirectories(start, stop) {
|
|
33148
|
+
let dir = resolve(start);
|
|
33149
|
+
try {
|
|
33150
|
+
if (!statSync3(dir).isDirectory()) {
|
|
33151
|
+
dir = dirname5(dir);
|
|
33152
|
+
}
|
|
33153
|
+
} catch {
|
|
33154
|
+
dir = dirname5(dir);
|
|
33155
|
+
}
|
|
33156
|
+
let prevDir = "";
|
|
33157
|
+
while (dir !== prevDir && dir !== "/") {
|
|
33158
|
+
yield dir;
|
|
33159
|
+
prevDir = dir;
|
|
33160
|
+
if (dir === stop)
|
|
33161
|
+
break;
|
|
33162
|
+
dir = dirname5(dir);
|
|
33163
|
+
}
|
|
33164
|
+
}
|
|
33165
|
+
function NearestRoot(includePatterns, excludePatterns) {
|
|
33166
|
+
return (file3) => {
|
|
33167
|
+
const cwd = process.cwd();
|
|
33168
|
+
if (excludePatterns) {
|
|
33169
|
+
for (const dir of walkUpDirectories(file3, cwd)) {
|
|
33170
|
+
for (const pattern of excludePatterns) {
|
|
33171
|
+
if (existsSync9(`${dir}/${pattern}`)) {
|
|
33172
|
+
return;
|
|
33173
|
+
}
|
|
33174
|
+
}
|
|
33175
|
+
}
|
|
33176
|
+
}
|
|
33177
|
+
for (const dir of walkUpDirectories(file3, cwd)) {
|
|
33178
|
+
for (const pattern of includePatterns) {
|
|
33179
|
+
if (pattern.includes("*")) {
|
|
33180
|
+
try {
|
|
33181
|
+
const entries = readdirSync2(dir);
|
|
33182
|
+
const regex = new RegExp(`^${pattern.replace(/\./g, "\\.").replace(/\*/g, ".*")}$`);
|
|
33183
|
+
if (entries.some((entry) => regex.test(entry))) {
|
|
33184
|
+
return dir;
|
|
33185
|
+
}
|
|
33186
|
+
} catch {}
|
|
33187
|
+
} else if (existsSync9(`${dir}/${pattern}`)) {
|
|
33188
|
+
return dir;
|
|
33189
|
+
}
|
|
33190
|
+
}
|
|
33191
|
+
}
|
|
33192
|
+
return;
|
|
33193
|
+
};
|
|
33194
|
+
}
|
|
32656
33195
|
var BUILTIN_SERVERS = {
|
|
33196
|
+
deno: {
|
|
33197
|
+
command: ["deno", "lsp"],
|
|
33198
|
+
extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs"],
|
|
33199
|
+
root: NearestRoot(["deno.json", "deno.jsonc"])
|
|
33200
|
+
},
|
|
32657
33201
|
typescript: {
|
|
32658
33202
|
command: ["typescript-language-server", "--stdio"],
|
|
32659
|
-
extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"]
|
|
33203
|
+
extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"],
|
|
33204
|
+
root: NearestRoot(LOCK_FILE_PATTERNS, ["deno.json", "deno.jsonc"])
|
|
32660
33205
|
},
|
|
32661
33206
|
vue: {
|
|
32662
33207
|
command: ["vue-language-server", "--stdio"],
|
|
32663
|
-
extensions: [".vue"]
|
|
32664
|
-
|
|
32665
|
-
svelte: {
|
|
32666
|
-
command: ["svelteserver", "--stdio"],
|
|
32667
|
-
extensions: [".svelte"]
|
|
32668
|
-
},
|
|
32669
|
-
astro: {
|
|
32670
|
-
command: ["astro-ls", "--stdio"],
|
|
32671
|
-
extensions: [".astro"]
|
|
33208
|
+
extensions: [".vue"],
|
|
33209
|
+
root: NearestRoot(LOCK_FILE_PATTERNS)
|
|
32672
33210
|
},
|
|
32673
33211
|
eslint: {
|
|
32674
33212
|
command: ["vscode-eslint-language-server", "--stdio"],
|
|
@@ -32679,54 +33217,316 @@ var BUILTIN_SERVERS = {
|
|
|
32679
33217
|
".jsx",
|
|
32680
33218
|
".mjs",
|
|
32681
33219
|
".cjs",
|
|
33220
|
+
".mts",
|
|
33221
|
+
".cts",
|
|
33222
|
+
".vue"
|
|
33223
|
+
],
|
|
33224
|
+
root: NearestRoot(LOCK_FILE_PATTERNS)
|
|
33225
|
+
},
|
|
33226
|
+
oxlint: {
|
|
33227
|
+
command: ["oxlint", "--lsp"],
|
|
33228
|
+
extensions: [
|
|
33229
|
+
".ts",
|
|
33230
|
+
".tsx",
|
|
33231
|
+
".js",
|
|
33232
|
+
".jsx",
|
|
33233
|
+
".mjs",
|
|
33234
|
+
".cjs",
|
|
33235
|
+
".mts",
|
|
33236
|
+
".cts",
|
|
32682
33237
|
".vue",
|
|
33238
|
+
".astro",
|
|
32683
33239
|
".svelte"
|
|
32684
|
-
]
|
|
33240
|
+
],
|
|
33241
|
+
root: NearestRoot([
|
|
33242
|
+
".oxlintrc.json",
|
|
33243
|
+
...LOCK_FILE_PATTERNS,
|
|
33244
|
+
"package.json"
|
|
33245
|
+
])
|
|
32685
33246
|
},
|
|
32686
|
-
|
|
32687
|
-
command: ["
|
|
32688
|
-
extensions: [
|
|
33247
|
+
biome: {
|
|
33248
|
+
command: ["biome", "lsp-proxy", "--stdio"],
|
|
33249
|
+
extensions: [
|
|
33250
|
+
".ts",
|
|
33251
|
+
".tsx",
|
|
33252
|
+
".js",
|
|
33253
|
+
".jsx",
|
|
33254
|
+
".mjs",
|
|
33255
|
+
".cjs",
|
|
33256
|
+
".mts",
|
|
33257
|
+
".cts",
|
|
33258
|
+
".json",
|
|
33259
|
+
".jsonc",
|
|
33260
|
+
".vue",
|
|
33261
|
+
".astro",
|
|
33262
|
+
".svelte",
|
|
33263
|
+
".css",
|
|
33264
|
+
".graphql",
|
|
33265
|
+
".gql",
|
|
33266
|
+
".html"
|
|
33267
|
+
],
|
|
33268
|
+
root: NearestRoot(["biome.json", "biome.jsonc", ...LOCK_FILE_PATTERNS])
|
|
32689
33269
|
},
|
|
32690
33270
|
gopls: {
|
|
32691
33271
|
command: ["gopls"],
|
|
32692
|
-
extensions: [".go"]
|
|
33272
|
+
extensions: [".go"],
|
|
33273
|
+
root: NearestRoot(["go.work", "go.mod", "go.sum"])
|
|
32693
33274
|
},
|
|
32694
|
-
|
|
32695
|
-
command: ["
|
|
32696
|
-
extensions: [".
|
|
33275
|
+
ruby_lsp: {
|
|
33276
|
+
command: ["rubocop", "--lsp"],
|
|
33277
|
+
extensions: [".rb", ".rake", ".gemspec", ".ru"],
|
|
33278
|
+
root: NearestRoot(["Gemfile"])
|
|
32697
33279
|
},
|
|
32698
|
-
|
|
32699
|
-
command: ["
|
|
32700
|
-
extensions: [".py", ".pyi"]
|
|
33280
|
+
ty: {
|
|
33281
|
+
command: ["ty", "server"],
|
|
33282
|
+
extensions: [".py", ".pyi"],
|
|
33283
|
+
root: NearestRoot([
|
|
33284
|
+
"pyproject.toml",
|
|
33285
|
+
"ty.toml",
|
|
33286
|
+
"setup.py",
|
|
33287
|
+
"setup.cfg",
|
|
33288
|
+
"requirements.txt",
|
|
33289
|
+
"Pipfile",
|
|
33290
|
+
"pyrightconfig.json"
|
|
33291
|
+
])
|
|
32701
33292
|
},
|
|
32702
33293
|
pyright: {
|
|
32703
33294
|
command: ["pyright-langserver", "--stdio"],
|
|
32704
|
-
extensions: [".py", ".pyi"]
|
|
33295
|
+
extensions: [".py", ".pyi"],
|
|
33296
|
+
root: NearestRoot([
|
|
33297
|
+
"pyproject.toml",
|
|
33298
|
+
"setup.py",
|
|
33299
|
+
"setup.cfg",
|
|
33300
|
+
"requirements.txt",
|
|
33301
|
+
"Pipfile",
|
|
33302
|
+
"pyrightconfig.json"
|
|
33303
|
+
])
|
|
32705
33304
|
},
|
|
32706
|
-
|
|
32707
|
-
command: ["
|
|
32708
|
-
extensions: [".
|
|
33305
|
+
elixir_ls: {
|
|
33306
|
+
command: ["elixir-ls"],
|
|
33307
|
+
extensions: [".ex", ".exs"],
|
|
33308
|
+
root: NearestRoot(["mix.exs", "mix.lock"])
|
|
32709
33309
|
},
|
|
32710
33310
|
zls: {
|
|
32711
33311
|
command: ["zls"],
|
|
32712
|
-
extensions: [".zig"]
|
|
33312
|
+
extensions: [".zig", ".zon"],
|
|
33313
|
+
root: NearestRoot(["build.zig"])
|
|
33314
|
+
},
|
|
33315
|
+
csharp: {
|
|
33316
|
+
command: ["csharp-ls"],
|
|
33317
|
+
extensions: [".cs"],
|
|
33318
|
+
root: NearestRoot([".slnx", ".sln", ".csproj", "global.json"])
|
|
33319
|
+
},
|
|
33320
|
+
fsharp: {
|
|
33321
|
+
command: ["fsautocomplete"],
|
|
33322
|
+
extensions: [".fs", ".fsi", ".fsx", ".fsscript"],
|
|
33323
|
+
root: NearestRoot([".slnx", ".sln", ".fsproj", "global.json"])
|
|
33324
|
+
},
|
|
33325
|
+
sourcekit_lsp: {
|
|
33326
|
+
command: ["sourcekit-lsp"],
|
|
33327
|
+
extensions: [".swift", ".objc", ".objcpp"],
|
|
33328
|
+
root: NearestRoot(["Package.swift", "*.xcodeproj", "*.xcworkspace"])
|
|
33329
|
+
},
|
|
33330
|
+
rust: {
|
|
33331
|
+
command: ["rust-analyzer"],
|
|
33332
|
+
extensions: [".rs"],
|
|
33333
|
+
root: NearestRoot(["Cargo.toml", "Cargo.lock"])
|
|
33334
|
+
},
|
|
33335
|
+
clangd: {
|
|
33336
|
+
command: ["clangd", "--background-index", "--clang-tidy"],
|
|
33337
|
+
extensions: [
|
|
33338
|
+
".c",
|
|
33339
|
+
".cpp",
|
|
33340
|
+
".cc",
|
|
33341
|
+
".cxx",
|
|
33342
|
+
".c++",
|
|
33343
|
+
".h",
|
|
33344
|
+
".hpp",
|
|
33345
|
+
".hh",
|
|
33346
|
+
".hxx",
|
|
33347
|
+
".h++"
|
|
33348
|
+
],
|
|
33349
|
+
root: NearestRoot([
|
|
33350
|
+
"compile_commands.json",
|
|
33351
|
+
"compile_flags.txt",
|
|
33352
|
+
".clangd",
|
|
33353
|
+
"CMakeLists.txt",
|
|
33354
|
+
"Makefile"
|
|
33355
|
+
])
|
|
33356
|
+
},
|
|
33357
|
+
svelte: {
|
|
33358
|
+
command: ["svelteserver", "--stdio"],
|
|
33359
|
+
extensions: [".svelte"],
|
|
33360
|
+
root: NearestRoot(LOCK_FILE_PATTERNS)
|
|
33361
|
+
},
|
|
33362
|
+
astro: {
|
|
33363
|
+
command: ["astro-ls", "--stdio"],
|
|
33364
|
+
extensions: [".astro"],
|
|
33365
|
+
root: NearestRoot(LOCK_FILE_PATTERNS)
|
|
33366
|
+
},
|
|
33367
|
+
jdtls: {
|
|
33368
|
+
command: ["jdtls"],
|
|
33369
|
+
extensions: [".java"],
|
|
33370
|
+
root: NearestRoot([
|
|
33371
|
+
"pom.xml",
|
|
33372
|
+
"build.gradle",
|
|
33373
|
+
"build.gradle.kts",
|
|
33374
|
+
".project",
|
|
33375
|
+
".classpath"
|
|
33376
|
+
])
|
|
33377
|
+
},
|
|
33378
|
+
kotlin_ls: {
|
|
33379
|
+
command: ["kotlin-lsp", "--stdio"],
|
|
33380
|
+
extensions: [".kt", ".kts"],
|
|
33381
|
+
root: NearestRoot([
|
|
33382
|
+
"settings.gradle.kts",
|
|
33383
|
+
"settings.gradle",
|
|
33384
|
+
"gradlew",
|
|
33385
|
+
"build.gradle.kts",
|
|
33386
|
+
"build.gradle",
|
|
33387
|
+
"pom.xml"
|
|
33388
|
+
])
|
|
33389
|
+
},
|
|
33390
|
+
yaml_ls: {
|
|
33391
|
+
command: ["yaml-language-server", "--stdio"],
|
|
33392
|
+
extensions: [".yaml", ".yml"],
|
|
33393
|
+
root: NearestRoot(LOCK_FILE_PATTERNS)
|
|
33394
|
+
},
|
|
33395
|
+
lua_ls: {
|
|
33396
|
+
command: ["lua-language-server"],
|
|
33397
|
+
extensions: [".lua"],
|
|
33398
|
+
root: NearestRoot([
|
|
33399
|
+
".luarc.json",
|
|
33400
|
+
".luarc.jsonc",
|
|
33401
|
+
".luacheckrc",
|
|
33402
|
+
"stylua.toml",
|
|
33403
|
+
"selene.toml",
|
|
33404
|
+
"selene.yml"
|
|
33405
|
+
])
|
|
33406
|
+
},
|
|
33407
|
+
php_intelephense: {
|
|
33408
|
+
command: ["intelephense", "--stdio"],
|
|
33409
|
+
extensions: [".php"],
|
|
33410
|
+
root: NearestRoot(["composer.json", "composer.lock", ".php-version"])
|
|
33411
|
+
},
|
|
33412
|
+
prisma: {
|
|
33413
|
+
command: ["prisma", "language-server"],
|
|
33414
|
+
extensions: [".prisma"],
|
|
33415
|
+
root: NearestRoot(["schema.prisma", "prisma/schema.prisma", "prisma"])
|
|
33416
|
+
},
|
|
33417
|
+
dart: {
|
|
33418
|
+
command: ["dart", "language-server", "--lsp"],
|
|
33419
|
+
extensions: [".dart"],
|
|
33420
|
+
root: NearestRoot(["pubspec.yaml", "analysis_options.yaml"])
|
|
33421
|
+
},
|
|
33422
|
+
ocaml_lsp: {
|
|
33423
|
+
command: ["ocamllsp"],
|
|
33424
|
+
extensions: [".ml", ".mli"],
|
|
33425
|
+
root: NearestRoot(["dune-project", "dune-workspace", ".merlin", "opam"])
|
|
33426
|
+
},
|
|
33427
|
+
bash: {
|
|
33428
|
+
command: ["bash-language-server", "start"],
|
|
33429
|
+
extensions: [".sh", ".bash", ".zsh", ".ksh"],
|
|
33430
|
+
root: undefined
|
|
33431
|
+
},
|
|
33432
|
+
terraform_ls: {
|
|
33433
|
+
command: ["terraform-ls", "serve"],
|
|
33434
|
+
extensions: [".tf", ".tfvars"],
|
|
33435
|
+
root: NearestRoot([".terraform.lock.hcl", "terraform.tfstate", "*.tf"])
|
|
33436
|
+
},
|
|
33437
|
+
texlab: {
|
|
33438
|
+
command: ["texlab"],
|
|
33439
|
+
extensions: [".tex", ".bib"],
|
|
33440
|
+
root: NearestRoot([".latexmkrc", "latexmkrc", ".texlabroot", "texlabroot"])
|
|
33441
|
+
},
|
|
33442
|
+
dockerfile: {
|
|
33443
|
+
command: ["docker-langserver", "--stdio"],
|
|
33444
|
+
extensions: [".dockerfile", "Dockerfile"],
|
|
33445
|
+
root: undefined
|
|
33446
|
+
},
|
|
33447
|
+
gleam: {
|
|
33448
|
+
command: ["gleam", "lsp"],
|
|
33449
|
+
extensions: [".gleam"],
|
|
33450
|
+
root: NearestRoot(["gleam.toml"])
|
|
33451
|
+
},
|
|
33452
|
+
clojure_lsp: {
|
|
33453
|
+
command: ["clojure-lsp", "listen"],
|
|
33454
|
+
extensions: [".clj", ".cljs", ".cljc", ".edn"],
|
|
33455
|
+
root: NearestRoot([
|
|
33456
|
+
"deps.edn",
|
|
33457
|
+
"project.clj",
|
|
33458
|
+
"shadow-cljs.edn",
|
|
33459
|
+
"bb.edn",
|
|
33460
|
+
"build.boot"
|
|
33461
|
+
])
|
|
33462
|
+
},
|
|
33463
|
+
nixd: {
|
|
33464
|
+
command: ["nixd"],
|
|
33465
|
+
extensions: [".nix"],
|
|
33466
|
+
root: NearestRoot(["flake.nix"])
|
|
33467
|
+
},
|
|
33468
|
+
tinymist: {
|
|
33469
|
+
command: ["tinymist"],
|
|
33470
|
+
extensions: [".typ", ".typc"],
|
|
33471
|
+
root: NearestRoot(["typst.toml"])
|
|
33472
|
+
},
|
|
33473
|
+
haskell_language_server: {
|
|
33474
|
+
command: ["haskell-language-server-wrapper", "--lsp"],
|
|
33475
|
+
extensions: [".hs", ".lhs"],
|
|
33476
|
+
root: NearestRoot(["stack.yaml", "cabal.project", "hie.yaml", "*.cabal"])
|
|
33477
|
+
},
|
|
33478
|
+
julials: {
|
|
33479
|
+
command: [
|
|
33480
|
+
"julia",
|
|
33481
|
+
"--startup-file=no",
|
|
33482
|
+
"--history-file=no",
|
|
33483
|
+
"-e",
|
|
33484
|
+
"using LanguageServer; runserver()"
|
|
33485
|
+
],
|
|
33486
|
+
extensions: [".jl"],
|
|
33487
|
+
root: NearestRoot(["Project.toml", "Manifest.toml", "*.jl"])
|
|
32713
33488
|
}
|
|
32714
33489
|
};
|
|
32715
33490
|
var LSP_INSTALL_HINTS = {
|
|
33491
|
+
deno: "Install Deno: https://deno.land/#installation",
|
|
32716
33492
|
typescript: "npm install -g typescript-language-server typescript",
|
|
32717
33493
|
vue: "npm install -g @vue/language-server",
|
|
32718
|
-
svelte: "npm install -g svelte-language-server",
|
|
32719
|
-
astro: "npm install -g @astrojs/language-server",
|
|
32720
33494
|
eslint: "npm install -g vscode-langservers-extracted",
|
|
32721
|
-
|
|
33495
|
+
oxlint: "npm install -g oxlint or install via package manager",
|
|
33496
|
+
biome: "npm install -g @biomejs/biome",
|
|
32722
33497
|
gopls: "go install golang.org/x/tools/gopls@latest",
|
|
32723
|
-
|
|
32724
|
-
|
|
33498
|
+
ruby_lsp: "gem install rubocop (Ruby LSP runs via rubocop --lsp)",
|
|
33499
|
+
ty: "pip install ty or see https://github.com/astral-sh/ty",
|
|
32725
33500
|
pyright: "pip install pyright",
|
|
32726
|
-
|
|
32727
|
-
zls: "
|
|
33501
|
+
elixir_ls: "Download from https://github.com/elixir-lsp/elixir-ls/releases or build from source",
|
|
33502
|
+
zls: "Install via your package manager or build from source: https://github.com/zigtools/zls",
|
|
33503
|
+
csharp: "dotnet tool install --global csharp-ls",
|
|
33504
|
+
fsharp: "dotnet tool install --global fsautocomplete",
|
|
33505
|
+
sourcekit_lsp: "Install via Xcode or Swift toolchain (included with Xcode)",
|
|
33506
|
+
rust: "rustup component add rust-analyzer",
|
|
33507
|
+
clangd: "Install clangd via your system package manager or LLVM",
|
|
33508
|
+
svelte: "npm install -g svelte-language-server",
|
|
33509
|
+
astro: "npm install -g @astrojs/language-server",
|
|
33510
|
+
jdtls: "See https://github.com/eclipse-jdtls/eclipse.jdt.ls for installation",
|
|
33511
|
+
kotlin_ls: "Download from https://github.com/Kotlin/kotlin-lsp/releases",
|
|
33512
|
+
yaml_ls: "npm install -g yaml-language-server",
|
|
33513
|
+
lua_ls: "Download from https://github.com/LuaLS/lua-language-server/releases",
|
|
33514
|
+
php_intelephense: "npm install -g intelephense",
|
|
33515
|
+
prisma: "npm install -g @prisma/language-server or use npx",
|
|
33516
|
+
dart: "dart pub global activate language_server",
|
|
33517
|
+
ocaml_lsp: "opam install ocaml-lsp-server",
|
|
33518
|
+
bash: "npm install -g bash-language-server",
|
|
33519
|
+
terraform_ls: "Download from https://github.com/hashicorp/terraform-ls/releases or install via tfenv",
|
|
33520
|
+
texlab: "Download from https://github.com/latex-lsp/texlab/releases",
|
|
33521
|
+
dockerfile: "npm install -g dockerfile-language-server-nodejs",
|
|
33522
|
+
gleam: "Install Gleam: https://gleam.run/getting-started/",
|
|
33523
|
+
clojure_lsp: "Install via deps.edn, project.clj, or: clj -M -m clojure-lsp.main",
|
|
33524
|
+
nixd: "Install via nix-env or your system package manager",
|
|
33525
|
+
tinymist: "cargo install tinymist or download from releases",
|
|
33526
|
+
haskell_language_server: "Install Haskell Tool Stack or Cabal, then language-server",
|
|
33527
|
+
julials: "Install Julia: https://julialang.org/downloads/"
|
|
32728
33528
|
};
|
|
32729
|
-
var
|
|
33529
|
+
var LANGUAGE_EXTENSIONS = {
|
|
32730
33530
|
".ts": "typescript",
|
|
32731
33531
|
".tsx": "typescriptreact",
|
|
32732
33532
|
".mts": "typescript",
|
|
@@ -32735,35 +33535,180 @@ var EXT_TO_LANG = {
|
|
|
32735
33535
|
".jsx": "javascriptreact",
|
|
32736
33536
|
".mjs": "javascript",
|
|
32737
33537
|
".cjs": "javascript",
|
|
33538
|
+
".ets": "typescript",
|
|
32738
33539
|
".vue": "vue",
|
|
32739
33540
|
".svelte": "svelte",
|
|
32740
33541
|
".astro": "astro",
|
|
32741
33542
|
".html": "html",
|
|
33543
|
+
".htm": "html",
|
|
33544
|
+
".xml": "xml",
|
|
33545
|
+
".xsl": "xsl",
|
|
32742
33546
|
".css": "css",
|
|
32743
33547
|
".scss": "scss",
|
|
33548
|
+
".sass": "sass",
|
|
32744
33549
|
".less": "less",
|
|
32745
33550
|
".json": "json",
|
|
33551
|
+
".jsonc": "json",
|
|
33552
|
+
".graphql": "graphql",
|
|
33553
|
+
".gql": "graphql",
|
|
33554
|
+
".dockerfile": "dockerfile",
|
|
33555
|
+
".sh": "shellscript",
|
|
33556
|
+
".bash": "shellscript",
|
|
33557
|
+
".zsh": "shellscript",
|
|
33558
|
+
".ksh": "shellscript",
|
|
32746
33559
|
".go": "go",
|
|
32747
33560
|
".rs": "rust",
|
|
32748
33561
|
".py": "python",
|
|
32749
33562
|
".pyi": "python",
|
|
33563
|
+
".rb": "ruby",
|
|
33564
|
+
".rake": "ruby",
|
|
33565
|
+
".gemspec": "ruby",
|
|
33566
|
+
".ru": "ruby",
|
|
32750
33567
|
".c": "c",
|
|
32751
33568
|
".cpp": "cpp",
|
|
32752
33569
|
".cc": "cpp",
|
|
32753
33570
|
".cxx": "cpp",
|
|
33571
|
+
".c++": "cpp",
|
|
32754
33572
|
".h": "c",
|
|
32755
33573
|
".hpp": "cpp",
|
|
32756
|
-
".
|
|
33574
|
+
".hh": "cpp",
|
|
33575
|
+
".hxx": "cpp",
|
|
33576
|
+
".h++": "cpp",
|
|
33577
|
+
".java": "java",
|
|
33578
|
+
".kt": "kotlin",
|
|
33579
|
+
".kts": "kotlin",
|
|
33580
|
+
".cs": "csharp",
|
|
33581
|
+
".fs": "fsharp",
|
|
33582
|
+
".fsi": "fsharp",
|
|
33583
|
+
".fsx": "fsharp",
|
|
33584
|
+
".fsscript": "fsharp",
|
|
33585
|
+
".swift": "swift",
|
|
33586
|
+
".m": "objective-c",
|
|
33587
|
+
".mm": "objective-cpp",
|
|
33588
|
+
".zig": "zig",
|
|
33589
|
+
".zon": "zig",
|
|
33590
|
+
".ex": "elixir",
|
|
33591
|
+
".exs": "elixir",
|
|
33592
|
+
".clj": "clojure",
|
|
33593
|
+
".cljs": "clojure",
|
|
33594
|
+
".cljc": "clojure",
|
|
33595
|
+
".edn": "clojure",
|
|
33596
|
+
".hs": "haskell",
|
|
33597
|
+
".lhs": "haskell",
|
|
33598
|
+
".ml": "ocaml",
|
|
33599
|
+
".mli": "ocaml",
|
|
33600
|
+
".scala": "scala",
|
|
33601
|
+
".php": "php",
|
|
33602
|
+
".lua": "lua",
|
|
33603
|
+
".dart": "dart",
|
|
33604
|
+
".yaml": "yaml",
|
|
33605
|
+
".yml": "yaml",
|
|
33606
|
+
".tf": "terraform",
|
|
33607
|
+
".tfvars": "terraform-vars",
|
|
33608
|
+
".hcl": "hcl",
|
|
33609
|
+
".nix": "nix",
|
|
33610
|
+
".typ": "typst",
|
|
33611
|
+
".typc": "typst",
|
|
33612
|
+
".tex": "latex",
|
|
33613
|
+
".latex": "latex",
|
|
33614
|
+
".bib": "bibtex",
|
|
33615
|
+
".bibtex": "bibtex",
|
|
33616
|
+
".prisma": "prisma",
|
|
33617
|
+
".jl": "julia",
|
|
33618
|
+
".gleam": "gleam",
|
|
33619
|
+
".md": "markdown",
|
|
33620
|
+
".markdown": "markdown",
|
|
33621
|
+
".d": "d",
|
|
33622
|
+
".pas": "pascal",
|
|
33623
|
+
".pascal": "pascal",
|
|
33624
|
+
".diff": "diff",
|
|
33625
|
+
".patch": "diff",
|
|
33626
|
+
".erl": "erlang",
|
|
33627
|
+
".hrl": "erlang",
|
|
33628
|
+
".groovy": "groovy",
|
|
33629
|
+
".handlebars": "handlebars",
|
|
33630
|
+
".hbs": "handlebars",
|
|
33631
|
+
".ini": "ini",
|
|
33632
|
+
".makefile": "makefile",
|
|
33633
|
+
makefile: "makefile",
|
|
33634
|
+
".pug": "jade",
|
|
33635
|
+
".jade": "jade",
|
|
33636
|
+
".r": "r",
|
|
33637
|
+
".cshtml": "razor",
|
|
33638
|
+
".razor": "razor",
|
|
33639
|
+
".erb": "erb",
|
|
33640
|
+
".html.erb": "erb",
|
|
33641
|
+
".js.erb": "erb",
|
|
33642
|
+
".css.erb": "erb",
|
|
33643
|
+
".json.erb": "erb",
|
|
33644
|
+
".shader": "shaderlab",
|
|
33645
|
+
".sql": "sql",
|
|
33646
|
+
".perl": "perl",
|
|
33647
|
+
".pl": "perl",
|
|
33648
|
+
".pm": "perl",
|
|
33649
|
+
".pm6": "perl6",
|
|
33650
|
+
".ps1": "powershell",
|
|
33651
|
+
".psm1": "powershell",
|
|
33652
|
+
".coffee": "coffeescript",
|
|
33653
|
+
".bat": "bat",
|
|
33654
|
+
".abap": "abap",
|
|
33655
|
+
".gitcommit": "git-commit",
|
|
33656
|
+
".gitrebase": "git-rebase"
|
|
32757
33657
|
};
|
|
32758
33658
|
|
|
32759
33659
|
// src/tools/lsp/config.ts
|
|
32760
|
-
function
|
|
33660
|
+
function buildMergedServers() {
|
|
33661
|
+
const servers = new Map;
|
|
32761
33662
|
for (const [id, config3] of Object.entries(BUILTIN_SERVERS)) {
|
|
33663
|
+
servers.set(id, {
|
|
33664
|
+
id,
|
|
33665
|
+
command: config3.command,
|
|
33666
|
+
extensions: config3.extensions,
|
|
33667
|
+
root: config3.root,
|
|
33668
|
+
env: config3.env,
|
|
33669
|
+
initialization: config3.initialization
|
|
33670
|
+
});
|
|
33671
|
+
}
|
|
33672
|
+
if (hasUserLspConfig()) {
|
|
33673
|
+
for (const [id, userConfig2] of getAllUserLspConfigs()) {
|
|
33674
|
+
if (userConfig2.disabled === true) {
|
|
33675
|
+
servers.delete(id);
|
|
33676
|
+
continue;
|
|
33677
|
+
}
|
|
33678
|
+
const existing = servers.get(id);
|
|
33679
|
+
if (existing) {
|
|
33680
|
+
servers.set(id, {
|
|
33681
|
+
...existing,
|
|
33682
|
+
id,
|
|
33683
|
+
command: userConfig2.command ?? existing.command,
|
|
33684
|
+
extensions: userConfig2.extensions ?? existing.extensions,
|
|
33685
|
+
root: existing.root,
|
|
33686
|
+
env: userConfig2.env ?? existing.env,
|
|
33687
|
+
initialization: userConfig2.initialization ?? existing.initialization
|
|
33688
|
+
});
|
|
33689
|
+
} else {
|
|
33690
|
+
servers.set(id, {
|
|
33691
|
+
id,
|
|
33692
|
+
command: userConfig2.command ?? [],
|
|
33693
|
+
extensions: userConfig2.extensions ?? [],
|
|
33694
|
+
root: undefined,
|
|
33695
|
+
env: userConfig2.env,
|
|
33696
|
+
initialization: userConfig2.initialization
|
|
33697
|
+
});
|
|
33698
|
+
}
|
|
33699
|
+
}
|
|
33700
|
+
}
|
|
33701
|
+
return servers;
|
|
33702
|
+
}
|
|
33703
|
+
function findServerForExtension(ext) {
|
|
33704
|
+
const servers = buildMergedServers();
|
|
33705
|
+
for (const [, config3] of servers) {
|
|
32762
33706
|
if (config3.extensions.includes(ext)) {
|
|
32763
33707
|
const server = {
|
|
32764
|
-
id,
|
|
33708
|
+
id: config3.id,
|
|
32765
33709
|
command: config3.command,
|
|
32766
33710
|
extensions: config3.extensions,
|
|
33711
|
+
root: config3.root,
|
|
32767
33712
|
env: config3.env,
|
|
32768
33713
|
initialization: config3.initialization
|
|
32769
33714
|
};
|
|
@@ -32773,39 +33718,37 @@ function findServerForExtension(ext) {
|
|
|
32773
33718
|
return {
|
|
32774
33719
|
status: "not_installed",
|
|
32775
33720
|
server,
|
|
32776
|
-
installHint: LSP_INSTALL_HINTS[id] || `Install '${config3.command[0]}' and add to PATH`
|
|
33721
|
+
installHint: LSP_INSTALL_HINTS[config3.id] || `Install '${config3.command[0]}' and add to PATH`
|
|
32777
33722
|
};
|
|
32778
33723
|
}
|
|
32779
33724
|
}
|
|
32780
33725
|
return { status: "not_configured", extension: ext };
|
|
32781
33726
|
}
|
|
32782
33727
|
function getLanguageId(ext) {
|
|
32783
|
-
return
|
|
33728
|
+
return LANGUAGE_EXTENSIONS[ext] || "plaintext";
|
|
32784
33729
|
}
|
|
32785
33730
|
function isServerInstalled(command) {
|
|
32786
33731
|
if (command.length === 0)
|
|
32787
33732
|
return false;
|
|
32788
33733
|
const cmd = command[0];
|
|
32789
33734
|
if (cmd.includes("/") || cmd.includes("\\")) {
|
|
32790
|
-
return
|
|
33735
|
+
return existsSync10(cmd);
|
|
32791
33736
|
}
|
|
32792
33737
|
const isWindows = process.platform === "win32";
|
|
32793
33738
|
const ext = isWindows ? ".exe" : "";
|
|
32794
|
-
const
|
|
32795
|
-
const
|
|
32796
|
-
const
|
|
32797
|
-
|
|
32798
|
-
|
|
32799
|
-
|
|
32800
|
-
|
|
33739
|
+
const opencodeBin = join11(homedir4(), ".config", "opencode", "bin");
|
|
33740
|
+
const searchPath = (process.env.PATH ?? "") + (isWindows ? ";" : ":") + opencodeBin;
|
|
33741
|
+
const result = import_which.default.sync(cmd, {
|
|
33742
|
+
path: searchPath,
|
|
33743
|
+
pathExt: isWindows ? process.env.PATHEXT : undefined,
|
|
33744
|
+
nothrow: true
|
|
33745
|
+
});
|
|
33746
|
+
if (result !== null) {
|
|
33747
|
+
return true;
|
|
32801
33748
|
}
|
|
32802
33749
|
const cwd = process.cwd();
|
|
32803
33750
|
const localBin = join11(cwd, "node_modules", ".bin", cmd);
|
|
32804
|
-
if (
|
|
32805
|
-
return true;
|
|
32806
|
-
}
|
|
32807
|
-
const globalBin = join11(homedir5(), ".config", "opencode", "bin", cmd);
|
|
32808
|
-
if (existsSync9(globalBin) || existsSync9(globalBin + ext)) {
|
|
33751
|
+
if (existsSync10(localBin) || existsSync10(localBin + ext)) {
|
|
32809
33752
|
return true;
|
|
32810
33753
|
}
|
|
32811
33754
|
return false;
|
|
@@ -32818,6 +33761,7 @@ class LSPServerManager {
|
|
|
32818
33761
|
cleanupInterval = null;
|
|
32819
33762
|
IDLE_TIMEOUT = 5 * 60 * 1000;
|
|
32820
33763
|
constructor() {
|
|
33764
|
+
log("[lsp] manager initialized");
|
|
32821
33765
|
this.startCleanupTimer();
|
|
32822
33766
|
this.registerProcessCleanup();
|
|
32823
33767
|
}
|
|
@@ -32874,16 +33818,31 @@ class LSPServerManager {
|
|
|
32874
33818
|
const managed = this.clients.get(key);
|
|
32875
33819
|
if (managed) {
|
|
32876
33820
|
if (managed.initPromise) {
|
|
33821
|
+
log("[lsp] getClient: waiting for init", { key, server: server.id });
|
|
32877
33822
|
await managed.initPromise;
|
|
32878
33823
|
}
|
|
32879
33824
|
if (managed.client.isAlive()) {
|
|
32880
33825
|
managed.refCount++;
|
|
32881
33826
|
managed.lastUsedAt = Date.now();
|
|
33827
|
+
log("[lsp] getClient: reuse pooled client", {
|
|
33828
|
+
key,
|
|
33829
|
+
server: server.id,
|
|
33830
|
+
refCount: managed.refCount
|
|
33831
|
+
});
|
|
32882
33832
|
return managed.client;
|
|
32883
33833
|
}
|
|
33834
|
+
log("[lsp] getClient: client dead, recreating", {
|
|
33835
|
+
key,
|
|
33836
|
+
server: server.id
|
|
33837
|
+
});
|
|
32884
33838
|
await managed.client.stop();
|
|
32885
33839
|
this.clients.delete(key);
|
|
32886
33840
|
}
|
|
33841
|
+
log("[lsp] getClient: creating new client", {
|
|
33842
|
+
key,
|
|
33843
|
+
server: server.id,
|
|
33844
|
+
root
|
|
33845
|
+
});
|
|
32887
33846
|
const client = new LSPClient(root, server);
|
|
32888
33847
|
const initPromise2 = (async () => {
|
|
32889
33848
|
await client.start();
|
|
@@ -32903,7 +33862,13 @@ class LSPServerManager {
|
|
|
32903
33862
|
m.initPromise = undefined;
|
|
32904
33863
|
m.isInitializing = false;
|
|
32905
33864
|
}
|
|
33865
|
+
log("[lsp] getClient: client ready", { key, server: server.id });
|
|
32906
33866
|
} catch (err) {
|
|
33867
|
+
log("[lsp] getClient: init failed", {
|
|
33868
|
+
key,
|
|
33869
|
+
server: server.id,
|
|
33870
|
+
error: String(err)
|
|
33871
|
+
});
|
|
32907
33872
|
this.clients.delete(key);
|
|
32908
33873
|
throw err;
|
|
32909
33874
|
}
|
|
@@ -32915,6 +33880,11 @@ class LSPServerManager {
|
|
|
32915
33880
|
if (managed && managed.refCount > 0) {
|
|
32916
33881
|
managed.refCount--;
|
|
32917
33882
|
managed.lastUsedAt = Date.now();
|
|
33883
|
+
log("[lsp] releaseClient", {
|
|
33884
|
+
key,
|
|
33885
|
+
server: serverId,
|
|
33886
|
+
refCount: managed.refCount
|
|
33887
|
+
});
|
|
32918
33888
|
}
|
|
32919
33889
|
}
|
|
32920
33890
|
isServerInitializing(root, serverId) {
|
|
@@ -32923,14 +33893,19 @@ class LSPServerManager {
|
|
|
32923
33893
|
return managed?.isInitializing ?? false;
|
|
32924
33894
|
}
|
|
32925
33895
|
async stopAll() {
|
|
32926
|
-
|
|
33896
|
+
log("[lsp] stopAll: shutting down all clients", {
|
|
33897
|
+
count: this.clients.size
|
|
33898
|
+
});
|
|
33899
|
+
for (const [key, managed] of this.clients) {
|
|
32927
33900
|
await managed.client.stop();
|
|
33901
|
+
log("[lsp] stopAll: client stopped", { key });
|
|
32928
33902
|
}
|
|
32929
33903
|
this.clients.clear();
|
|
32930
33904
|
if (this.cleanupInterval) {
|
|
32931
33905
|
clearInterval(this.cleanupInterval);
|
|
32932
33906
|
this.cleanupInterval = null;
|
|
32933
33907
|
}
|
|
33908
|
+
log("[lsp] stopAll: complete");
|
|
32934
33909
|
}
|
|
32935
33910
|
}
|
|
32936
33911
|
var lspManager = LSPServerManager.getInstance();
|
|
@@ -32949,6 +33924,11 @@ class LSPClient {
|
|
|
32949
33924
|
this.server = server;
|
|
32950
33925
|
}
|
|
32951
33926
|
async start() {
|
|
33927
|
+
log("[lsp] LSPClient.start: spawning server", {
|
|
33928
|
+
server: this.server.id,
|
|
33929
|
+
command: this.server.command.join(" "),
|
|
33930
|
+
root: this.root
|
|
33931
|
+
});
|
|
32952
33932
|
this.proc = spawn5(this.server.command, {
|
|
32953
33933
|
stdin: "pipe",
|
|
32954
33934
|
stdout: "pipe",
|
|
@@ -33018,13 +33998,19 @@ class LSPClient {
|
|
|
33018
33998
|
this.processExited = true;
|
|
33019
33999
|
});
|
|
33020
34000
|
this.connection.listen();
|
|
33021
|
-
await new Promise((
|
|
34001
|
+
await new Promise((resolve3) => setTimeout(resolve3, 100));
|
|
33022
34002
|
if (this.proc.exitCode !== null) {
|
|
33023
34003
|
const stderr = this.stderrBuffer.join(`
|
|
33024
34004
|
`);
|
|
34005
|
+
log("[lsp] LSPClient.start: server exited immediately", {
|
|
34006
|
+
server: this.server.id,
|
|
34007
|
+
exitCode: this.proc.exitCode,
|
|
34008
|
+
stderr: stderr.slice(0, 500)
|
|
34009
|
+
});
|
|
33025
34010
|
throw new Error(`LSP server exited immediately with code ${this.proc.exitCode}` + (stderr ? `
|
|
33026
34011
|
stderr: ${stderr}` : ""));
|
|
33027
34012
|
}
|
|
34013
|
+
log("[lsp] LSPClient.start: server spawned", { server: this.server.id });
|
|
33028
34014
|
}
|
|
33029
34015
|
startStderrReading() {
|
|
33030
34016
|
if (!this.proc)
|
|
@@ -33050,6 +34036,10 @@ stderr: ${stderr}` : ""));
|
|
|
33050
34036
|
async initialize() {
|
|
33051
34037
|
if (!this.connection)
|
|
33052
34038
|
throw new Error("LSP connection not established");
|
|
34039
|
+
log("[lsp] LSPClient.initialize: sending initialize request", {
|
|
34040
|
+
server: this.server.id,
|
|
34041
|
+
root: this.root
|
|
34042
|
+
});
|
|
33053
34043
|
const rootUri = pathToFileURL(this.root).href;
|
|
33054
34044
|
await this.connection.sendRequest("initialize", {
|
|
33055
34045
|
processId: process.pid,
|
|
@@ -33081,14 +34071,22 @@ stderr: ${stderr}` : ""));
|
|
|
33081
34071
|
});
|
|
33082
34072
|
this.connection.sendNotification("initialized");
|
|
33083
34073
|
await new Promise((r) => setTimeout(r, 300));
|
|
34074
|
+
log("[lsp] LSPClient.initialize: complete", { server: this.server.id });
|
|
33084
34075
|
}
|
|
33085
34076
|
async openFile(filePath) {
|
|
33086
|
-
const absPath =
|
|
33087
|
-
if (this.openedFiles.has(absPath))
|
|
34077
|
+
const absPath = resolve2(filePath);
|
|
34078
|
+
if (this.openedFiles.has(absPath)) {
|
|
34079
|
+
log("[lsp] openFile: already open, skipping", { filePath: absPath });
|
|
33088
34080
|
return;
|
|
34081
|
+
}
|
|
33089
34082
|
const text = readFileSync4(absPath, "utf-8");
|
|
33090
34083
|
const ext = extname(absPath);
|
|
33091
34084
|
const languageId = getLanguageId(ext);
|
|
34085
|
+
log("[lsp] openFile: opening document", {
|
|
34086
|
+
filePath: absPath,
|
|
34087
|
+
languageId,
|
|
34088
|
+
size: text.length
|
|
34089
|
+
});
|
|
33092
34090
|
this.connection?.sendNotification("textDocument/didOpen", {
|
|
33093
34091
|
textDocument: {
|
|
33094
34092
|
uri: pathToFileURL(absPath).href,
|
|
@@ -33101,7 +34099,7 @@ stderr: ${stderr}` : ""));
|
|
|
33101
34099
|
await new Promise((r) => setTimeout(r, 1000));
|
|
33102
34100
|
}
|
|
33103
34101
|
async definition(filePath, line, character) {
|
|
33104
|
-
const absPath =
|
|
34102
|
+
const absPath = resolve2(filePath);
|
|
33105
34103
|
await this.openFile(absPath);
|
|
33106
34104
|
return this.connection?.sendRequest("textDocument/definition", {
|
|
33107
34105
|
textDocument: { uri: pathToFileURL(absPath).href },
|
|
@@ -33109,7 +34107,7 @@ stderr: ${stderr}` : ""));
|
|
|
33109
34107
|
});
|
|
33110
34108
|
}
|
|
33111
34109
|
async references(filePath, line, character, includeDeclaration = true) {
|
|
33112
|
-
const absPath =
|
|
34110
|
+
const absPath = resolve2(filePath);
|
|
33113
34111
|
await this.openFile(absPath);
|
|
33114
34112
|
return this.connection?.sendRequest("textDocument/references", {
|
|
33115
34113
|
textDocument: { uri: pathToFileURL(absPath).href },
|
|
@@ -33118,7 +34116,7 @@ stderr: ${stderr}` : ""));
|
|
|
33118
34116
|
});
|
|
33119
34117
|
}
|
|
33120
34118
|
async diagnostics(filePath) {
|
|
33121
|
-
const absPath =
|
|
34119
|
+
const absPath = resolve2(filePath);
|
|
33122
34120
|
const uri = pathToFileURL(absPath).href;
|
|
33123
34121
|
await this.openFile(absPath);
|
|
33124
34122
|
await new Promise((r) => setTimeout(r, 500));
|
|
@@ -33133,7 +34131,7 @@ stderr: ${stderr}` : ""));
|
|
|
33133
34131
|
return { items: this.diagnosticsStore.get(uri) ?? [] };
|
|
33134
34132
|
}
|
|
33135
34133
|
async rename(filePath, line, character, newName) {
|
|
33136
|
-
const absPath =
|
|
34134
|
+
const absPath = resolve2(filePath);
|
|
33137
34135
|
await this.openFile(absPath);
|
|
33138
34136
|
return this.connection?.sendRequest("textDocument/rename", {
|
|
33139
34137
|
textDocument: { uri: pathToFileURL(absPath).href },
|
|
@@ -33145,6 +34143,7 @@ stderr: ${stderr}` : ""));
|
|
|
33145
34143
|
return this.proc !== null && !this.processExited && this.proc.exitCode === null;
|
|
33146
34144
|
}
|
|
33147
34145
|
async stop() {
|
|
34146
|
+
log("[lsp] LSPClient.stop: stopping", { server: this.server.id });
|
|
33148
34147
|
try {
|
|
33149
34148
|
if (this.connection) {
|
|
33150
34149
|
await this.connection.sendRequest("shutdown");
|
|
@@ -33157,45 +34156,24 @@ stderr: ${stderr}` : ""));
|
|
|
33157
34156
|
this.connection = null;
|
|
33158
34157
|
this.processExited = true;
|
|
33159
34158
|
this.diagnosticsStore.clear();
|
|
34159
|
+
log("[lsp] LSPClient.stop: complete", { server: this.server.id });
|
|
33160
34160
|
}
|
|
33161
34161
|
}
|
|
33162
34162
|
// src/tools/lsp/utils.ts
|
|
33163
34163
|
import {
|
|
33164
|
-
existsSync as
|
|
34164
|
+
existsSync as existsSync11,
|
|
33165
34165
|
readFileSync as readFileSync5,
|
|
33166
|
-
statSync as
|
|
34166
|
+
statSync as statSync4,
|
|
33167
34167
|
unlinkSync as unlinkSync3,
|
|
33168
34168
|
writeFileSync as writeFileSync3
|
|
33169
34169
|
} from "fs";
|
|
33170
|
-
import { dirname as
|
|
34170
|
+
import { dirname as dirname6, extname as extname2, join as join12, resolve as resolve3 } from "path";
|
|
33171
34171
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
33172
|
-
function
|
|
33173
|
-
|
|
33174
|
-
|
|
33175
|
-
if (!statSync3(dir).isDirectory()) {
|
|
33176
|
-
dir = dirname4(dir);
|
|
33177
|
-
}
|
|
33178
|
-
} catch {
|
|
33179
|
-
dir = dirname4(dir);
|
|
33180
|
-
}
|
|
33181
|
-
const markers = [
|
|
33182
|
-
".git",
|
|
33183
|
-
"package.json",
|
|
33184
|
-
"pyproject.toml",
|
|
33185
|
-
"Cargo.toml",
|
|
33186
|
-
"go.mod"
|
|
33187
|
-
];
|
|
33188
|
-
let prevDir = "";
|
|
33189
|
-
while (dir !== prevDir) {
|
|
33190
|
-
for (const marker of markers) {
|
|
33191
|
-
if (existsSync10(join12(dir, marker))) {
|
|
33192
|
-
return dir;
|
|
33193
|
-
}
|
|
33194
|
-
}
|
|
33195
|
-
prevDir = dir;
|
|
33196
|
-
dir = dirname4(dir);
|
|
34172
|
+
function findServerProjectRoot(filePath, server) {
|
|
34173
|
+
if (server.root) {
|
|
34174
|
+
return server.root(filePath) ?? dirname6(resolve3(filePath));
|
|
33197
34175
|
}
|
|
33198
|
-
return
|
|
34176
|
+
return dirname6(resolve3(filePath));
|
|
33199
34177
|
}
|
|
33200
34178
|
function uriToPath(uri) {
|
|
33201
34179
|
return fileURLToPath2(uri);
|
|
@@ -33214,24 +34192,42 @@ function formatServerLookupError(result) {
|
|
|
33214
34192
|
return `No LSP server configured for extension: ${result.extension}`;
|
|
33215
34193
|
}
|
|
33216
34194
|
async function withLspClient(filePath, fn) {
|
|
33217
|
-
const absPath =
|
|
34195
|
+
const absPath = resolve3(filePath);
|
|
33218
34196
|
const ext = extname2(absPath);
|
|
33219
34197
|
const result = findServerForExtension(ext);
|
|
33220
34198
|
if (result.status !== "found") {
|
|
34199
|
+
log("[lsp] withLspClient: server not found", {
|
|
34200
|
+
filePath: absPath,
|
|
34201
|
+
extension: ext
|
|
34202
|
+
});
|
|
33221
34203
|
throw new Error(formatServerLookupError(result));
|
|
33222
34204
|
}
|
|
33223
34205
|
const server = result.server;
|
|
33224
|
-
const root =
|
|
34206
|
+
const root = findServerProjectRoot(absPath, server) ?? dirname6(absPath);
|
|
34207
|
+
log("[lsp] withLspClient: acquiring client", {
|
|
34208
|
+
filePath: absPath,
|
|
34209
|
+
server: server.id,
|
|
34210
|
+
root
|
|
34211
|
+
});
|
|
33225
34212
|
const client = await lspManager.getClient(root, server);
|
|
33226
34213
|
try {
|
|
33227
|
-
|
|
34214
|
+
const result2 = await fn(client);
|
|
34215
|
+
log("[lsp] withLspClient: operation complete", { server: server.id });
|
|
34216
|
+
return result2;
|
|
33228
34217
|
} catch (e) {
|
|
33229
34218
|
if (e instanceof Error && e.message.includes("timeout")) {
|
|
33230
34219
|
const isInitializing = lspManager.isServerInitializing(root, server.id);
|
|
33231
34220
|
if (isInitializing) {
|
|
34221
|
+
log("[lsp] withLspClient: timeout during init", {
|
|
34222
|
+
server: server.id
|
|
34223
|
+
});
|
|
33232
34224
|
throw new Error(`LSP server is still initializing. Please retry in a few seconds.`);
|
|
33233
34225
|
}
|
|
33234
34226
|
}
|
|
34227
|
+
log("[lsp] withLspClient: operation failed", {
|
|
34228
|
+
server: server.id,
|
|
34229
|
+
error: String(e)
|
|
34230
|
+
});
|
|
33235
34231
|
throw e;
|
|
33236
34232
|
} finally {
|
|
33237
34233
|
lspManager.releaseClient(root, server.id);
|
|
@@ -33315,6 +34311,7 @@ function applyTextEditsToFile(filePath, edits) {
|
|
|
33315
34311
|
}
|
|
33316
34312
|
function applyWorkspaceEdit(edit) {
|
|
33317
34313
|
if (!edit) {
|
|
34314
|
+
log("[lsp] applyWorkspaceEdit: no edit provided");
|
|
33318
34315
|
return {
|
|
33319
34316
|
success: false,
|
|
33320
34317
|
filesModified: [],
|
|
@@ -33322,6 +34319,8 @@ function applyWorkspaceEdit(edit) {
|
|
|
33322
34319
|
errors: ["No edit provided"]
|
|
33323
34320
|
};
|
|
33324
34321
|
}
|
|
34322
|
+
const changeCount = (edit.changes ? Object.keys(edit.changes).length : 0) + (edit.documentChanges ? edit.documentChanges.length : 0);
|
|
34323
|
+
log("[lsp] applyWorkspaceEdit: applying", { changeCount });
|
|
33325
34324
|
const result = {
|
|
33326
34325
|
success: true,
|
|
33327
34326
|
filesModified: [],
|
|
@@ -33388,6 +34387,12 @@ function applyWorkspaceEdit(edit) {
|
|
|
33388
34387
|
}
|
|
33389
34388
|
}
|
|
33390
34389
|
}
|
|
34390
|
+
log("[lsp] applyWorkspaceEdit: complete", {
|
|
34391
|
+
success: result.success,
|
|
34392
|
+
filesModified: result.filesModified.length,
|
|
34393
|
+
totalEdits: result.totalEdits,
|
|
34394
|
+
errors: result.errors.length
|
|
34395
|
+
});
|
|
33391
34396
|
return result;
|
|
33392
34397
|
}
|
|
33393
34398
|
function formatApplyResult(result) {
|
|
@@ -33536,6 +34541,28 @@ var OhMyOpenCodeLite = async (ctx) => {
|
|
|
33536
34541
|
modelArrayMap[agentDef.name] = agentDef._modelArray;
|
|
33537
34542
|
}
|
|
33538
34543
|
}
|
|
34544
|
+
const runtimeChains = {};
|
|
34545
|
+
for (const agentDef of agentDefs) {
|
|
34546
|
+
if (agentDef._modelArray?.length) {
|
|
34547
|
+
runtimeChains[agentDef.name] = agentDef._modelArray.map((m) => m.id);
|
|
34548
|
+
}
|
|
34549
|
+
}
|
|
34550
|
+
if (config3.fallback?.enabled !== false) {
|
|
34551
|
+
const chains = config3.fallback?.chains ?? {};
|
|
34552
|
+
for (const [agentName, chainModels] of Object.entries(chains)) {
|
|
34553
|
+
if (!chainModels?.length)
|
|
34554
|
+
continue;
|
|
34555
|
+
const existing = runtimeChains[agentName] ?? [];
|
|
34556
|
+
const seen = new Set(existing);
|
|
34557
|
+
for (const m of chainModels) {
|
|
34558
|
+
if (!seen.has(m)) {
|
|
34559
|
+
seen.add(m);
|
|
34560
|
+
existing.push(m);
|
|
34561
|
+
}
|
|
34562
|
+
}
|
|
34563
|
+
runtimeChains[agentName] = existing;
|
|
34564
|
+
}
|
|
34565
|
+
}
|
|
33539
34566
|
const tmuxConfig = {
|
|
33540
34567
|
enabled: config3.tmux?.enabled ?? false,
|
|
33541
34568
|
layout: config3.tmux?.layout ?? "main-vertical",
|
|
@@ -33562,6 +34589,7 @@ var OhMyOpenCodeLite = async (ctx) => {
|
|
|
33562
34589
|
const chatHeadersHook = createChatHeadersHook(ctx);
|
|
33563
34590
|
const delegateTaskRetryHook = createDelegateTaskRetryHook(ctx);
|
|
33564
34591
|
const jsonErrorRecoveryHook = createJsonErrorRecoveryHook(ctx);
|
|
34592
|
+
const foregroundFallback = new ForegroundFallbackManager(ctx.client, runtimeChains, config3.fallback?.enabled !== false && Object.keys(runtimeChains).length > 0);
|
|
33565
34593
|
return {
|
|
33566
34594
|
name: "oh-my-opencode-slim",
|
|
33567
34595
|
agent: agents,
|
|
@@ -33577,43 +34605,96 @@ var OhMyOpenCodeLite = async (ctx) => {
|
|
|
33577
34605
|
},
|
|
33578
34606
|
mcp: mcps,
|
|
33579
34607
|
config: async (opencodeConfig) => {
|
|
33580
|
-
|
|
34608
|
+
const lspConfig = opencodeConfig.lsp;
|
|
34609
|
+
setUserLspConfig(lspConfig);
|
|
34610
|
+
if (config3.setDefaultAgent !== false && !opencodeConfig.default_agent) {
|
|
34611
|
+
opencodeConfig.default_agent = "orchestrator";
|
|
34612
|
+
}
|
|
33581
34613
|
if (!opencodeConfig.agent) {
|
|
33582
34614
|
opencodeConfig.agent = { ...agents };
|
|
33583
34615
|
} else {
|
|
33584
|
-
Object.
|
|
34616
|
+
for (const [name, pluginAgent] of Object.entries(agents)) {
|
|
34617
|
+
const existing = opencodeConfig.agent[name];
|
|
34618
|
+
if (existing) {
|
|
34619
|
+
opencodeConfig.agent[name] = {
|
|
34620
|
+
...pluginAgent,
|
|
34621
|
+
...existing
|
|
34622
|
+
};
|
|
34623
|
+
} else {
|
|
34624
|
+
opencodeConfig.agent[name] = {
|
|
34625
|
+
...pluginAgent
|
|
34626
|
+
};
|
|
34627
|
+
}
|
|
34628
|
+
}
|
|
33585
34629
|
}
|
|
33586
34630
|
const configAgent = opencodeConfig.agent;
|
|
33587
|
-
|
|
34631
|
+
const fallbackChainsEnabled = config3.fallback?.enabled !== false;
|
|
34632
|
+
const fallbackChains = fallbackChainsEnabled ? config3.fallback?.chains ?? {} : {};
|
|
34633
|
+
const effectiveArrays = {};
|
|
34634
|
+
for (const [agentName, models] of Object.entries(modelArrayMap)) {
|
|
34635
|
+
effectiveArrays[agentName] = [...models];
|
|
34636
|
+
}
|
|
34637
|
+
for (const [agentName, chainModels] of Object.entries(fallbackChains)) {
|
|
34638
|
+
if (!chainModels || chainModels.length === 0)
|
|
34639
|
+
continue;
|
|
34640
|
+
if (!effectiveArrays[agentName]) {
|
|
34641
|
+
const entry = configAgent[agentName];
|
|
34642
|
+
const currentModel = typeof entry?.model === "string" ? entry.model : undefined;
|
|
34643
|
+
effectiveArrays[agentName] = currentModel ? [{ id: currentModel }] : [];
|
|
34644
|
+
}
|
|
34645
|
+
const seen = new Set(effectiveArrays[agentName].map((m) => m.id));
|
|
34646
|
+
for (const chainModel of chainModels) {
|
|
34647
|
+
if (!seen.has(chainModel)) {
|
|
34648
|
+
seen.add(chainModel);
|
|
34649
|
+
effectiveArrays[agentName].push({ id: chainModel });
|
|
34650
|
+
}
|
|
34651
|
+
}
|
|
34652
|
+
}
|
|
34653
|
+
if (Object.keys(effectiveArrays).length > 0) {
|
|
33588
34654
|
const providerConfig = opencodeConfig.provider ?? {};
|
|
33589
|
-
const
|
|
33590
|
-
for (const [agentName, modelArray] of Object.entries(
|
|
34655
|
+
const hasProviderConfig = Object.keys(providerConfig).length > 0;
|
|
34656
|
+
for (const [agentName, modelArray] of Object.entries(effectiveArrays)) {
|
|
34657
|
+
if (modelArray.length === 0)
|
|
34658
|
+
continue;
|
|
33591
34659
|
let resolved = false;
|
|
33592
|
-
|
|
33593
|
-
const
|
|
33594
|
-
|
|
33595
|
-
|
|
33596
|
-
|
|
33597
|
-
|
|
33598
|
-
const
|
|
33599
|
-
if (
|
|
33600
|
-
entry
|
|
33601
|
-
if (
|
|
33602
|
-
entry.
|
|
34660
|
+
if (hasProviderConfig) {
|
|
34661
|
+
const configuredProviders = Object.keys(providerConfig);
|
|
34662
|
+
for (const modelEntry of modelArray) {
|
|
34663
|
+
const slashIdx = modelEntry.id.indexOf("/");
|
|
34664
|
+
if (slashIdx === -1)
|
|
34665
|
+
continue;
|
|
34666
|
+
const providerID = modelEntry.id.slice(0, slashIdx);
|
|
34667
|
+
if (configuredProviders.includes(providerID)) {
|
|
34668
|
+
const entry = configAgent[agentName];
|
|
34669
|
+
if (entry) {
|
|
34670
|
+
entry.model = modelEntry.id;
|
|
34671
|
+
if (modelEntry.variant) {
|
|
34672
|
+
entry.variant = modelEntry.variant;
|
|
34673
|
+
}
|
|
33603
34674
|
}
|
|
34675
|
+
log("[plugin] resolved model fallback", {
|
|
34676
|
+
agent: agentName,
|
|
34677
|
+
model: modelEntry.id,
|
|
34678
|
+
variant: modelEntry.variant
|
|
34679
|
+
});
|
|
34680
|
+
resolved = true;
|
|
34681
|
+
break;
|
|
33604
34682
|
}
|
|
33605
|
-
log("[plugin] resolved model fallback", {
|
|
33606
|
-
agent: agentName,
|
|
33607
|
-
model: modelEntry.id,
|
|
33608
|
-
variant: modelEntry.variant
|
|
33609
|
-
});
|
|
33610
|
-
resolved = true;
|
|
33611
|
-
break;
|
|
33612
34683
|
}
|
|
33613
34684
|
}
|
|
33614
34685
|
if (!resolved) {
|
|
33615
|
-
|
|
33616
|
-
|
|
34686
|
+
const firstModel = modelArray[0];
|
|
34687
|
+
const entry = configAgent[agentName];
|
|
34688
|
+
if (entry) {
|
|
34689
|
+
entry.model = firstModel.id;
|
|
34690
|
+
if (firstModel.variant) {
|
|
34691
|
+
entry.variant = firstModel.variant;
|
|
34692
|
+
}
|
|
34693
|
+
}
|
|
34694
|
+
log("[plugin] resolved model from array (no provider config)", {
|
|
34695
|
+
agent: agentName,
|
|
34696
|
+
model: firstModel.id,
|
|
34697
|
+
variant: firstModel.variant
|
|
33617
34698
|
});
|
|
33618
34699
|
}
|
|
33619
34700
|
}
|
|
@@ -33647,6 +34728,7 @@ var OhMyOpenCodeLite = async (ctx) => {
|
|
|
33647
34728
|
}
|
|
33648
34729
|
},
|
|
33649
34730
|
event: async (input) => {
|
|
34731
|
+
await foregroundFallback.handleEvent(input.event);
|
|
33650
34732
|
await autoUpdateChecker.event(input);
|
|
33651
34733
|
await tmuxSessionManager.onSessionCreated(input.event);
|
|
33652
34734
|
await backgroundManager.handleSessionStatus(input.event);
|