@trim21/personal-pi-extensions 0.1.560 → 0.1.561

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.560",
3
+ "version": "0.1.561",
4
4
  "type": "module",
5
5
  "description": "Custom pi coding-agent extensions: bwrap sandbox, workspace guard, opencode edit, and more",
6
6
  "keywords": [
@@ -115,23 +115,35 @@ export class BashInterruptedError extends Error {
115
115
  readonly kind: "timeout" | "aborted";
116
116
  readonly partial: BashExecutionPartial;
117
117
  readonly sandboxHint: string | undefined;
118
+ /**
119
+ * 命令实际运行时长(毫秒):从审批结束、命令真正开始执行算到终止,
120
+ * 不含审批弹窗等用户 UI 交互耗时。
121
+ */
122
+ readonly elapsedMs: number;
118
123
 
119
124
  constructor(
120
125
  kind: "timeout" | "aborted",
121
126
  message: string,
122
127
  partial: BashExecutionPartial,
123
128
  sandboxHint: string | undefined,
129
+ elapsedMs: number,
124
130
  cause: unknown,
125
131
  ) {
126
132
  super(message, { cause });
127
133
  this.kind = kind;
128
134
  this.partial = partial;
129
135
  this.sandboxHint = sandboxHint;
136
+ this.elapsedMs = elapsedMs;
130
137
  // 对齐标准错误分类:中断=AbortError(用户取消),超时=TimeoutError
131
138
  this.name = kind === "aborted" ? "AbortError" : "TimeoutError";
132
139
  }
133
140
  }
134
141
 
142
+ /** 命令运行时长的展示文案(秒,一位小数),超时/中断状态文本共用。 */
143
+ export function formatElapsedSeconds(elapsedMs: number): string {
144
+ return `${(elapsedMs / 1000).toFixed(1)} seconds`;
145
+ }
146
+
135
147
  function escapeHtml(text: string): string {
136
148
  return text
137
149
  .replaceAll("&", "&")
@@ -425,6 +437,8 @@ export class BwrapRuntime {
425
437
  }
426
438
  // 命令失败时附带的沙箱状态(写边界 + 网络层级),由上层拼进错误文本
427
439
  const sandboxHint = describeSandbox(runtime, local);
440
+ // 计时起点放在审批之后:审批弹窗的等待时长属于用户 UI 操作,不是命令运行时间
441
+ const startedAt = Date.now();
428
442
  await using output = new BashOutput(request.ctx.sessionManager.getSessionId());
429
443
  const { onUpdate } = request;
430
444
 
@@ -463,6 +477,7 @@ export class BwrapRuntime {
463
477
  truncation: partial.truncation,
464
478
  };
465
479
  } catch (error) {
480
+ const elapsedMs = Date.now() - startedAt;
466
481
  // 超时/中断:把命令终止前已捕获的输出附在错误上(文本 + 落盘路径),
467
482
  // 展示时输出在前、状态在最后(对齐 pi 内置 bash),避免只报超时丢输出
468
483
  // 超时识别:优先 name=TimeoutError(对齐标准错误分类),
@@ -477,6 +492,7 @@ export class BwrapRuntime {
477
492
  `Command timed out after ${error.message.slice("timeout:".length)} seconds`,
478
493
  partial,
479
494
  sandboxHint,
495
+ elapsedMs,
480
496
  error,
481
497
  );
482
498
  }
@@ -489,6 +505,7 @@ export class BwrapRuntime {
489
505
  "Command aborted by user",
490
506
  partial,
491
507
  sandboxHint,
508
+ elapsedMs,
492
509
  error,
493
510
  );
494
511
  }
@@ -14,6 +14,7 @@ import {
14
14
  BashInterruptedError,
15
15
  type BwrapRuntime,
16
16
  createBwrapRuntime,
17
+ formatElapsedSeconds,
17
18
  sandboxHintBlock,
18
19
  } from "../bwrap/runtime.js";
19
20
  import { resolveWorkdir } from "../lib/path.js";
@@ -152,9 +153,13 @@ export function registerShellTools(
152
153
  error.partial.fullOutputPath,
153
154
  );
154
155
  if (error.kind === "aborted") {
155
- // 用户取消:直接返回已捕获的输出,不抛错
156
- const full = text ? `${text}\n\nCommand aborted by user` : "Command aborted by user";
157
- return { content: [{ type: "text", text: full }], details: undefined };
156
+ // 用户取消:直接返回已捕获的输出,不抛错;时长只算命令真正运行的时间,
157
+ // 不含审批弹窗等 UI 交互
158
+ const status = `Command aborted by user after ${formatElapsedSeconds(error.elapsedMs)}`;
159
+ return {
160
+ content: [{ type: "text", text: text ? `${text}\n\n${status}` : status }],
161
+ details: undefined,
162
+ };
158
163
  }
159
164
  const full = text
160
165
  ? `${text}\n\nCommand timed out after ${timeout} milliseconds`
@@ -8,6 +8,7 @@ import {
8
8
  BashInterruptedError,
9
9
  type BwrapRuntime,
10
10
  createBwrapRuntime,
11
+ formatElapsedSeconds,
11
12
  sandboxHintBlock,
12
13
  } from "../bwrap/runtime.js";
13
14
  import { resolveWorkdir } from "../lib/path.js";
@@ -114,7 +115,7 @@ export default function opencodeBash(
114
115
  const status =
115
116
  error.kind === "timeout"
116
117
  ? `Command exceeded timeout of ${timeout} ms. Retry with a larger timeout if the command is expected to take longer.`
117
- : "Command aborted by user";
118
+ : `Command aborted by user after ${formatElapsedSeconds(error.elapsedMs)}`;
118
119
  const full = text ? `${text}\n\n${status}` : status;
119
120
  // 对齐上游 opencode:超时与中断都不抛错,输出与状态文本一起返回;
120
121
  // 超时可能是沙箱的网络限制导致的,附加沙箱状态(用户中断与沙箱无关)