@josephyoung/pi-file-reference 0.1.0 → 0.1.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/.github/workflows/publish.yml +29 -0
- package/AGENTS.md +47 -0
- package/README.md +10 -0
- package/extensions/index.ts +41 -29
- package/package.json +1 -1
- package/tsconfig.json +1 -1
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Publish to npm
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
paths:
|
|
8
|
+
- package.json
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
publish:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
id-token: write
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
- uses: actions/setup-node@v4
|
|
20
|
+
with:
|
|
21
|
+
node-version: 24
|
|
22
|
+
- run: |
|
|
23
|
+
PACKAGE_VERSION=$(node -p "require('./package.json').version")
|
|
24
|
+
PUBLISHED_VERSION=$(npm view @josephyoung/pi-file-reference version 2>/dev/null || echo "0.0.0")
|
|
25
|
+
if [ "$PACKAGE_VERSION" != "$PUBLISHED_VERSION" ]; then
|
|
26
|
+
npm publish --provenance --access public
|
|
27
|
+
else
|
|
28
|
+
echo "Version $PACKAGE_VERSION already published, skipping"
|
|
29
|
+
fi
|
package/AGENTS.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# pi-file-reference
|
|
2
|
+
|
|
3
|
+
Pi extension that resolves `@filepath` references in AGENTS.md and injects file content into system prompt.
|
|
4
|
+
|
|
5
|
+
## Structure
|
|
6
|
+
|
|
7
|
+
- `extensions/index.ts` — extension entry point
|
|
8
|
+
- `session_start`: scan AGENTS.md for @refs, read files, cache in memory
|
|
9
|
+
- `before_agent_start`: inject cached file content into system prompt
|
|
10
|
+
- `package.json` — pi package metadata
|
|
11
|
+
|
|
12
|
+
## How it works
|
|
13
|
+
|
|
14
|
+
When a user writes `@./docs/style-guide.md` in their AGENTS.md:
|
|
15
|
+
|
|
16
|
+
1. The extension finds all `@` references in AGENTS.md (cwd or ~/.pi/agent/)
|
|
17
|
+
2. Resolves paths (relative, absolute, ~/ expansion)
|
|
18
|
+
3. If the path is a file: reads it
|
|
19
|
+
If the path is a directory: reads all immediate files (depth 1, sorted alphabetically)
|
|
20
|
+
4. Injects them into the system prompt under `# Context References`
|
|
21
|
+
|
|
22
|
+
## Conventions
|
|
23
|
+
|
|
24
|
+
- All code and comments in English
|
|
25
|
+
- AGENTS.md drives the project-level AI context
|
|
26
|
+
- Match Pi's internal style for context file injection (`## @path\n\n{content}`)
|
|
27
|
+
|
|
28
|
+
## Publishing
|
|
29
|
+
|
|
30
|
+
After functional changes are committed and pushed, update the GitHub repo description if the feature set changed:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
gh repo edit --description "Pi extension: ..."
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Then bump version and push:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm version patch # bump version, creates commit + tag
|
|
40
|
+
git push origin main --tags # push to main triggers CI (package.json change)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
- GitHub Actions workflow: `.github/workflows/publish.yml`
|
|
44
|
+
- Trigger: push to main when `package.json` changes, or `workflow_dispatch`
|
|
45
|
+
- CI checks if version > npm latest before publishing (idempotent)
|
|
46
|
+
- Uses npm Trusted Publishing (OIDC) — no tokens or OTP needed
|
|
47
|
+
- OIDC runs on `refs/heads/main` — ensure npm Trusted Publisher is configured for branch `main`
|
package/README.md
CHANGED
|
@@ -21,6 +21,16 @@ A [pi](https://github.com/earendil-works/pi-coding-agent) extension that resolve
|
|
|
21
21
|
|
|
22
22
|
The `@` must be at the start of a line or preceded by whitespace.
|
|
23
23
|
|
|
24
|
+
### Directory references
|
|
25
|
+
|
|
26
|
+
When `@path` resolves to a directory, all immediate files (depth 1) are injected:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
@./docs
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Injects `@docs/style-guide.md`, `@docs/patterns.md`, etc. (sorted alphabetically). Subdirectories are skipped. Trailing `/` is stripped (`@./docs/` works the same).
|
|
33
|
+
|
|
24
34
|
## Installation
|
|
25
35
|
|
|
26
36
|
```bash
|
package/extensions/index.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import type { ExtensionAPI
|
|
1
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import * as os from "node:os";
|
|
5
5
|
|
|
6
6
|
const AGENTS_FILE = "AGENTS.md";
|
|
7
|
-
const STORE_KEY = "agents-at-context";
|
|
8
7
|
|
|
9
8
|
/**
|
|
10
9
|
* Parse @filepath references from a line.
|
|
@@ -123,52 +122,65 @@ function loadRefs(cwd: string): RefContent[] {
|
|
|
123
122
|
return true;
|
|
124
123
|
});
|
|
125
124
|
|
|
126
|
-
// Read each referenced file
|
|
125
|
+
// Read each referenced file or directory
|
|
127
126
|
const results: RefContent[] = [];
|
|
128
127
|
for (const ref of uniqueRefs) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
128
|
+
// Strip trailing slashes for consistent handling
|
|
129
|
+
const cleanRef = ref.endsWith("/") ? ref.slice(0, -1) : ref;
|
|
130
|
+
const resolvedPath = resolveRef(cleanRef, baseDir);
|
|
131
|
+
|
|
132
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
133
|
+
console.warn(`[pi-file-reference] @${cleanRef} -> ${resolvedPath} not found, skipping`);
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const stat = fs.statSync(resolvedPath);
|
|
138
|
+
if (stat.isDirectory()) {
|
|
139
|
+
// Read all files at depth 1, skip subdirectories
|
|
140
|
+
const entries = fs.readdirSync(resolvedPath, { withFileTypes: true });
|
|
141
|
+
const files = entries
|
|
142
|
+
.filter((e) => e.isFile())
|
|
143
|
+
.map((e) => e.name)
|
|
144
|
+
.sort(); // deterministic order
|
|
145
|
+
|
|
146
|
+
if (files.length === 0) {
|
|
147
|
+
console.warn(`[pi-file-reference] @${cleanRef} is an empty directory, skipping`);
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
for (const fileName of files) {
|
|
152
|
+
const filePath = path.join(resolvedPath, fileName);
|
|
153
|
+
results.push({
|
|
154
|
+
ref: `${cleanRef}/${fileName}`,
|
|
155
|
+
content: fs.readFileSync(filePath, "utf-8"),
|
|
156
|
+
});
|
|
157
|
+
}
|
|
132
158
|
} else {
|
|
133
|
-
|
|
159
|
+
results.push({ ref: cleanRef, content: fs.readFileSync(resolvedPath, "utf-8") });
|
|
134
160
|
}
|
|
135
161
|
}
|
|
136
162
|
|
|
137
163
|
return results;
|
|
138
164
|
}
|
|
139
165
|
|
|
166
|
+
let cachedRefs: RefContent[] = [];
|
|
167
|
+
|
|
140
168
|
export default function (pi: ExtensionAPI) {
|
|
141
169
|
pi.on("session_start", (_event, ctx) => {
|
|
142
|
-
|
|
143
|
-
const entries = ctx.sessionManager.getEntries();
|
|
144
|
-
const existing = entries.find(
|
|
145
|
-
(e): e is CustomEntry<{ refs: RefContent[] }> =>
|
|
146
|
-
e.type === "custom" && e.customType === STORE_KEY,
|
|
147
|
-
);
|
|
148
|
-
if (existing) return;
|
|
149
|
-
|
|
150
|
-
const refs = loadRefs(ctx.cwd);
|
|
151
|
-
if (refs.length === 0) return;
|
|
152
|
-
|
|
153
|
-
pi.appendEntry(STORE_KEY, { refs });
|
|
170
|
+
cachedRefs = loadRefs(ctx.cwd);
|
|
154
171
|
});
|
|
155
172
|
|
|
156
|
-
pi.on("before_agent_start", (event,
|
|
157
|
-
|
|
158
|
-
const entry = entries.find(
|
|
159
|
-
(e): e is CustomEntry<{ refs: RefContent[] }> =>
|
|
160
|
-
e.type === "custom" && e.customType === STORE_KEY,
|
|
161
|
-
);
|
|
162
|
-
if (!entry?.data?.refs?.length) return;
|
|
173
|
+
pi.on("before_agent_start", (event, _ctx) => {
|
|
174
|
+
if (!cachedRefs.length) return;
|
|
163
175
|
|
|
164
|
-
const injected =
|
|
165
|
-
.map((r) =>
|
|
176
|
+
const injected = cachedRefs
|
|
177
|
+
.map((r) => `## @${r.ref}\n\n${r.content}`)
|
|
166
178
|
.join("\n\n");
|
|
167
179
|
|
|
168
180
|
return {
|
|
169
181
|
systemPrompt:
|
|
170
182
|
event.systemPrompt +
|
|
171
|
-
`\n\n
|
|
183
|
+
`\n\n# Context References\n\n${injected}`,
|
|
172
184
|
};
|
|
173
185
|
});
|
|
174
186
|
}
|
package/package.json
CHANGED
package/tsconfig.json
CHANGED