@better-fs-tools/pi 0.1.0 → 0.2.0
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/README.md +15 -11
- package/dist/extension.js +3 -3
- package/dist/fs-tools.d.ts +15 -5
- package/dist/fs-tools.js +16 -13
- package/dist/index.d.ts +1 -1
- package/dist/mutation-tools.d.ts +1 -1
- package/dist/mutation-tools.js +1 -1
- package/dist/roots.d.ts +1 -1
- package/dist/tool.d.ts +8 -4
- package/dist/tool.js +11 -3
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @better-fs-tools/pi
|
|
2
2
|
|
|
3
|
-
Better FS Tools for the [Pi coding agent](https://www.npmjs.com/package/@earendil-works/pi-coding-agent). It replaces Pi's built-in `read`, `edit`, and `write` tools, and
|
|
3
|
+
Better FS Tools for the [Pi coding agent](https://www.npmjs.com/package/@earendil-works/pi-coding-agent). It replaces Pi's built-in `read`, `edit`, and `write` tools, and can add `apply_patch`. Every call is confined to the working directory of that call. A read store, so that `edit` and `write` need a read first, is opt-in.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -10,7 +10,7 @@ npm install @better-fs-tools/pi @better-fs-tools/read @better-fs-tools/write @ea
|
|
|
10
10
|
|
|
11
11
|
`@earendil-works/pi-coding-agent` (`^0.84.2`) and `typebox` (`^1.3.16`) are required peers. The package needs Node 24 or later.
|
|
12
12
|
|
|
13
|
-
The package has a `pi.extensions` entry. When Pi loads the package, the entry registers `read`, `edit`,
|
|
13
|
+
The package has a `pi.extensions` entry. When Pi loads the package, the entry registers `read`, `edit`, and `write` from `createPiFsTools()`, as Pi's own tools are. `read` returns images, as Pi's own `read` does. There is no read store, so `edit` and `write` do not check for a read first. Writes stay inside `ctx.cwd`. The entry writes no settings or session file.
|
|
14
14
|
|
|
15
15
|
## Example
|
|
16
16
|
|
|
@@ -19,13 +19,15 @@ To choose your own options, register the tools from your own extension:
|
|
|
19
19
|
```ts
|
|
20
20
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
21
21
|
import { createPiFsTools } from "@better-fs-tools/pi";
|
|
22
|
-
import { denyPaths, unicodeRepair } from "@better-fs-tools/read";
|
|
22
|
+
import { denyPaths, memoryStore, unicodeRepair } from "@better-fs-tools/read";
|
|
23
23
|
import { hashlineFormat } from "@better-fs-tools/read/formats";
|
|
24
24
|
import { protectPaths } from "@better-fs-tools/write";
|
|
25
25
|
|
|
26
26
|
export default function fsToolsExtension(pi: ExtensionAPI): void {
|
|
27
|
-
// Four tools with one read store, so edit and write need a read first.
|
|
27
|
+
// Four tools with one read store, so edit and write need a read first. The
|
|
28
|
+
// store and apply_patch are opt-in.
|
|
28
29
|
const tools = createPiFsTools({
|
|
30
|
+
state: memoryStore(),
|
|
29
31
|
read: {
|
|
30
32
|
resolve: unicodeRepair({ note: false }),
|
|
31
33
|
authorize: denyPaths(["**/.env", "**/.env.*"]),
|
|
@@ -69,14 +71,15 @@ export default function readExtension(pi: ExtensionAPI): void {
|
|
|
69
71
|
- `fs`, `cwd`, and `allowedRoots` throw `TypeError`. Each call reads through `nodeFileSystem` with Pi's `ctx.cwd` as the only allowed root. When the working directory changes between calls, the root changes too. The tool keeps the filesystems for the last 8 working directories.
|
|
70
72
|
- Pi's `ExtensionContext` is the host type. Host functions get it as `ctx.call.host`, for example `ctx.call.host.ui.confirm(...)` in `askUser`, or `ctx.call.host.sessionManager.getSessionId()` in a `state` factory.
|
|
71
73
|
- The default signature is `defaultReadSignature({ name: "read" })`. Its schema has integer `offset` and `limit`, so a model that sends `2.5` gets Pi's validation error. `digest` defaults to `nodeDigest()`.
|
|
74
|
+
- `converters` defaults to `[imageConverter()]`, as Pi's own `read` returns images. This holds for `createPiReadTool()`, `createPiFsTools()`, and the extension entry. A list you pass replaces the default, so `converters: []` turns images off, and a list without `imageConverter()` refuses images. In `createPiFsTools()` the option goes under `read`, for example `read: { converters: [] }`.
|
|
72
75
|
- Image parts become Pi `image` parts. Other media becomes a text part that says what was left out.
|
|
73
76
|
- `details.truncation` follows Pi's own read tool for line and byte stops. Its `content` comes from the formatter in `"view"` mode. For other results, or a formatter that returns parts, `details` is `{}`. `toPiReadDetails()` builds the details for your own tool.
|
|
74
77
|
|
|
75
78
|
## What the write tools do
|
|
76
79
|
|
|
77
|
-
- `createPiFsTools(options?)` wraps `createFsTools()` from `@better-fs-tools/write`. It builds `read`, `edit`,
|
|
78
|
-
- `createPiEditTool()`, `createPiWriteTool()`, and `createPiApplyPatchTool()` build one tool each. They default to `state: null`, so
|
|
79
|
-
- `fs`, `cwd`, and `allowedRoots` throw `TypeError`, as for the read tool. Writes go through `nodeFileSystem` with `ctx.cwd` as the only allowed root, and `hardLinks: "
|
|
80
|
+
- `createPiFsTools(options?)` wraps `createFsTools()` from `@better-fs-tools/write`. It builds `read`, `edit`, and `write` with one `nodeDigest()`, one lock manager, one clock, and one cache of filesystems over `ctx.cwd`. `applyPatch: true`, or an options object, adds `apply_patch`. `state` defaults to `null`, so read-before-write is off; `state: memoryStore()` turns it on. `digest` (default `nodeDigest()`), `locks`, `clock`, and the root options (`denyRoots`, `symlinks`, `hardLinks`, `newFileMode`, `newDirectoryMode`) are set once for all the tools. Each tool's other options go under `read`, `edit`, `write`, and `applyPatch`. The result also has `applyPatch` (`null` when off), `state`, `digest`, `locks`, `clock`, and `invalidate(path, call?)`, which returns an `InvalidateOutcome`. Pass the call, so the path resolves under its `ctx.cwd`: in a bash `afterRun` hook it is `ctx.call`. Without it the outcome is `{ ok: false }` with reason `unsupported`. An unknown top-level key, or `state`, `digest`, `locks`, `clock`, or a root option inside a tool's options, throws `TypeError`.
|
|
81
|
+
- `createPiEditTool()`, `createPiWriteTool()`, and `createPiApplyPatchTool()` build one tool each. They default to `state: null`, so read-before-write is off. Pass the same `state` as your read tool, or use `createPiFsTools()`.
|
|
82
|
+
- `fs`, `cwd`, and `allowedRoots` throw `TypeError`, as for the read tool. Writes go through `nodeFileSystem` with `ctx.cwd` as the only allowed root, and `hardLinks: "in-place"` by default: a file with more than one hard link is written through the link, not atomically. `hardLinks: "refuse"` fails that write with `DENIED`. `newFileMode` and `newDirectoryMode` set the modes of new files and directories exactly. Without them, a new file is `0o666` and a new directory `0o777`, less the process umask.
|
|
80
83
|
- The default signatures follow Pi's own tools: `edit` takes `path` and `edits: [{ oldText, newText }]` (`multiEditSignature({ name: "edit" })`), and `write` takes `path` and `content`. Their prompt snippets and guidelines are Pi's own, so the system prompt stays the same. `apply_patch` uses `freeformPatchSignature()`: models with grammar-tool support get the Codex patch grammar, and other models get the JSON schema.
|
|
81
84
|
- `edit` and `apply_patch` return `details` in the shape of Pi's `EditToolDetails` (`diff`, `patch`, `firstChangedLine`), so Pi's edit renderer draws the diff. `toPiMutationDetails()` builds them for your own tool. `write` returns no details, as Pi's own `write` does.
|
|
82
85
|
- A tool error becomes Pi content text. The tool does not throw for a tool error.
|
|
@@ -105,11 +108,13 @@ With the file tools, a bash `afterRun` hook can make the next edit of a file nee
|
|
|
105
108
|
```ts
|
|
106
109
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
107
110
|
import { createPiBashTool, createPiFsTools } from "@better-fs-tools/pi";
|
|
111
|
+
import { memoryStore } from "@better-fs-tools/read";
|
|
108
112
|
|
|
109
|
-
// The
|
|
110
|
-
// package.json needs a read, since the command may have
|
|
113
|
+
// The file tools with a read store, and Pi-shaped bash. After each command,
|
|
114
|
+
// the next edit of package.json needs a read, since the command may have
|
|
115
|
+
// changed it.
|
|
111
116
|
export default function fsAndBashExtension(pi: ExtensionAPI): void {
|
|
112
|
-
const tools = createPiFsTools();
|
|
117
|
+
const tools = createPiFsTools({ state: memoryStore() });
|
|
113
118
|
const bash = createPiBashTool({
|
|
114
119
|
afterRun: [
|
|
115
120
|
{
|
|
@@ -125,7 +130,6 @@ export default function fsAndBashExtension(pi: ExtensionAPI): void {
|
|
|
125
130
|
pi.registerTool(tools.read);
|
|
126
131
|
pi.registerTool(tools.edit);
|
|
127
132
|
pi.registerTool(tools.write);
|
|
128
|
-
pi.registerTool(tools.applyPatch);
|
|
129
133
|
pi.registerTool(bash);
|
|
130
134
|
}
|
|
131
135
|
```
|
package/dist/extension.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pi package extension entry. Installing the package into a Pi project
|
|
3
|
-
* registers read, edit, write,
|
|
4
|
-
*
|
|
3
|
+
* registers read, edit, and write, as Pi's own tools are, and nothing else.
|
|
4
|
+
* There is no read store, so edit and write do not check for a read first.
|
|
5
|
+
* read returns images, as Pi's own read does.
|
|
5
6
|
* Nothing is written outside the process: no settings file, no session file.
|
|
6
7
|
*/
|
|
7
8
|
import { createPiFsTools } from "./fs-tools.js";
|
|
@@ -10,5 +11,4 @@ export default function fsToolsExtension(pi) {
|
|
|
10
11
|
pi.registerTool(tools.read);
|
|
11
12
|
pi.registerTool(tools.edit);
|
|
12
13
|
pi.registerTool(tools.write);
|
|
13
|
-
pi.registerTool(tools.applyPatch);
|
|
14
14
|
}
|
package/dist/fs-tools.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type { PiRootOptions } from "./roots.ts";
|
|
|
6
6
|
import type { CreatePiReadToolOptions, PiReadTool } from "./tool.ts";
|
|
7
7
|
type BundleSharedKey = FsToolsSharedKey | keyof PiRootOptions;
|
|
8
8
|
export interface CreatePiFsToolsOptions extends PiRootOptions {
|
|
9
|
-
/** Default
|
|
9
|
+
/** Default null: no read-before-write. A store, for example memoryStore(), turns it on. */
|
|
10
10
|
readonly state?: ReadStateStore | null;
|
|
11
11
|
/** Default nodeDigest(). */
|
|
12
12
|
readonly digest?: Digest;
|
|
@@ -17,13 +17,15 @@ export interface CreatePiFsToolsOptions extends PiRootOptions {
|
|
|
17
17
|
readonly read?: Omit<CreatePiReadToolOptions, BundleSharedKey>;
|
|
18
18
|
readonly edit?: Omit<CreatePiEditToolOptions, BundleSharedKey>;
|
|
19
19
|
readonly write?: Omit<CreatePiWriteToolOptions, BundleSharedKey>;
|
|
20
|
-
|
|
20
|
+
/** Off by default. `true` or an options object adds an apply_patch tool. */
|
|
21
|
+
readonly applyPatch?: boolean | Omit<CreatePiApplyPatchToolOptions, BundleSharedKey>;
|
|
21
22
|
}
|
|
22
23
|
export interface PiFsTools {
|
|
23
24
|
readonly read: PiReadTool;
|
|
24
25
|
readonly edit: PiMutationTool;
|
|
25
26
|
readonly write: PiMutationTool;
|
|
26
|
-
|
|
27
|
+
/** null unless options.applyPatch is true or an object. */
|
|
28
|
+
readonly applyPatch: PiMutationTool | null;
|
|
27
29
|
readonly state: ReadStateStore | null;
|
|
28
30
|
/** options.digest, or nodeDigest(). */
|
|
29
31
|
readonly digest: Digest;
|
|
@@ -37,13 +39,21 @@ export interface PiFsTools {
|
|
|
37
39
|
*/
|
|
38
40
|
invalidate(path: string, call?: ToolCallContext<ExtensionContext>): Promise<InvalidateOutcome>;
|
|
39
41
|
}
|
|
42
|
+
/** The createPiFsTools result when `applyPatch` is true or an object: it is never null. */
|
|
43
|
+
export interface PiFsToolsWithApplyPatch extends PiFsTools {
|
|
44
|
+
readonly applyPatch: PiMutationTool;
|
|
45
|
+
}
|
|
40
46
|
/**
|
|
41
|
-
* Creates Pi read, edit,
|
|
42
|
-
*
|
|
47
|
+
* Creates Pi read, edit, and write tools rooted at each call's ctx.cwd, and
|
|
48
|
+
* an apply_patch tool when `applyPatch` is true or an object. They share one
|
|
49
|
+
* digest, lock manager, and clock, and the read store when `state` is given.
|
|
43
50
|
* Throws TypeError on fs, cwd, or allowedRoots anywhere in the options, on an
|
|
44
51
|
* unknown key, and on a shared option (state, digest, locks, clock, or a root
|
|
45
52
|
* option) inside one tool's options. There is no bash: register
|
|
46
53
|
* createPiBashTool() and call invalidate from its afterRun hook.
|
|
47
54
|
*/
|
|
55
|
+
export declare function createPiFsTools(options: CreatePiFsToolsOptions & {
|
|
56
|
+
readonly applyPatch: true | Omit<CreatePiApplyPatchToolOptions, BundleSharedKey>;
|
|
57
|
+
}): PiFsToolsWithApplyPatch;
|
|
48
58
|
export declare function createPiFsTools(options?: CreatePiFsToolsOptions): PiFsTools;
|
|
49
59
|
export {};
|
package/dist/fs-tools.js
CHANGED
|
@@ -15,14 +15,6 @@ const KNOWN_OPTIONS = new Set([
|
|
|
15
15
|
"applyPatch",
|
|
16
16
|
]);
|
|
17
17
|
const BUNDLE_SHARED_KEYS = ["state", "digest", "locks", "clock", ...PI_ROOT_KEYS];
|
|
18
|
-
/**
|
|
19
|
-
* Creates Pi read, edit, write, and apply_patch tools rooted at each call's
|
|
20
|
-
* ctx.cwd. They share one read state store, digest, lock manager, and clock.
|
|
21
|
-
* Throws TypeError on fs, cwd, or allowedRoots anywhere in the options, on an
|
|
22
|
-
* unknown key, and on a shared option (state, digest, locks, clock, or a root
|
|
23
|
-
* option) inside one tool's options. There is no bash: register
|
|
24
|
-
* createPiBashTool() and call invalidate from its afterRun hook.
|
|
25
|
-
*/
|
|
26
18
|
export function createPiFsTools(options = {}) {
|
|
27
19
|
checkPiOptions(options, "fs");
|
|
28
20
|
for (const key of Object.keys(options)) {
|
|
@@ -37,9 +29,15 @@ export function createPiFsTools(options = {}) {
|
|
|
37
29
|
read: options.read ?? {},
|
|
38
30
|
edit: options.edit ?? {},
|
|
39
31
|
write: options.write ?? {},
|
|
40
|
-
applyPatch: options.applyPatch
|
|
32
|
+
applyPatch: options.applyPatch === true
|
|
33
|
+
? {}
|
|
34
|
+
: options.applyPatch === false || options.applyPatch === undefined
|
|
35
|
+
? null
|
|
36
|
+
: options.applyPatch,
|
|
41
37
|
};
|
|
42
38
|
for (const [key, value] of Object.entries(given)) {
|
|
39
|
+
if (value === null)
|
|
40
|
+
continue;
|
|
43
41
|
checkPiOptions(value, key);
|
|
44
42
|
for (const shared of BUNDLE_SHARED_KEYS) {
|
|
45
43
|
if (Object.hasOwn(value, shared)) {
|
|
@@ -52,13 +50,16 @@ export function createPiFsTools(options = {}) {
|
|
|
52
50
|
const { signature: _readSignature, promptSnippet: _readSnippet, promptGuidelines: _readLines, ...read } = given.read;
|
|
53
51
|
const { signature: _editSignature, promptSnippet: _editSnippet, promptGuidelines: _editLines, ...edit } = given.edit;
|
|
54
52
|
const { signature: _writeSignature, promptSnippet: _writeSnippet, promptGuidelines: _writeLines, ...write } = given.write;
|
|
55
|
-
const { signature: _patchSignature, promptSnippet: _patchSnippet, promptGuidelines: _patchLines, ...applyPatch } = given.applyPatch;
|
|
56
53
|
const parts = {
|
|
57
54
|
read: piReadParts(given.read),
|
|
58
55
|
edit: piEditParts(given.edit),
|
|
59
56
|
write: piWriteParts(given.write),
|
|
60
|
-
applyPatch: piApplyPatchParts(given.applyPatch),
|
|
61
57
|
};
|
|
58
|
+
let patch = null;
|
|
59
|
+
if (given.applyPatch !== null) {
|
|
60
|
+
const { signature: _patchSignature, promptSnippet: _patchSnippet, promptGuidelines: _patchLines, ...deps } = given.applyPatch;
|
|
61
|
+
patch = { deps, parts: piApplyPatchParts(given.applyPatch) };
|
|
62
|
+
}
|
|
62
63
|
const core = createFsTools({
|
|
63
64
|
fs,
|
|
64
65
|
digest: options.digest ?? nodeDigest(),
|
|
@@ -68,13 +69,15 @@ export function createPiFsTools(options = {}) {
|
|
|
68
69
|
read: { ...read, ...piReadDeps(parts.read) },
|
|
69
70
|
edit: { ...edit, messages: parts.edit.messages },
|
|
70
71
|
write: { ...write, messages: parts.write.messages },
|
|
71
|
-
applyPatch: { ...
|
|
72
|
+
...(patch === null ? {} : { applyPatch: { ...patch.deps, messages: patch.parts.messages } }),
|
|
72
73
|
});
|
|
73
74
|
return Object.freeze({
|
|
74
75
|
read: adaptPiReadTool(parts.read, core.read, core.digest),
|
|
75
76
|
edit: adaptPiMutationTool(parts.edit, core.edit),
|
|
76
77
|
write: adaptPiMutationTool(parts.write, core.write),
|
|
77
|
-
applyPatch:
|
|
78
|
+
applyPatch: patch === null || core.applyPatch === null
|
|
79
|
+
? null
|
|
80
|
+
: adaptPiMutationTool(patch.parts, core.applyPatch),
|
|
78
81
|
state: core.state,
|
|
79
82
|
digest: core.digest,
|
|
80
83
|
locks: core.locks,
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export type { CreatePiBashToolOptions, PiBashDetails, PiBashTool, PiBashToolResu
|
|
|
3
3
|
export { toPiReadDetails } from "./details.ts";
|
|
4
4
|
export type { PiReadDetails, PiTruncationResult } from "./details.ts";
|
|
5
5
|
export { createPiFsTools } from "./fs-tools.ts";
|
|
6
|
-
export type { CreatePiFsToolsOptions, PiFsTools } from "./fs-tools.ts";
|
|
6
|
+
export type { CreatePiFsToolsOptions, PiFsTools, PiFsToolsWithApplyPatch } from "./fs-tools.ts";
|
|
7
7
|
export { toPiMutationDetails } from "./mutation-details.ts";
|
|
8
8
|
export type { PiMutationDetails } from "./mutation-details.ts";
|
|
9
9
|
export { createPiApplyPatchTool, createPiEditTool, createPiWriteTool } from "./mutation-tools.ts";
|
package/dist/mutation-tools.d.ts
CHANGED
|
@@ -61,7 +61,7 @@ export declare function piApplyPatchParts(options: PartsInput<PatchSignature>):
|
|
|
61
61
|
/**
|
|
62
62
|
* Creates a Pi edit tool rooted at each call's ctx.cwd. Throws TypeError when
|
|
63
63
|
* options set fs, cwd, or allowedRoots. Read-before-write is off unless you
|
|
64
|
-
* pass a `state`; use createPiFsTools() for a store shared with read.
|
|
64
|
+
* pass a `state`; use createPiFsTools({ state }) for a store shared with read.
|
|
65
65
|
*/
|
|
66
66
|
export declare function createPiEditTool(options?: CreatePiEditToolOptions): PiMutationTool;
|
|
67
67
|
/** Creates a Pi write tool, as createPiEditTool. `details` is always undefined, as for Pi's own write. */
|
package/dist/mutation-tools.js
CHANGED
|
@@ -43,7 +43,7 @@ function parts(tool, signature, options, snippet, guidelines) {
|
|
|
43
43
|
/**
|
|
44
44
|
* Creates a Pi edit tool rooted at each call's ctx.cwd. Throws TypeError when
|
|
45
45
|
* options set fs, cwd, or allowedRoots. Read-before-write is off unless you
|
|
46
|
-
* pass a `state`; use createPiFsTools() for a store shared with read.
|
|
46
|
+
* pass a `state`; use createPiFsTools({ state }) for a store shared with read.
|
|
47
47
|
*/
|
|
48
48
|
export function createPiEditTool(options = {}) {
|
|
49
49
|
checkPiOptions(options, "edit");
|
package/dist/roots.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export interface PiRootOptions {
|
|
|
6
6
|
/** Added to /dev, /proc, /sys. */
|
|
7
7
|
readonly denyRoots?: readonly string[];
|
|
8
8
|
readonly symlinks?: NodeFileSystemOptions["symlinks"];
|
|
9
|
-
/** How to replace a file with more than one hard link. Default "refuse". */
|
|
9
|
+
/** How to replace a file with more than one hard link. Default "in-place". "refuse" fails with DENIED. */
|
|
10
10
|
readonly hardLinks?: "refuse" | "in-place";
|
|
11
11
|
/** Mode of a new file, exactly. Default 0o666 less the process umask. */
|
|
12
12
|
readonly newFileMode?: number;
|
package/dist/tool.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import type { TSchema } from "typebox";
|
|
3
3
|
import type { NodeFileSystemOptions } from "@better-fs-tools/node";
|
|
4
|
-
import type { Digest, JsonObject, ReadFormatter, ReadLimits, ReadMessageCatalog, ReadTool, ReadToolDeps, StateNeedsDigestOrDefault } from "@better-fs-tools/read";
|
|
4
|
+
import type { Converter, Digest, JsonObject, ReadFormatter, ReadLimits, ReadMessageCatalog, ReadTool, ReadToolDeps, StateNeedsDigestOrDefault } from "@better-fs-tools/read";
|
|
5
5
|
import type { ReadSignature } from "@better-fs-tools/read/signature";
|
|
6
6
|
import type { PiReadDetails } from "./details.ts";
|
|
7
7
|
import type { PiContentPart } from "./parts.ts";
|
|
@@ -17,7 +17,8 @@ export interface PiReadOptions {
|
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
19
|
* Options for createPiReadTool. digest defaults to nodeDigest(); a state needs
|
|
20
|
-
* a digest that is not null.
|
|
20
|
+
* a digest that is not null. converters defaults to [imageConverter()], as
|
|
21
|
+
* Pi's own read shows images. A list you pass replaces it: [] turns images off.
|
|
21
22
|
*/
|
|
22
23
|
export type CreatePiReadToolOptions = Omit<ReadToolDeps<ExtensionContext>, "fs"> & StateNeedsDigestOrDefault & PiReadOptions & {
|
|
23
24
|
/** Added to /dev, /proc, /sys. */
|
|
@@ -42,7 +43,8 @@ export interface PiReadTool {
|
|
|
42
43
|
/**
|
|
43
44
|
* Creates a Pi read tool rooted at each call's ctx.cwd. Throws TypeError when
|
|
44
45
|
* options set fs, cwd, or allowedRoots. It keeps no read state by default and
|
|
45
|
-
* writes nothing outside the process.
|
|
46
|
+
* writes nothing outside the process. An image becomes a Pi image part unless
|
|
47
|
+
* options.converters leaves imageConverter() out.
|
|
46
48
|
*/
|
|
47
49
|
export declare function createPiReadTool(options?: CreatePiReadToolOptions): PiReadTool;
|
|
48
50
|
export interface PiReadParts {
|
|
@@ -52,11 +54,13 @@ export interface PiReadParts {
|
|
|
52
54
|
readonly limits: Readonly<ReadLimits>;
|
|
53
55
|
readonly formatter: ReadFormatter<ExtensionContext>;
|
|
54
56
|
readonly messages: Partial<ReadMessageCatalog>;
|
|
57
|
+
readonly converters: readonly Converter<ExtensionContext>[];
|
|
55
58
|
}
|
|
56
|
-
export declare function piReadParts(options: PiReadOptions & Pick<Partial<ReadToolDeps<ExtensionContext>>, "limits" | "messages" | "formatter">): PiReadParts;
|
|
59
|
+
export declare function piReadParts(options: PiReadOptions & Pick<Partial<ReadToolDeps<ExtensionContext>>, "limits" | "messages" | "formatter" | "converters">): PiReadParts;
|
|
57
60
|
export declare function piReadDeps(parts: PiReadParts): {
|
|
58
61
|
limits: Readonly<ReadLimits>;
|
|
59
62
|
formatter: ReadFormatter<ExtensionContext>;
|
|
60
63
|
messages: Partial<ReadMessageCatalog>;
|
|
64
|
+
converters: readonly Converter<ExtensionContext>[];
|
|
61
65
|
};
|
|
62
66
|
export declare function adaptPiReadTool(parts: PiReadParts, read: ReadTool<ExtensionContext>, digest: Digest | null): PiReadTool;
|
package/dist/tool.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
import { nodeDigest } from "@better-fs-tools/node";
|
|
3
|
-
import { createReadTool, lineNumberFormatter, resolveReadLimits } from "@better-fs-tools/read";
|
|
3
|
+
import { createReadTool, imageConverter, lineNumberFormatter, resolveReadLimits, } from "@better-fs-tools/read";
|
|
4
4
|
import { defaultReadSignature, readSignatureMessages } from "@better-fs-tools/read/signature";
|
|
5
5
|
import { toPiReadDetails } from "./details.js";
|
|
6
6
|
import { toPiPart } from "./parts.js";
|
|
@@ -12,7 +12,8 @@ const PI_BUILTIN_READ_GUIDELINES = [
|
|
|
12
12
|
/**
|
|
13
13
|
* Creates a Pi read tool rooted at each call's ctx.cwd. Throws TypeError when
|
|
14
14
|
* options set fs, cwd, or allowedRoots. It keeps no read state by default and
|
|
15
|
-
* writes nothing outside the process.
|
|
15
|
+
* writes nothing outside the process. An image becomes a Pi image part unless
|
|
16
|
+
* options.converters leaves imageConverter() out.
|
|
16
17
|
*/
|
|
17
18
|
export function createPiReadTool(options = {}) {
|
|
18
19
|
checkPiOptions(options, "read");
|
|
@@ -37,10 +38,17 @@ export function piReadParts(options) {
|
|
|
37
38
|
limits: resolveReadLimits(options.limits),
|
|
38
39
|
formatter: options.formatter ?? lineNumberFormatter(),
|
|
39
40
|
messages: { ...readSignatureMessages(signature), ...options.messages },
|
|
41
|
+
// Pi's own read returns images, so the Pi host turns them on.
|
|
42
|
+
converters: options.converters ?? [imageConverter()],
|
|
40
43
|
};
|
|
41
44
|
}
|
|
42
45
|
export function piReadDeps(parts) {
|
|
43
|
-
return {
|
|
46
|
+
return {
|
|
47
|
+
limits: parts.limits,
|
|
48
|
+
formatter: parts.formatter,
|
|
49
|
+
messages: parts.messages,
|
|
50
|
+
converters: parts.converters,
|
|
51
|
+
};
|
|
44
52
|
}
|
|
45
53
|
export function adaptPiReadTool(parts, read, digest) {
|
|
46
54
|
const { signature, promptSnippet, promptGuidelines, limits, formatter } = parts;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-fs-tools/pi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "The Better FS Tools read, edit, write, apply_patch, and bash tools and extension for the Pi coding agent.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -42,13 +42,13 @@
|
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@better-fs-tools/node": "^0.
|
|
46
|
-
"@better-fs-tools/read": "^0.
|
|
47
|
-
"@better-fs-tools/shell": "^0.
|
|
48
|
-
"@better-fs-tools/write": "^0.
|
|
45
|
+
"@better-fs-tools/node": "^0.2.0",
|
|
46
|
+
"@better-fs-tools/read": "^0.2.0",
|
|
47
|
+
"@better-fs-tools/shell": "^0.2.0",
|
|
48
|
+
"@better-fs-tools/write": "^0.2.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@better-fs-tools/fs": "^0.
|
|
51
|
+
"@better-fs-tools/fs": "^0.2.0",
|
|
52
52
|
"@earendil-works/pi-coding-agent": "^0.84.2",
|
|
53
53
|
"typebox": "^1.3.16"
|
|
54
54
|
},
|