@henryqw/pi-add-dir 0.1.12 → 0.1.14
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 +12 -6
- package/extensions/add-dir.ts +70 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# `@henryqw/pi-add-dir`
|
|
2
2
|
|
|
3
|
-
Add external directories to the current Pi session
|
|
3
|
+
Add external directories to the current Pi session. Pi can use their context files and skills, and search their files.
|
|
4
4
|
|
|
5
5
|
## Why
|
|
6
6
|
|
|
7
|
-
- **Created for**:
|
|
8
|
-
- **Advantage**:
|
|
7
|
+
- **Created for**: Use context and skills outside the current working directory.
|
|
8
|
+
- **Advantage**: Use external trees without copying them into the repository.
|
|
9
9
|
|
|
10
10
|
## Install
|
|
11
11
|
|
|
@@ -23,10 +23,16 @@ pi install npm:@henryqw/pi-add-dir
|
|
|
23
23
|
| `add_directory` | tool | Add a directory. |
|
|
24
24
|
| `search_external_files` | tool | Glob-search added directories. |
|
|
25
25
|
|
|
26
|
-
Added directories
|
|
26
|
+
Added directories give Pi these resources:
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
- Root `AGENTS.md`, `CLAUDE.md`, `.pi/AGENTS.md`, and `.pi/CLAUDE.md` files. Pi injects them into later prompts.
|
|
29
|
+
- Skills that Pi loads from `.pi/skills`, `.agents/skills`, and `.claude/skills`.
|
|
30
|
+
- Files in the editor's `@` autocomplete, with absolute paths.
|
|
31
|
+
|
|
32
|
+
`/dir-add` reloads when it finds skills. `add_directory` reports when a reload is needed.
|
|
33
|
+
|
|
34
|
+
Search supports basename and relative-path globs. It skips `.git` and `node_modules`. It uses Node filesystem traversal and returns at most 1,000 results per call.
|
|
29
35
|
|
|
30
36
|
## State
|
|
31
37
|
|
|
32
|
-
Pi session entry `add-dir:state` stores added directories
|
|
38
|
+
Pi session entry `add-dir:state` stores added directories. It is package-managed; do not edit it. Tree navigation restores the active branch's directories and reloads resources when that set changes.
|
package/extensions/add-dir.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
import { basename, isAbsolute, relative, sep } from "node:path";
|
|
2
|
-
import {
|
|
1
|
+
import { basename, isAbsolute, join, relative, sep } from "node:path";
|
|
2
|
+
import {
|
|
3
|
+
Text,
|
|
4
|
+
truncateToWidth,
|
|
5
|
+
visibleWidth,
|
|
6
|
+
type AutocompleteProvider,
|
|
7
|
+
type AutocompleteSuggestions,
|
|
8
|
+
} from "@earendil-works/pi-tui";
|
|
3
9
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
4
10
|
import { Type } from "typebox";
|
|
5
11
|
import {
|
|
@@ -85,6 +91,67 @@ function contextSummary(dirCtx: DirContext): string {
|
|
|
85
91
|
return found.length > 0 ? ` Found: ${found.join(", ")}.` : " No context files found.";
|
|
86
92
|
}
|
|
87
93
|
|
|
94
|
+
function extractAtToken(textBeforeCursor: string): string | undefined {
|
|
95
|
+
return textBeforeCursor.match(/(?:^|[ \t])(@(?:"[^"]*|[^\s"]*))$/)?.[1];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function createExternalAutocompleteProvider(
|
|
99
|
+
current: AutocompleteProvider,
|
|
100
|
+
getAddedDirs: () => AddedDir[],
|
|
101
|
+
): AutocompleteProvider {
|
|
102
|
+
return {
|
|
103
|
+
async getSuggestions(lines, cursorLine, cursorCol, options): Promise<AutocompleteSuggestions | null> {
|
|
104
|
+
const line = lines[cursorLine] ?? "";
|
|
105
|
+
const token = extractAtToken(line.slice(0, cursorCol));
|
|
106
|
+
if (!token) return current.getSuggestions(lines, cursorLine, cursorCol, options);
|
|
107
|
+
|
|
108
|
+
const quoted = token.startsWith('@"');
|
|
109
|
+
const query = token.slice(quoted ? 2 : 1);
|
|
110
|
+
if (isAbsolute(query) || query.startsWith("~/") || query.startsWith("./") || query.startsWith("../")) {
|
|
111
|
+
return current.getSuggestions(lines, cursorLine, cursorCol, options);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const tokenStart = cursorCol - token.length;
|
|
115
|
+
const sources = await Promise.all([
|
|
116
|
+
current.getSuggestions(lines, cursorLine, cursorCol, options),
|
|
117
|
+
...getAddedDirs().map(async (dir) => {
|
|
118
|
+
const externalPath = join(dir.absolutePath, query);
|
|
119
|
+
const externalToken = `${quoted || externalPath.includes(" ") ? '@"' : "@"}${externalPath}`;
|
|
120
|
+
const externalLines = [...lines];
|
|
121
|
+
externalLines[cursorLine] = `${line.slice(0, tokenStart)}${externalToken}${line.slice(cursorCol)}`;
|
|
122
|
+
const suggestions = await current.getSuggestions(
|
|
123
|
+
externalLines,
|
|
124
|
+
cursorLine,
|
|
125
|
+
tokenStart + externalToken.length,
|
|
126
|
+
options,
|
|
127
|
+
);
|
|
128
|
+
return suggestions
|
|
129
|
+
? {
|
|
130
|
+
...suggestions,
|
|
131
|
+
items: suggestions.items.map((item) => ({
|
|
132
|
+
...item,
|
|
133
|
+
description: `${dir.label}: ${item.description ?? item.value}`,
|
|
134
|
+
})),
|
|
135
|
+
}
|
|
136
|
+
: null;
|
|
137
|
+
}),
|
|
138
|
+
]);
|
|
139
|
+
|
|
140
|
+
const itemCount = Math.max(...sources.map((source) => source?.items.length ?? 0));
|
|
141
|
+
const items = Array.from({ length: itemCount }, (_, index) =>
|
|
142
|
+
sources.flatMap((source) => (source?.items[index] ? [source.items[index]] : [])),
|
|
143
|
+
).flat();
|
|
144
|
+
return items.length > 0 ? { prefix: token, items } : null;
|
|
145
|
+
},
|
|
146
|
+
applyCompletion(lines, cursorLine, cursorCol, item, prefix) {
|
|
147
|
+
return current.applyCompletion(lines, cursorLine, cursorCol, item, prefix);
|
|
148
|
+
},
|
|
149
|
+
shouldTriggerFileCompletion(lines, cursorLine, cursorCol) {
|
|
150
|
+
return current.shouldTriggerFileCompletion?.(lines, cursorLine, cursorCol) ?? true;
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
88
155
|
export default function addDirExtension(pi: ExtensionAPI): void {
|
|
89
156
|
let addedDirs: AddedDir[] = [];
|
|
90
157
|
let currentCwd = "";
|
|
@@ -212,6 +279,7 @@ export default function addDirExtension(pi: ExtensionAPI): void {
|
|
|
212
279
|
|
|
213
280
|
pi.on("session_start", async (_event, ctx) => {
|
|
214
281
|
reconstructState(ctx);
|
|
282
|
+
ctx.ui.addAutocompleteProvider((current) => createExternalAutocompleteProvider(current, () => addedDirs));
|
|
215
283
|
});
|
|
216
284
|
pi.on("session_tree", async (_event, ctx) => {
|
|
217
285
|
if (reconstructState(ctx)) pi.sendUserMessage("/dir-reload", { expandPromptTemplates: true });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@henryqw/pi-add-dir",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"description": "Add external directories to a Pi session with context, skills, and file search.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
},
|
|
16
16
|
"license": "MIT",
|
|
17
17
|
"files": [
|
|
18
|
+
"LICENSE",
|
|
18
19
|
"extensions",
|
|
19
|
-
"README.md"
|
|
20
|
-
"LICENSE"
|
|
20
|
+
"README.md"
|
|
21
21
|
],
|
|
22
22
|
"scripts": {
|
|
23
23
|
"test": "node --test test/*.test.ts",
|