@trim21/personal-pi-extensions 0.1.595 → 0.1.597

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.595",
3
+ "version": "0.1.597",
4
4
  "type": "module",
5
5
  "description": "Custom pi coding-agent extensions: bwrap sandbox, workspace guard, opencode edit, and more",
6
6
  "keywords": [
@@ -13,7 +13,6 @@
13
13
  },
14
14
  "files": [
15
15
  "src",
16
- "vendor",
17
16
  "README.md"
18
17
  ],
19
18
  "publishConfig": {
package/src/bwrap/core.ts CHANGED
@@ -3,7 +3,6 @@ import { constants, type Dirent, existsSync, readFileSync } from "node:fs";
3
3
  import { access as fsAccess, readdir, realpath, stat } from "node:fs/promises";
4
4
  import { delimiter, join } from "node:path";
5
5
  import process from "node:process";
6
- import { fileURLToPath } from "node:url";
7
6
 
8
7
  import { StringEnum } from "@earendil-works/pi-ai";
9
8
  import { type BashOperations, getAgentDir, getShellConfig } from "@earendil-works/pi-coding-agent";
@@ -266,28 +265,16 @@ function findCommandInPath(name: string, hint: string): string {
266
265
  throw new Error(hint);
267
266
  }
268
267
 
269
- // npm 包内自带的静态编译 mihomo(linux-x64),发布时由 CI 下载到 vendor/;
270
- // 源码方式运行(vendor 不存在)时自然跳过,走 PATH 查找。
271
- const VENDORED_MIHOMO_PATH = fileURLToPath(
272
- new URL("../../vendor/mihomo-linux-x64", import.meta.url),
273
- );
274
-
275
- export function findMihomo(override?: string, bundledPath = VENDORED_MIHOMO_PATH): string {
268
+ export function findMihomo(override?: string): string {
276
269
  if (override) {
277
270
  if (!existsSync(override)) {
278
271
  throw new Error(`mihomo not found at configured path: ${override}`);
279
272
  }
280
273
  return override;
281
274
  }
282
- // 优先全局 PATH(用户自装的 mihomo),没有时回退到包内自带二进制
283
- for (const directory of (process.env.PATH ?? "").split(delimiter)) {
284
- const candidate = join(directory, "mihomo");
285
- if (existsSync(candidate)) return candidate;
286
- }
287
- if (existsSync(bundledPath)) return bundledPath;
288
- throw new Error(
289
- "mihomo not found in PATH and the package ships no bundled binary. " +
290
- "Install it from https://github.com/MetaCubeX/mihomo",
275
+ return findCommandInPath(
276
+ "mihomo",
277
+ "mihomo not found in PATH. Install it from https://github.com/MetaCubeX/mihomo",
291
278
  );
292
279
  }
293
280
 
package/src/gh/base.ts CHANGED
@@ -151,11 +151,11 @@ export function runGh(
151
151
  resolve({
152
152
  stdout,
153
153
  stderr,
154
- // When killed by a signal the close event's code is null; report the
155
- // process as failed instead of pretending it succeeded. -1 is a
156
- // sentinel for "did not exit normally" — distinct from a real gh
157
- // failure exit code (1), which is always in 0-255.
158
- code: code ?? (killed ? -1 : 0),
154
+ // When killed by a signal the close event's code is null — including
155
+ // kills we did not initiate. Report failure instead of pretending it
156
+ // succeeded. -1 is a sentinel for "did not exit normally" — distinct
157
+ // from a real gh failure exit code (1), which is always in 0-255.
158
+ code: code ?? -1,
159
159
  killed,
160
160
  combined: combined.join(""),
161
161
  reason: killReason,
@@ -309,11 +309,19 @@ export function truncate(
309
309
  out.push(line);
310
310
  bytes += lineBytes;
311
311
  }
312
- return { text: out.join("\n"), truncated: true };
312
+ if (out.length > 0) return { text: out.join("\n"), truncated: true };
313
+
314
+ // 首行自己就超过 maxBytes(如单行超长文本):保底保留字节前缀,
315
+ // 不能把非空输出截成空字符串。
316
+ return {
317
+ text: Buffer.from(text, "utf8").subarray(0, maxBytes).toString("utf8"),
318
+ truncated: true,
319
+ };
313
320
  }
314
321
 
315
322
  /**
316
- * Format a successful gh invocation's stdout into a tool result.
323
+ * Format a successful gh invocation's text stdout into a tool result,
324
+ * line-truncated. JSON output must go through `toToolResultJson` instead.
317
325
  * Failures are thrown by `ghExec` as `GhError`, so only the success path lives here.
318
326
  */
319
327
  export function toToolResult(
@@ -330,6 +338,19 @@ export function toToolResult(
330
338
  };
331
339
  }
332
340
 
341
+ /**
342
+ * Format a successful gh invocation's JSON stdout into a tool result, passed
343
+ * through whole. Line-based truncation must not touch JSON: it would cut the
344
+ * payload into invalid JSON, and since `gh --json` prints one line, any
345
+ * over-budget payload used to be blanked entirely.
346
+ */
347
+ export function toToolResultJson(json: string, input?: unknown): ToolResult {
348
+ return {
349
+ content: [{ type: "text", text: json }],
350
+ details: { ...(input !== undefined && { input }), truncated: false },
351
+ };
352
+ }
353
+
333
354
  /**
334
355
  * Pendant subtitle for a tool result: `repo=x/y` (when provided) plus the
335
356
  * tool's id parameter, e.g. `repo=x/y number=123`. Returns undefined when
@@ -9,7 +9,7 @@ import {
9
9
  type ToolCall,
10
10
  type ToolResult,
11
11
  toPositiveId,
12
- toToolResult,
12
+ toToolResultJson,
13
13
  } from "../base.js";
14
14
 
15
15
  interface RunIdParams {
@@ -25,7 +25,7 @@ async function workflowJobs(gh: GhClient, call: ToolCall<RunIdParams>): Promise<
25
25
  const { owner, repo: name } = splitRepo(effectiveRepo);
26
26
 
27
27
  const jobs = await gh.checks.runJobs(owner, name, runId, signal);
28
- const result = toToolResult(JSON.stringify({ total_count: jobs.length, jobs }), params);
28
+ const result = toToolResultJson(JSON.stringify({ total_count: jobs.length, jobs }), params);
29
29
  result.details.pendant = subtitlePendant(params, "run_id");
30
30
  return result;
31
31
  }
@@ -1,7 +1,7 @@
1
1
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
2
  import { Type } from "typebox";
3
3
 
4
- import { type GhClient, ghExec, repoArgs, subtitlePendant, toToolResult } from "../base.js";
4
+ import { type GhClient, ghExec, repoArgs, subtitlePendant, toToolResultJson } from "../base.js";
5
5
 
6
6
  export function addReadIssueCommentsTool(_gh: GhClient, pi: ExtensionAPI) {
7
7
  pi.registerTool({
@@ -15,7 +15,7 @@ export function addReadIssueCommentsTool(_gh: GhClient, pi: ExtensionAPI) {
15
15
  }),
16
16
  async execute(_id, params, signal, _onUpdate, ctx) {
17
17
  const { number, repo } = params;
18
- const result = toToolResult(
18
+ const result = toToolResultJson(
19
19
  await ghExec(["issue", "view", String(number), ...repoArgs(repo), "--json", "comments"], {
20
20
  cwd: ctx.cwd,
21
21
  signal,
@@ -1,7 +1,7 @@
1
1
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
2
  import { Type } from "typebox";
3
3
 
4
- import { type GhClient, ghExec, repoArgs, subtitlePendant, toToolResult } from "../base.js";
4
+ import { type GhClient, ghExec, repoArgs, subtitlePendant, toToolResultJson } from "../base.js";
5
5
 
6
6
  export function addReadIssueTool(_gh: GhClient, pi: ExtensionAPI) {
7
7
  pi.registerTool({
@@ -15,7 +15,7 @@ export function addReadIssueTool(_gh: GhClient, pi: ExtensionAPI) {
15
15
  }),
16
16
  async execute(_id, params, signal, _onUpdate, ctx) {
17
17
  const { number, repo } = params;
18
- const result = toToolResult(
18
+ const result = toToolResultJson(
19
19
  await ghExec(
20
20
  [
21
21
  "issue",
@@ -8,7 +8,7 @@ import {
8
8
  repoArgs,
9
9
  resolveRepo,
10
10
  subtitlePendant,
11
- truncate,
11
+ toToolResultJson,
12
12
  } from "../base.js";
13
13
 
14
14
  export function addReadPrCommentsTool(_gh: GhClient, pi: ExtensionAPI) {
@@ -65,12 +65,9 @@ export function addReadPrCommentsTool(_gh: GhClient, pi: ExtensionAPI) {
65
65
  },
66
66
  );
67
67
  }
68
- const { text, truncated } = truncate(out);
69
- const pendant = subtitlePendant(params, "number");
70
- return {
71
- content: [{ type: "text", text }],
72
- details: { input: params, truncated, ...(pendant && { pendant }) },
73
- };
68
+ const result = toToolResultJson(out, params);
69
+ result.details.pendant = subtitlePendant(params, "number");
70
+ return result;
74
71
  },
75
72
  });
76
73
  }
@@ -1,7 +1,7 @@
1
1
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
2
  import { Type } from "typebox";
3
3
 
4
- import { type GhClient, ghExec, repoArgs, subtitlePendant, toToolResult } from "../base.js";
4
+ import { type GhClient, ghExec, repoArgs, subtitlePendant, toToolResultJson } from "../base.js";
5
5
 
6
6
  export function addReadPrTool(_gh: GhClient, pi: ExtensionAPI) {
7
7
  pi.registerTool({
@@ -15,7 +15,7 @@ export function addReadPrTool(_gh: GhClient, pi: ExtensionAPI) {
15
15
  }),
16
16
  async execute(_id, params, signal, _onUpdate, ctx) {
17
17
  const { number, repo } = params;
18
- const result = toToolResult(
18
+ const result = toToolResultJson(
19
19
  await ghExec(
20
20
  [
21
21
  "pr",
@@ -1,4 +0,0 @@
1
- [diffend] Oversized file quarantined before diffing.
2
- name: package/vendor/mihomo-linux-x64
3
- size: 61825150 bytes
4
- sha256: 08787faafea19c1ab0f83fa5a1b22363b7d03ea78da18091a4c883aecaaa5979