@trim21/personal-pi-extensions 0.1.20261103084002 → 0.1.20261104043713
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trim21/personal-pi-extensions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.20261104043713",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Custom pi coding-agent extensions: bwrap sandbox, workspace guard, opencode edit, and more",
|
|
6
6
|
"keywords": [
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"eslint-plugin-import-x": "^4.17.1",
|
|
55
55
|
"eslint-plugin-promise": "7.3.0",
|
|
56
56
|
"eslint-plugin-simple-import-sort": "14.0.0",
|
|
57
|
-
"eslint-plugin-unicorn": "
|
|
57
|
+
"eslint-plugin-unicorn": "79.0.0",
|
|
58
58
|
"eslint-plugin-unused-imports": "4.4.1",
|
|
59
59
|
"husky": "^9.1.7",
|
|
60
60
|
"jiti": "^2.7.0",
|
package/src/claude-code/shell.ts
CHANGED
|
@@ -79,7 +79,6 @@ function formatBashSuccess(result: Awaited<ReturnType<BwrapRuntime["execute"]>>)
|
|
|
79
79
|
content: { type: "text"; text: string }[];
|
|
80
80
|
details: BashToolDetails | undefined;
|
|
81
81
|
} {
|
|
82
|
-
// eslint-disable-next-line unicorn/prefer-default-parameters -- output 是 string,空输出需显示 "(no output)",默认参数只覆盖 undefined
|
|
83
82
|
const { output, truncation, fullOutputPath } = result;
|
|
84
83
|
const text = appendTruncationNotice(output || "(no output)", truncation, fullOutputPath);
|
|
85
84
|
return {
|
package/src/lib/lsp/lsp.ts
CHANGED
|
@@ -438,6 +438,39 @@ async function abortable<T>(promise: Promise<T>, signal?: AbortSignal): Promise<
|
|
|
438
438
|
await Promise.race([promise, abort]);
|
|
439
439
|
}
|
|
440
440
|
|
|
441
|
+
/**
|
|
442
|
+
* 打开文档让服务器索引 / 产出诊断。diagnostics 传 "document" 时最多等 5s,
|
|
443
|
+
* "full" 最多等 10s;不传则只 didOpen 不等待。
|
|
444
|
+
*/
|
|
445
|
+
async function openAndWaitForDiagnostics(
|
|
446
|
+
clients: LspClient[],
|
|
447
|
+
file: string,
|
|
448
|
+
diagnostics?: "document" | "full",
|
|
449
|
+
options?: LspRequestOptions,
|
|
450
|
+
): Promise<void> {
|
|
451
|
+
await Promise.all(
|
|
452
|
+
clients.map(async (client) => {
|
|
453
|
+
const after = Date.now();
|
|
454
|
+
const version = await client.notify.open({ path: file });
|
|
455
|
+
if (!diagnostics) {
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
await abortable(
|
|
459
|
+
client.waitForDiagnostics({
|
|
460
|
+
path: file,
|
|
461
|
+
version,
|
|
462
|
+
mode: diagnostics,
|
|
463
|
+
after,
|
|
464
|
+
signal: options?.signal,
|
|
465
|
+
}),
|
|
466
|
+
options?.signal,
|
|
467
|
+
);
|
|
468
|
+
}),
|
|
469
|
+
).catch(() => {
|
|
470
|
+
// 诊断等待失败不影响读 / 写操作本身
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
|
|
441
474
|
export interface LspService {
|
|
442
475
|
touchFile(
|
|
443
476
|
file: string,
|
|
@@ -1034,10 +1067,6 @@ export function createLspService(
|
|
|
1034
1067
|
return result;
|
|
1035
1068
|
}
|
|
1036
1069
|
|
|
1037
|
-
/**
|
|
1038
|
-
* 打开文档让服务器索引 / 产出诊断。diagnostics 传 "document" 时最多等 5s,
|
|
1039
|
-
* "full" 最多等 10s;不传则只 didOpen 不等待。
|
|
1040
|
-
*/
|
|
1041
1070
|
async function touchFile(
|
|
1042
1071
|
file: string,
|
|
1043
1072
|
cwd: string,
|
|
@@ -1045,34 +1074,21 @@ export function createLspService(
|
|
|
1045
1074
|
options?: LspRequestOptions,
|
|
1046
1075
|
): Promise<void> {
|
|
1047
1076
|
const clients = await getClients(file, cwd, options?.notify);
|
|
1048
|
-
await
|
|
1049
|
-
clients.map(async (client) => {
|
|
1050
|
-
const after = Date.now();
|
|
1051
|
-
const version = await client.notify.open({ path: file });
|
|
1052
|
-
if (!diagnostics) {
|
|
1053
|
-
return;
|
|
1054
|
-
}
|
|
1055
|
-
await abortable(
|
|
1056
|
-
client.waitForDiagnostics({
|
|
1057
|
-
path: file,
|
|
1058
|
-
version,
|
|
1059
|
-
mode: diagnostics,
|
|
1060
|
-
after,
|
|
1061
|
-
signal: options?.signal,
|
|
1062
|
-
}),
|
|
1063
|
-
options?.signal,
|
|
1064
|
-
);
|
|
1065
|
-
}),
|
|
1066
|
-
).catch(() => {
|
|
1067
|
-
// 诊断等待失败不影响写操作本身
|
|
1068
|
-
});
|
|
1077
|
+
await openAndWaitForDiagnostics(clients, file, diagnostics, options);
|
|
1069
1078
|
}
|
|
1070
1079
|
|
|
1071
|
-
/**
|
|
1080
|
+
/** 聚合活跃工作区内的当前诊断(path → diagnostics)。 */
|
|
1072
1081
|
function diagnostics(): Promise<Record<string, Diagnostic[]>> {
|
|
1073
1082
|
const results: Record<string, Diagnostic[]> = {};
|
|
1074
1083
|
for (const client of state.clients) {
|
|
1075
1084
|
for (const [filePath, diags] of client.diagnostics) {
|
|
1085
|
+
// 服务器可以为 root 外或 cwd 外的路径推送 / pull 诊断:只保留活跃工作区内的
|
|
1086
|
+
if (state.cwd !== undefined && !containsPath(filePath, state.cwd)) {
|
|
1087
|
+
continue;
|
|
1088
|
+
}
|
|
1089
|
+
if (!containsPath(filePath, client.root)) {
|
|
1090
|
+
continue;
|
|
1091
|
+
}
|
|
1076
1092
|
(results[filePath] ??= []).push(...diags);
|
|
1077
1093
|
}
|
|
1078
1094
|
}
|
|
@@ -1081,7 +1097,8 @@ export function createLspService(
|
|
|
1081
1097
|
|
|
1082
1098
|
/**
|
|
1083
1099
|
* read / edit / write 用:等待文档诊断并返回该文件的 ERROR / WARN 报告(text 空串表示无此类诊断)
|
|
1084
|
-
*
|
|
1100
|
+
* 与数量。诊断只取拥有该文件的 client(见 getClients),不属于活跃工作区的文件报告为空。
|
|
1101
|
+
* 内部所有 LSP 失败都会被吞掉,不干扰读取或写操作本身。
|
|
1085
1102
|
*/
|
|
1086
1103
|
async function lspDiagnosticsForFile(
|
|
1087
1104
|
file: string,
|
|
@@ -1091,10 +1108,14 @@ export function createLspService(
|
|
|
1091
1108
|
if (options?.signal?.aborted) {
|
|
1092
1109
|
return EMPTY_DIAGNOSTIC_REPORT;
|
|
1093
1110
|
}
|
|
1094
|
-
await
|
|
1095
|
-
|
|
1111
|
+
const clients = await getClients(file, cwd, options?.notify);
|
|
1112
|
+
if (clients.length === 0) {
|
|
1113
|
+
return EMPTY_DIAGNOSTIC_REPORT;
|
|
1114
|
+
}
|
|
1115
|
+
await openAndWaitForDiagnostics(clients, file, "document", options);
|
|
1096
1116
|
const normalized = normalize(file);
|
|
1097
|
-
|
|
1117
|
+
const collected = clients.flatMap((client) => client.diagnostics.get(normalized) ?? []);
|
|
1118
|
+
return report(normalized, collected);
|
|
1098
1119
|
}
|
|
1099
1120
|
|
|
1100
1121
|
/** 符号重命名:只面向 language 类服务器;按配置顺序取第一个成功结果。 */
|
|
@@ -229,9 +229,9 @@ export function registerLspRenameTool(
|
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
const renamed =
|
|
232
|
-
result.placeholder
|
|
233
|
-
? `
|
|
234
|
-
: `
|
|
232
|
+
result.placeholder === undefined || result.placeholder === params.new_name
|
|
233
|
+
? `to '${params.new_name}'`
|
|
234
|
+
: `'${result.placeholder}' -> '${params.new_name}'`;
|
|
235
235
|
const summary = `Renamed ${renamed} across ${applied.length} file(s).`;
|
|
236
236
|
const text =
|
|
237
237
|
diagnosticText === ""
|
|
@@ -123,7 +123,7 @@ function interpolateEnvVars(value: string, env: NodeJS.ProcessEnv): string {
|
|
|
123
123
|
// eslint-disable-next-line unicorn/prefer-default-parameters -- replaceAll 回调参数被上下文的 ...args: any[] 定成 any,默认参数无法保留 string 注解
|
|
124
124
|
return value.replaceAll(envVarPattern, (_match, name: string, fallback?: string) => {
|
|
125
125
|
const resolved = env[name];
|
|
126
|
-
return resolved
|
|
126
|
+
return resolved === undefined || resolved === "" ? (fallback ?? "") : resolved;
|
|
127
127
|
});
|
|
128
128
|
}
|
|
129
129
|
|
package/src/opencode/files.ts
CHANGED
|
@@ -446,7 +446,6 @@ function registerReadTool(bus: ToolBus, getService: () => LspService, state: Rea
|
|
|
446
446
|
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
447
447
|
signal?.throwIfAborted();
|
|
448
448
|
|
|
449
|
-
// eslint-disable-next-line unicorn/prefer-default-parameters -- params.offset || 1:0 视为 1,默认参数只覆盖 undefined
|
|
450
449
|
const { filePath: rawPath, offset, limit } = params;
|
|
451
450
|
|
|
452
451
|
const absolutePath = isAbsolute(rawPath) ? rawPath : resolvePath(ctx.cwd, rawPath);
|