@trim21/personal-pi-extensions 0.1.594 → 0.1.596

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.594",
3
+ "version": "0.1.596",
4
4
  "type": "module",
5
5
  "description": "Custom pi coding-agent extensions: bwrap sandbox, workspace guard, opencode edit, and more",
6
6
  "keywords": [
@@ -99,7 +99,7 @@
99
99
  "node": ">=24.14"
100
100
  },
101
101
  "dependencies": {
102
- "@cortexkit/aft-bridge": "0.55.1",
102
+ "@cortexkit/aft-bridge": "0.57.1",
103
103
  "@mozilla/readability": "^0.6.0",
104
104
  "@parcel/watcher": "^2.6.0",
105
105
  "@vscode/tree-sitter-wasm": "^0.3.1",
@@ -115,6 +115,6 @@
115
115
  "web-tree-sitter": "^0.27.0"
116
116
  },
117
117
  "optionalDependencies": {
118
- "@cortexkit/aft-linux-x64": "0.55.1"
118
+ "@cortexkit/aft-linux-x64": "0.57.1"
119
119
  }
120
120
  }
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",