@zigai/pi-mention-project 0.2.0 → 0.2.2
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 +11 -45
- package/package.json +1 -1
- package/src/expand-mentions.ts +23 -81
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/@zigai/pi-mention-project)
|
|
5
5
|
[](../../LICENSE)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Type `#` to fuzzy-search your project folder. The completion inserts `#project-name`; the model receives the project's absolute path.
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
@@ -12,65 +12,31 @@ This Pi extension adds fuzzy project directory mentions that default to `#`.
|
|
|
12
12
|
pi install npm:@zigai/pi-mention-project
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
##
|
|
15
|
+
## Config
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
- Searches only the direct child folders inside configured project roots.
|
|
19
|
-
- Defaults to Git repository folders and ignores dot-prefixed folders.
|
|
20
|
-
- Expands project mentions before the model sees the prompt so the model gets each project's absolute path.
|
|
21
|
-
|
|
22
|
-
## Usage
|
|
23
|
-
|
|
24
|
-
Configure one or more project roots, then type `#` in the prompt editor and start typing a folder name.
|
|
25
|
-
|
|
26
|
-
If `~/Projects` contains `pi-tweaks`, selecting `#pi-tweaks` adds that project mention. Before the model sees the prompt, the extension prepends project metadata with the absolute project path and removes the `#` sigil from the visible sentence.
|
|
27
|
-
|
|
28
|
-
## Configuration
|
|
29
|
-
|
|
30
|
-
Configuration lives in Pi settings: globally in `~/.pi/agent/settings.json`, or per trusted project in `.pi/settings.json`.
|
|
31
|
-
|
|
32
|
-
Project roots default to an empty list. Set `mentionProjectRoots` to the directories whose direct child folders should be mentionable:
|
|
33
|
-
|
|
34
|
-
```json
|
|
35
|
-
{
|
|
36
|
-
"mentionProjectRoots": ["~/Projects", "~/Work"]
|
|
37
|
-
}
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
Only immediate child directories are listed. For example, `~/Projects/app` is mentionable, but `~/Projects/app/packages/api` is not.
|
|
41
|
-
|
|
42
|
-
By default, a child folder is listed only when it has a `.git` directory or worktree `.git` file, and folders whose names start with `.` are hidden. To include non-Git folders, set `mentionProjectGitReposOnly` to `false`:
|
|
17
|
+
Add roots in `~/.pi/agent/settings.json` or `.pi/settings.json`:
|
|
43
18
|
|
|
44
19
|
```json
|
|
45
20
|
{
|
|
46
|
-
"
|
|
21
|
+
"mentionProjectRoots": ["~/Projects"]
|
|
47
22
|
}
|
|
48
23
|
```
|
|
49
24
|
|
|
50
|
-
|
|
25
|
+
By default it lists only direct child folders that:
|
|
51
26
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
"mentionProjectIncludeDotFolders": true
|
|
55
|
-
}
|
|
56
|
-
```
|
|
27
|
+
- are Git repos (`.git` directory or worktree file)
|
|
28
|
+
- do not start with `.`
|
|
57
29
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
```sh
|
|
61
|
-
pi --mention-project-include-non-git --mention-project-include-dot-folders
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
The mention character defaults to `#`. To change it, set `mentionProjectTrigger` to a single non-whitespace character:
|
|
30
|
+
Optional settings:
|
|
65
31
|
|
|
66
32
|
```json
|
|
67
33
|
{
|
|
68
|
-
"mentionProjectTrigger": "
|
|
34
|
+
"mentionProjectTrigger": "#",
|
|
35
|
+
"mentionProjectGitReposOnly": true,
|
|
36
|
+
"mentionProjectIncludeDotFolders": false
|
|
69
37
|
}
|
|
70
38
|
```
|
|
71
39
|
|
|
72
|
-
Folder names should be unique across configured roots. If the same folder name exists in multiple roots, the first configured root wins.
|
|
73
|
-
|
|
74
40
|
## License
|
|
75
41
|
|
|
76
42
|
MIT
|
package/package.json
CHANGED
package/src/expand-mentions.ts
CHANGED
|
@@ -7,31 +7,6 @@ import {
|
|
|
7
7
|
} from "./mention-syntax.ts";
|
|
8
8
|
import type { ProjectDirectory } from "./types.ts";
|
|
9
9
|
|
|
10
|
-
function escapeXmlText(value: string): string {
|
|
11
|
-
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function escapeXmlAttribute(value: string): string {
|
|
15
|
-
return escapeXmlText(value).replace(/"/g, """);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function formatProjectBlock(project: ProjectDirectory): string {
|
|
19
|
-
const name = escapeXmlAttribute(project.name);
|
|
20
|
-
const projectPath = escapeXmlAttribute(project.path);
|
|
21
|
-
const root = escapeXmlAttribute(project.root);
|
|
22
|
-
return `<project name="${name}" path="${projectPath}" root="${root}">\nDirectory: ${escapeXmlText(project.path)}\n</project>`;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function formatCombinedProjectBlock(projects: ProjectDirectory[]): string {
|
|
26
|
-
if (projects.length === 1) {
|
|
27
|
-
const project = projects[0];
|
|
28
|
-
if (project !== undefined) return formatProjectBlock(project);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const content = projects.map((project) => formatProjectBlock(project)).join("\n\n");
|
|
32
|
-
return `<projects>\n${content}\n</projects>`;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
10
|
function projectMap(projects: ProjectDirectory[]): Map<string, ProjectDirectory> {
|
|
36
11
|
const byName = new Map<string, ProjectDirectory>();
|
|
37
12
|
for (const project of projects) {
|
|
@@ -41,69 +16,36 @@ function projectMap(projects: ProjectDirectory[]): Map<string, ProjectDirectory>
|
|
|
41
16
|
return byName;
|
|
42
17
|
}
|
|
43
18
|
|
|
44
|
-
function mentionedProjectNames(
|
|
45
|
-
text: string,
|
|
46
|
-
projects: ProjectDirectory[],
|
|
47
|
-
trigger: string,
|
|
48
|
-
): Set<string> {
|
|
49
|
-
const names = new Set<string>();
|
|
50
|
-
const knownNames = projectNameSet(projects);
|
|
51
|
-
|
|
52
|
-
for (const match of text.matchAll(projectMentionPattern(trigger))) {
|
|
53
|
-
const parsed = parseProjectMentionName(match[2], match[3], knownNames);
|
|
54
|
-
if (parsed !== undefined) {
|
|
55
|
-
names.add(parsed.name);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return names;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function removeProjectMentionSigils(
|
|
63
|
-
text: string,
|
|
64
|
-
projects: ProjectDirectory[],
|
|
65
|
-
trigger: string,
|
|
66
|
-
): string {
|
|
67
|
-
const knownNames = projectNameSet(projects);
|
|
68
|
-
return text
|
|
69
|
-
.replace(
|
|
70
|
-
projectMentionPattern(trigger),
|
|
71
|
-
(
|
|
72
|
-
match: string,
|
|
73
|
-
leading: string,
|
|
74
|
-
quotedName: string | undefined,
|
|
75
|
-
unquotedName: string | undefined,
|
|
76
|
-
) => {
|
|
77
|
-
const parsed = parseProjectMentionName(quotedName, unquotedName, knownNames);
|
|
78
|
-
if (parsed === undefined) return match;
|
|
79
|
-
return `${leading}${parsed.name}${parsed.suffix}`;
|
|
80
|
-
},
|
|
81
|
-
)
|
|
82
|
-
.trim();
|
|
83
|
-
}
|
|
84
|
-
|
|
85
19
|
export function expandProjectMentions(
|
|
86
20
|
text: string,
|
|
87
21
|
projects: ProjectDirectory[],
|
|
88
22
|
trigger: string,
|
|
89
23
|
): string {
|
|
90
24
|
const byName = projectMap(projects);
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const loaded: ProjectDirectory[] = [];
|
|
95
|
-
for (const name of names) {
|
|
96
|
-
const project = byName.get(name);
|
|
97
|
-
if (project !== undefined) {
|
|
98
|
-
loaded.push(project);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
if (loaded.length === 0) return text;
|
|
25
|
+
const knownNames = projectNameSet(projects);
|
|
26
|
+
let changed = false;
|
|
102
27
|
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
28
|
+
const expanded = text.replace(
|
|
29
|
+
projectMentionPattern(trigger),
|
|
30
|
+
(
|
|
31
|
+
match: string,
|
|
32
|
+
leading: string,
|
|
33
|
+
quotedName: string | undefined,
|
|
34
|
+
unquotedName: string | undefined,
|
|
35
|
+
) => {
|
|
36
|
+
const parsed = parseProjectMentionName(quotedName, unquotedName, knownNames);
|
|
37
|
+
if (parsed === undefined) return match;
|
|
38
|
+
|
|
39
|
+
const project = byName.get(parsed.name);
|
|
40
|
+
if (project === undefined) return match;
|
|
41
|
+
|
|
42
|
+
changed = true;
|
|
43
|
+
return `${leading}${project.path}${parsed.suffix}`;
|
|
44
|
+
},
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
if (!changed) return text;
|
|
48
|
+
return expanded;
|
|
107
49
|
}
|
|
108
50
|
|
|
109
51
|
type ContextMessage = ContextEvent["messages"][number];
|