@trim21/personal-pi-extensions 0.0.299 → 0.0.300

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.
@@ -1,116 +0,0 @@
1
- /**
2
- * Enhanced Write Tool Extension
3
- *
4
- * Aligned with opencode commit 999be62662 (v1.2.25-1672-g999be62662, 2026-08-12):
5
- * https://github.com/anomalyco/opencode/blob/999be62662/packages/opencode/src/tool/write.ts
6
- * Aligned behaviours: BOM preservation (source.bom || next.bom).
7
- * Known gaps (intentionally not implemented): LSP diagnostics in the result,
8
- * formatter run. Unlike opencode (which has no write lock), this extension
9
- * serialises writes via the mutation queue.
10
- *
11
- * Overrides the built-in `write` tool with opencode-compatible parameter names.
12
- *
13
- * - Uses `filePath` (opencode) instead of `path` (pi built-in)
14
- * - Creates parent directories automatically
15
- * - Serialises writes to the same file via mutation queue
16
- *
17
- * Install:
18
- * cp enhanced-write.ts ~/.pi/agent/extensions/
19
- *
20
- * Or for project-local:
21
- * cp enhanced-write.ts .pi/extensions/
22
- */
23
-
24
- import { mkdir, open, writeFile } from "node:fs/promises";
25
- import { dirname, resolve as resolvePath } from "node:path";
26
-
27
- import { type ExtensionAPI, withFileMutationQueue } from "@earendil-works/pi-coding-agent";
28
- import { Type } from "typebox";
29
-
30
- import { guardWriteAccess } from "../lib/write-guard.js";
31
- import { stripBom } from "./edit-engine.js";
32
-
33
- /**
34
- * opencode: desiredBom = source.bom || next.bom —— 优先保留原文件 BOM,
35
- * 否则用新内容自带的 BOM。
36
- * @param existing - 旧文件前几个字节(undefined 表示文件不存在)
37
- * @param content - 要写入的完整内容
38
- */
39
- export function resolveBom(
40
- existing: Buffer | undefined,
41
- content: string,
42
- ): { bom: string; text: string } {
43
- const sourceBom =
44
- existing !== undefined &&
45
- existing.length >= 3 &&
46
- existing[0] === 0xef &&
47
- existing[1] === 0xbb &&
48
- existing[2] === 0xbf
49
- ? "\uFEFF"
50
- : "";
51
- const { bom: nextBom, text } = stripBom(content);
52
- return { bom: sourceBom || nextBom, text };
53
- }
54
-
55
- export default function opencodeWrite(pi: ExtensionAPI) {
56
- pi.registerTool({
57
- name: "write",
58
- label: "write",
59
- description:
60
- "Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.",
61
- promptSnippet: "Create or overwrite files",
62
- promptGuidelines: ["Use write only for new files or complete rewrites."],
63
- parameters: Type.Object({
64
- filePath: Type.String({
65
- description: "The absolute path to the file to write (must be absolute, not relative)",
66
- }),
67
- content: Type.String({ description: "The content to write to the file" }),
68
- }),
69
- async execute(_toolCallId, params, signal, _onUpdate, ctx) {
70
- const { filePath: rawPath, content } = params;
71
- const absolutePath = resolvePath(ctx.cwd, rawPath);
72
- await guardWriteAccess(ctx, {
73
- toolName: "write",
74
- absolutePath,
75
- change: { oldText: "", newText: content },
76
- });
77
- const dir = dirname(absolutePath);
78
-
79
- const throwIfAborted = () => {
80
- if (signal?.aborted) throw new Error("Operation aborted");
81
- };
82
-
83
- return withFileMutationQueue(absolutePath, async () => {
84
- throwIfAborted();
85
-
86
- // opencode: desiredBom = source.bom || next.bom —— 保留原文件 BOM,
87
- // 否则用新内容自带的 BOM
88
- let existing: Buffer | undefined;
89
- try {
90
- const fh = await open(absolutePath, "r");
91
- try {
92
- existing = Buffer.alloc(3);
93
- const { bytesRead } = await fh.read(existing, 0, 3, 0);
94
- if (bytesRead < 3) existing = undefined;
95
- } finally {
96
- await fh.close();
97
- }
98
- } catch {
99
- // 文件不存在:无旧 BOM
100
- }
101
- throwIfAborted();
102
- const { bom: desiredBom, text: nextText } = resolveBom(existing, content);
103
-
104
- await mkdir(dir, { recursive: true });
105
- throwIfAborted();
106
- await writeFile(absolutePath, desiredBom + nextText, "utf8");
107
- throwIfAborted();
108
-
109
- return {
110
- content: [{ type: "text", text: "Wrote file successfully." }],
111
- details: undefined,
112
- };
113
- });
114
- },
115
- });
116
- }