@trim21/personal-pi-extensions 0.1.688 → 0.1.690
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 +2 -2
- package/src/bwrap/network-stack.ts +2 -1
- package/src/claude-code/grep.ts +2 -1
- package/src/claude-code/shell.ts +1 -0
- package/src/codemode/worker.js +11 -7
- package/src/codemode/worker.ts +10 -6
- package/src/gh/schemas.ts +4 -2
- package/src/lib/lsp/client.ts +1 -1
- package/src/lib/lsp/server-config.ts +1 -0
- package/src/opencode/files.ts +1 -0
- package/src/talk/policy.ts +4 -4
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.690",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Custom pi coding-agent extensions: bwrap sandbox, workspace guard, opencode edit, and more",
|
|
6
6
|
"keywords": [
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"eslint-plugin-import-x": "^4.17.1",
|
|
54
54
|
"eslint-plugin-promise": "7.3.0",
|
|
55
55
|
"eslint-plugin-simple-import-sort": "14.0.0",
|
|
56
|
-
"eslint-plugin-unicorn": "
|
|
56
|
+
"eslint-plugin-unicorn": "77.0.0",
|
|
57
57
|
"eslint-plugin-unused-imports": "4.4.1",
|
|
58
58
|
"husky": "^9.1.7",
|
|
59
59
|
"jiti": "^2.7.0",
|
|
@@ -85,7 +85,8 @@ function killHolder(pid: number | undefined): void {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
/** 轮询等待进程退出(进程消失即返回)。 */
|
|
88
|
-
async function waitForExit(pid: number
|
|
88
|
+
async function waitForExit(pid: number): Promise<void> {
|
|
89
|
+
const timeoutMs = 2000;
|
|
89
90
|
const deadline = Date.now() + timeoutMs;
|
|
90
91
|
while (Date.now() < deadline) {
|
|
91
92
|
try {
|
package/src/claude-code/grep.ts
CHANGED
|
@@ -36,7 +36,8 @@ const VCS_DIRECTORIES_TO_EXCLUDE = [".git", ".svn", ".hg", ".bzr", ".jj", ".sl"]
|
|
|
36
36
|
*/
|
|
37
37
|
const DEFAULT_HEAD_LIMIT = 250;
|
|
38
38
|
|
|
39
|
-
function truncateOutput(output: string
|
|
39
|
+
function truncateOutput(output: string): string {
|
|
40
|
+
const maxCharacters = 30_000;
|
|
40
41
|
if (output.length <= maxCharacters) {
|
|
41
42
|
return output;
|
|
42
43
|
}
|
package/src/claude-code/shell.ts
CHANGED
|
@@ -108,6 +108,7 @@ function formatBashSuccess(result: Awaited<ReturnType<BwrapRuntime["execute"]>>)
|
|
|
108
108
|
content: { type: "text"; text: string }[];
|
|
109
109
|
details: BashToolDetails | undefined;
|
|
110
110
|
} {
|
|
111
|
+
// eslint-disable-next-line unicorn/prefer-default-parameters -- output 是 string,空输出需显示 "(no output)",默认参数只覆盖 undefined
|
|
111
112
|
const { output, truncation, fullOutputPath } = result;
|
|
112
113
|
const text = appendTruncationNotice(output || "(no output)", truncation, fullOutputPath);
|
|
113
114
|
return {
|
package/src/codemode/worker.js
CHANGED
|
@@ -8903,15 +8903,20 @@ function parseWrites(json) {
|
|
|
8903
8903
|
return emptyWrites();
|
|
8904
8904
|
}
|
|
8905
8905
|
}
|
|
8906
|
-
function scriptError(payload
|
|
8906
|
+
function scriptError(payload) {
|
|
8907
8907
|
if (payload === void 0) {
|
|
8908
|
-
return { kind, message: "the script failed without an error message" };
|
|
8908
|
+
return { kind: "script", message: "the script failed without an error message" };
|
|
8909
8909
|
}
|
|
8910
8910
|
try {
|
|
8911
8911
|
const parsed = JSON.parse(payload);
|
|
8912
|
-
return {
|
|
8912
|
+
return {
|
|
8913
|
+
kind: "script",
|
|
8914
|
+
name: parsed.name,
|
|
8915
|
+
message: parsed.message ?? payload,
|
|
8916
|
+
stack: parsed.stack
|
|
8917
|
+
};
|
|
8913
8918
|
} catch {
|
|
8914
|
-
return { kind, message: payload };
|
|
8919
|
+
return { kind: "script", message: payload };
|
|
8915
8920
|
}
|
|
8916
8921
|
}
|
|
8917
8922
|
async function runScript(wasm, start) {
|
|
@@ -8966,7 +8971,7 @@ async function runScript(wasm, start) {
|
|
|
8966
8971
|
post({
|
|
8967
8972
|
t: "done",
|
|
8968
8973
|
ok: false,
|
|
8969
|
-
error: scriptError(b === void 0 ? void 0 : b.toString()
|
|
8974
|
+
error: scriptError(b === void 0 ? void 0 : b.toString()),
|
|
8970
8975
|
writes
|
|
8971
8976
|
});
|
|
8972
8977
|
}
|
|
@@ -9034,8 +9039,7 @@ async function runScript(wasm, start) {
|
|
|
9034
9039
|
t: "done",
|
|
9035
9040
|
ok: false,
|
|
9036
9041
|
error: scriptError(
|
|
9037
|
-
JSON.stringify({ name: error.name, message: error.message, stack: error.stack })
|
|
9038
|
-
"script"
|
|
9042
|
+
JSON.stringify({ name: error.name, message: error.message, stack: error.stack })
|
|
9039
9043
|
),
|
|
9040
9044
|
writes: emptyWrites()
|
|
9041
9045
|
});
|
package/src/codemode/worker.ts
CHANGED
|
@@ -69,15 +69,20 @@ function parseWrites(json: string): StoreWrites {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
/** 把 prelude 的 error 描述 JSON 转成可上报的错误。 */
|
|
72
|
-
function scriptError(payload: string | undefined
|
|
72
|
+
function scriptError(payload: string | undefined): ScriptError {
|
|
73
73
|
if (payload === undefined) {
|
|
74
|
-
return { kind, message: "the script failed without an error message" };
|
|
74
|
+
return { kind: "script", message: "the script failed without an error message" };
|
|
75
75
|
}
|
|
76
76
|
try {
|
|
77
77
|
const parsed = JSON.parse(payload) as { name?: string; message?: string; stack?: string };
|
|
78
|
-
return {
|
|
78
|
+
return {
|
|
79
|
+
kind: "script",
|
|
80
|
+
name: parsed.name,
|
|
81
|
+
message: parsed.message ?? payload,
|
|
82
|
+
stack: parsed.stack,
|
|
83
|
+
};
|
|
79
84
|
} catch {
|
|
80
|
-
return { kind, message: payload };
|
|
85
|
+
return { kind: "script", message: payload };
|
|
81
86
|
}
|
|
82
87
|
}
|
|
83
88
|
|
|
@@ -150,7 +155,7 @@ async function runScript(wasm: object, start: Extract<HostMessage, { t: "start"
|
|
|
150
155
|
post({
|
|
151
156
|
t: "done",
|
|
152
157
|
ok: false,
|
|
153
|
-
error: scriptError(b === undefined ? undefined : b.toString()
|
|
158
|
+
error: scriptError(b === undefined ? undefined : b.toString()),
|
|
154
159
|
writes,
|
|
155
160
|
});
|
|
156
161
|
}
|
|
@@ -229,7 +234,6 @@ async function runScript(wasm: object, start: Extract<HostMessage, { t: "start"
|
|
|
229
234
|
ok: false,
|
|
230
235
|
error: scriptError(
|
|
231
236
|
JSON.stringify({ name: error.name, message: error.message, stack: error.stack }),
|
|
232
|
-
"script",
|
|
233
237
|
),
|
|
234
238
|
writes: emptyWrites(),
|
|
235
239
|
});
|
package/src/gh/schemas.ts
CHANGED
|
@@ -16,14 +16,16 @@ import { Type } from "typebox";
|
|
|
16
16
|
/** GitHub 的 actor(author / assignee / mergedBy / review 作者)。 */
|
|
17
17
|
export const ghActorSchema = Type.Object({
|
|
18
18
|
login: Type.Optional(Type.String()),
|
|
19
|
-
name
|
|
19
|
+
// `user.name` 是 `string | null`:没有显示名的账号返回 null
|
|
20
|
+
name: Type.Optional(Type.Union([Type.String(), Type.Null()])),
|
|
20
21
|
is_bot: Type.Optional(Type.Boolean()),
|
|
21
22
|
});
|
|
22
23
|
|
|
23
24
|
export const ghLabelSchema = Type.Object({
|
|
24
25
|
name: Type.String(),
|
|
25
26
|
color: Type.Optional(Type.String()),
|
|
26
|
-
description:
|
|
27
|
+
// 没有描述的 label 是 `"description": null`(不是缺字段),所以既要 optional 也要 nullable
|
|
28
|
+
description: Type.Optional(Type.Union([Type.String(), Type.Null()])),
|
|
27
29
|
});
|
|
28
30
|
|
|
29
31
|
export const ghMilestoneSchema = Type.Object({
|
package/src/lib/lsp/client.ts
CHANGED
|
@@ -1466,7 +1466,7 @@ export async function create(input: CreateInput): Promise<LspClient> {
|
|
|
1466
1466
|
const toPaths = (locations: { uri: string }[] | null): Set<string> =>
|
|
1467
1467
|
new Set(
|
|
1468
1468
|
(locations ?? []).flatMap((location) =>
|
|
1469
|
-
location.uri.startsWith("file:") ?
|
|
1469
|
+
location.uri.startsWith("file:") ? normalize(fileURLToPath(location.uri)) : [],
|
|
1470
1470
|
),
|
|
1471
1471
|
);
|
|
1472
1472
|
|
|
@@ -112,6 +112,7 @@ function resolveTemplate(template: string, root: string, cwd: string): string {
|
|
|
112
112
|
const envVarPattern = /\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\}/g;
|
|
113
113
|
|
|
114
114
|
function interpolateEnvVars(value: string, env: NodeJS.ProcessEnv): string {
|
|
115
|
+
// eslint-disable-next-line unicorn/prefer-default-parameters -- replaceAll 回调参数被上下文的 ...args: any[] 定成 any,默认参数无法保留 string 注解
|
|
115
116
|
return value.replaceAll(envVarPattern, (_match, name: string, fallback?: string) => {
|
|
116
117
|
const resolved = env[name];
|
|
117
118
|
return resolved !== undefined && resolved !== "" ? resolved : (fallback ?? "");
|
package/src/opencode/files.ts
CHANGED
|
@@ -446,6 +446,7 @@ 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
|
|
449
450
|
const { filePath: rawPath, offset, limit } = params;
|
|
450
451
|
|
|
451
452
|
const absolutePath = isAbsolute(rawPath) ? rawPath : resolvePath(ctx.cwd, rawPath);
|
package/src/talk/policy.ts
CHANGED
|
@@ -30,7 +30,7 @@ export class OutboundPolicy {
|
|
|
30
30
|
* definition worked through what it was handed). `target` scopes the
|
|
31
31
|
* identical-body dedupe to a single peer (loop-breaking).
|
|
32
32
|
*/
|
|
33
|
-
check(body: string, unreadBacklog: number, target
|
|
33
|
+
check(body: string, unreadBacklog: number, target = ""): OutboundVerdict {
|
|
34
34
|
if (body.length > MAX_BODY_CHARS) {
|
|
35
35
|
return {
|
|
36
36
|
ok: false,
|
|
@@ -44,7 +44,7 @@ export class OutboundPolicy {
|
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
46
|
const now = this.now();
|
|
47
|
-
const dedupeKey = `${body}\u0000${target
|
|
47
|
+
const dedupeKey = `${body}\u0000${target}`;
|
|
48
48
|
const lastSame = this.recentBodies.get(dedupeKey);
|
|
49
49
|
if (lastSame !== undefined && now - lastSame < DEDUPE_WINDOW_MS) {
|
|
50
50
|
return {
|
|
@@ -66,9 +66,9 @@ export class OutboundPolicy {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
/** Record a successful send so dedupe/rate state stays current. */
|
|
69
|
-
recordSend(body: string, target
|
|
69
|
+
recordSend(body: string, target = ""): void {
|
|
70
70
|
this.sentAt.push(this.now());
|
|
71
|
-
this.recentBodies.set(`${body}\u0000${target
|
|
71
|
+
this.recentBodies.set(`${body}\u0000${target}`, this.now());
|
|
72
72
|
// bound the dedupe map
|
|
73
73
|
if (this.recentBodies.size <= 200) {
|
|
74
74
|
return;
|