@trim21/personal-pi-extensions 0.0.299 → 0.0.300
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/package.json +3 -1
- package/src/claude-code/files.ts +168 -137
- package/src/lib/lsp/adapter.ts +41 -0
- package/src/lib/lsp/adapters/clangd.ts +26 -0
- package/src/lib/lsp/adapters/index.ts +11 -0
- package/src/lib/lsp/adapters/pyright.ts +50 -0
- package/src/lib/lsp/adapters/ruff.ts +27 -0
- package/src/lib/lsp/adapters/typescript.ts +34 -0
- package/src/lib/lsp/bin.ts +88 -0
- package/src/lib/lsp/client.ts +693 -0
- package/src/lib/lsp/diagnostic.ts +35 -0
- package/src/lib/lsp/language.ts +125 -0
- package/src/lib/lsp/launch.ts +22 -0
- package/src/lib/lsp/lsp.ts +285 -0
- package/src/opencode/{read.ts → files.ts} +276 -31
- package/src/opencode/index.ts +13 -14
- package/src/spawn-agent.ts +6 -4
- package/src/opencode/edit.ts +0 -169
- package/src/opencode/write.ts +0 -116
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 工作区优先的二进制 / 模块查找。
|
|
3
|
+
*
|
|
4
|
+
* 查找顺序(对每个候选目录逐级向上到 stopDir 为止):
|
|
5
|
+
* node_modules/.bin/<cmd> → .venv/bin/<cmd> → venv/bin/<cmd>
|
|
6
|
+
* 全部落空后由调用方回退到 PATH(which)。
|
|
7
|
+
* 这样项目用 uv / pnpm 装的服务器(.venv、node_modules)优先于系统级安装。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { existsSync } from "node:fs";
|
|
11
|
+
import { delimiter, dirname, join, normalize } from "node:path";
|
|
12
|
+
|
|
13
|
+
export function exists(p: string): boolean {
|
|
14
|
+
return existsSync(p);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** 从 fromDir 逐级向上(含 stopDir 本身)收集目录,到文件系统根为止。 */
|
|
18
|
+
export function walkUp(fromDir: string, stopDir: string): string[] {
|
|
19
|
+
const dirs: string[] = [];
|
|
20
|
+
let current = normalize(fromDir);
|
|
21
|
+
const stop = normalize(stopDir);
|
|
22
|
+
for (;;) {
|
|
23
|
+
dirs.push(current);
|
|
24
|
+
if (current === stop) break;
|
|
25
|
+
const parent = dirname(current);
|
|
26
|
+
if (parent === current) break;
|
|
27
|
+
current = parent;
|
|
28
|
+
}
|
|
29
|
+
return dirs;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function binaryNames(cmd: string): string[] {
|
|
33
|
+
if (process.platform === "win32") {
|
|
34
|
+
const ext = (process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM").toLowerCase().split(";");
|
|
35
|
+
return [cmd, ...ext.map((e) => cmd + e)];
|
|
36
|
+
}
|
|
37
|
+
return [cmd];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 从 fromDir 向上(到 stopDir)在项目工作区里找二进制。
|
|
42
|
+
* 候选位置:node_modules/.bin、.venv/bin、venv/bin。
|
|
43
|
+
*/
|
|
44
|
+
export function findBinaryInWorkspace(
|
|
45
|
+
cmd: string,
|
|
46
|
+
fromDir: string,
|
|
47
|
+
stopDir: string,
|
|
48
|
+
): Promise<string | undefined> {
|
|
49
|
+
for (const dir of walkUp(fromDir, stopDir)) {
|
|
50
|
+
const roots = [
|
|
51
|
+
join(dir, "node_modules", ".bin"),
|
|
52
|
+
join(dir, ".venv", "bin"),
|
|
53
|
+
join(dir, "venv", "bin"),
|
|
54
|
+
];
|
|
55
|
+
for (const root of roots) {
|
|
56
|
+
for (const name of binaryNames(cmd)) {
|
|
57
|
+
const candidate = join(root, name);
|
|
58
|
+
if (exists(candidate)) return Promise.resolve(candidate);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return Promise.resolve(undefined);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** 从 fromDir 向上(到 stopDir)找 node_modules/<modulePath>(如 typescript/lib/tsserver.js)。 */
|
|
66
|
+
export function findModuleInWorkspace(
|
|
67
|
+
modulePath: string,
|
|
68
|
+
fromDir: string,
|
|
69
|
+
stopDir: string,
|
|
70
|
+
): Promise<string | undefined> {
|
|
71
|
+
for (const dir of walkUp(fromDir, stopDir)) {
|
|
72
|
+
const candidate = join(dir, "node_modules", modulePath);
|
|
73
|
+
if (exists(candidate)) return Promise.resolve(candidate);
|
|
74
|
+
}
|
|
75
|
+
return Promise.resolve(undefined);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** PATH 查找(同步,逻辑简单;调用频率低,无需缓存)。 */
|
|
79
|
+
export function which(cmd: string): string | undefined {
|
|
80
|
+
const pathDirs = (process.env.PATH ?? "").split(delimiter).filter(Boolean);
|
|
81
|
+
for (const dir of pathDirs) {
|
|
82
|
+
for (const name of binaryNames(cmd)) {
|
|
83
|
+
const candidate = join(dir, name);
|
|
84
|
+
if (existsSync(candidate)) return candidate;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|