@trim21/personal-pi-extensions 0.0.300 → 0.0.301

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.0.300",
3
+ "version": "0.0.301",
4
4
  "type": "module",
5
5
  "description": "Custom pi coding-agent extensions: bwrap sandbox, workspace guard, opencode edit, and more",
6
6
  "keywords": [
@@ -35,7 +35,7 @@ export interface PreviewExtract {
35
35
  truncated: boolean;
36
36
  }
37
37
 
38
- /** AFT preview diff 条目:`include_diff_content` 时带 before/after,>512KB 只带 truncated。 */
38
+ /** AFT preview diff 条目:preview 模式下默认带 before/after,>512KB 只带 truncated。 */
39
39
  const previewDiffSchema = Type.Object({
40
40
  before: Type.Optional(Type.String()),
41
41
  after: Type.Optional(Type.String()),
@@ -232,12 +232,11 @@ export function registerAstEditTool(pi: ExtensionAPI, ctx: AftToolContext): void
232
232
  const rawArgs = buildWireArgs(params, filePath);
233
233
 
234
234
  // 第一步:preview(不写盘)拿所有变动文件的 before/after,供写保护审批。
235
- const { response } = await callAftTool(
236
- bridgeFor(ctx),
237
- "edit",
238
- { ...rawArgs, preview: true, include_diff_content: true },
239
- extCtx,
240
- );
235
+ // preview 必须经 options 传入(bridge 会放到 tool_call 消息顶层),
236
+ // 放进 arguments 会被 AFT 忽略并真的写盘。
237
+ const { response } = await callAftTool(bridgeFor(ctx), "edit", rawArgs, extCtx, {
238
+ preview: true,
239
+ });
241
240
  const { files: previewFiles, truncated } = extractPreviewFiles(response);
242
241
  if (truncated) {
243
242
  throw new Error("ast_edit: file too large for preview (over 512KB)");
package/src/aft/bridge.ts CHANGED
@@ -7,8 +7,6 @@
7
7
  * aft-bridge 锁一致就不会走到最后的网络下载。
8
8
  */
9
9
 
10
- import { createRequire } from "node:module";
11
-
12
10
  import {
13
11
  type AftProjectTransport,
14
12
  type AftTransportPool,
@@ -22,16 +20,6 @@ import {
22
20
  } from "@cortexkit/aft-bridge";
23
21
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
24
22
 
25
- /** aft-bridge 包自身版本,作为二进制版本匹配基准。 */
26
- const BRIDGE_VERSION: string = (() => {
27
- try {
28
- const req = createRequire(import.meta.url);
29
- return (req("@cortexkit/aft-bridge/package.json") as { version?: string }).version ?? "0.0.0";
30
- } catch {
31
- return "0.0.0";
32
- }
33
- })();
34
-
35
23
  /** Pi 会话 ID:Rust 侧用它做 session 作用域(undo/checkpoint),感知工具可留空。 */
36
24
  export function resolveSessionId(extCtx: ExtensionContext): string | undefined {
37
25
  const manager = (extCtx as unknown as { sessionManager?: { getSessionId?: () => string } })
@@ -40,9 +28,14 @@ export function resolveSessionId(extCtx: ExtensionContext): string | undefined {
40
28
  return typeof id === "string" && id.length > 0 ? id : undefined;
41
29
  }
42
30
 
43
- /** 解析 aft 二进制;失败时抛出(调用方决定是否降级不注册工具)。 */
31
+ /**
32
+ * 解析 aft 二进制;失败时抛出(调用方决定是否降级不注册工具)。
33
+ * 不带版本参数:findBinary 内部用 @cortexkit/aft-bridge 自身版本作为匹配基准,
34
+ * 与 npm 平台包(@cortexkit/aft-<platform>)精确对齐,避免手动读 package.json
35
+ * (其 exports 不暴露 ./package.json)。
36
+ */
44
37
  export async function resolveAftBinary(): Promise<string> {
45
- const path = await findBinary(BRIDGE_VERSION);
38
+ const path = await findBinary();
46
39
  if (!path) {
47
40
  throw new Error(
48
41
  "AFT binary not found. Install via npm platform package (@cortexkit/aft-<platform>), cargo install agent-file-tools, or place `aft` on PATH.",
@@ -64,7 +57,7 @@ export async function createAftPool(cwd: string): Promise<AftPool> {
64
57
  const pool = await createAftTransportPool({
65
58
  harness: "pi",
66
59
  binaryPath,
67
- poolOptions: { minVersion: BRIDGE_VERSION },
60
+ poolOptions: {},
68
61
  configOverrides: {
69
62
  storage_dir: resolveCortexKitStorageRoot(),
70
63
  cortexkit_user_config_path: paths.userConfigPath,
@@ -85,7 +78,7 @@ export async function callAftTool(
85
78
  command: string,
86
79
  rawArgs: Record<string, unknown>,
87
80
  extCtx: ExtensionContext,
88
- options?: BridgeRequestOptions,
81
+ options?: BridgeRequestOptions & { preview?: boolean },
89
82
  softCodes?: ReadonlySet<string>,
90
83
  ): Promise<{ text: string; response: Record<string, unknown> }> {
91
84
  const timeoutMs = timeoutForCommand(command);
@@ -144,9 +144,13 @@ function containsPath(file: string, cwd: string): boolean {
144
144
 
145
145
  /**
146
146
  * 创建 LSP 服务实例。state 由闭包持有;adapters 可注入(测试传 [] 或
147
- * mock adapters 即可隔离真实服务器)。
147
+ * mock adapters 即可隔离真实服务器)。globalConfigPath 供测试注入
148
+ * 固定的全局配置路径,避免被本机 ~/.pi/agent/lsp.json 影响。
148
149
  */
149
- export function createLspService(adapters: LspServerAdapter[] = createAdapters()): LspService {
150
+ export function createLspService(
151
+ adapters: LspServerAdapter[] = createAdapters(),
152
+ globalConfigPath?: string,
153
+ ): LspService {
150
154
  const state: LspState = {
151
155
  clients: [],
152
156
  adapters,
@@ -156,7 +160,7 @@ export function createLspService(adapters: LspServerAdapter[] = createAdapters()
156
160
 
157
161
  async function getClients(file: string, cwd: string): Promise<LspClient[]> {
158
162
  if (!containsPath(file, cwd)) return [];
159
- const config = await loadLspConfig(cwd);
163
+ const config = await loadLspConfig(cwd, globalConfigPath);
160
164
  const timeout = timeoutOptions(config);
161
165
  const adapters = filterAdapters(state.adapters, config);
162
166
  const extension = extname(file) || file;