pi-direnv 0.1.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 +25 -0
- package/index.ts +90 -0
- package/package.json +37 -0
package/README.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# pi-direnv
|
|
2
|
+
|
|
3
|
+
Auto-load [direnv](https://direnv.net/) environment at session start. Ensures bash commands have project-specific env vars from `.envrc` files.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pi install npm:pi-direnv
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## What it does
|
|
12
|
+
|
|
13
|
+
On `session_start`:
|
|
14
|
+
|
|
15
|
+
1. Checks if `direnv` is installed (skips silently if not)
|
|
16
|
+
2. Searches for `.envrc` from cwd up to the git root
|
|
17
|
+
3. Runs `direnv export json` and applies variables to `process.env`
|
|
18
|
+
4. Shows a notification with the count of loaded vars
|
|
19
|
+
5. Warns if `.envrc` is blocked (needs `direnv allow`)
|
|
20
|
+
|
|
21
|
+
## Why
|
|
22
|
+
|
|
23
|
+
Nix flakes + direnv is a common pattern. Without this extension, `pi exec` commands miss project-specific PATH entries, env vars, and tool versions defined in your flake's `devShell`.
|
|
24
|
+
|
|
25
|
+
Inspired by [simonwjackson/opencode-direnv](https://github.com/simonwjackson/opencode-direnv).
|
package/index.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-direnv Extension
|
|
3
|
+
*
|
|
4
|
+
* Automatically loads direnv environment variables at session start.
|
|
5
|
+
* Ensures bash commands have access to project-specific env vars
|
|
6
|
+
* defined in .envrc files (commonly used with Nix flakes).
|
|
7
|
+
*
|
|
8
|
+
* Behavior:
|
|
9
|
+
* - Searches for .envrc from cwd up to git root
|
|
10
|
+
* - Runs `direnv export json` and applies vars to process.env
|
|
11
|
+
* - Shows notification if .envrc is blocked or env loaded
|
|
12
|
+
* - Silently skips if direnv missing or no .envrc exists
|
|
13
|
+
*
|
|
14
|
+
* Inspired by https://github.com/simonwjackson/opencode-direnv
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
18
|
+
import { existsSync } from "node:fs";
|
|
19
|
+
import { dirname, join } from "node:path";
|
|
20
|
+
|
|
21
|
+
export default function (pi: ExtensionAPI) {
|
|
22
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
23
|
+
const cwd = process.cwd();
|
|
24
|
+
|
|
25
|
+
// Check direnv is available
|
|
26
|
+
try {
|
|
27
|
+
await pi.exec("which", ["direnv"]);
|
|
28
|
+
} catch {
|
|
29
|
+
return; // direnv not installed, skip silently
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Find .envrc searching upward to git root
|
|
33
|
+
const gitRoot = await findGitRoot(pi);
|
|
34
|
+
const envrcPath = findEnvrc(cwd, gitRoot);
|
|
35
|
+
if (!envrcPath) return;
|
|
36
|
+
|
|
37
|
+
const envrcDir = dirname(envrcPath);
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
const result = await pi.exec("direnv", ["export", "json"], { cwd: envrcDir });
|
|
41
|
+
const output = result.stdout?.trim();
|
|
42
|
+
if (!output) return;
|
|
43
|
+
|
|
44
|
+
const envVars = JSON.parse(output) as Record<string, string>;
|
|
45
|
+
const count = Object.keys(envVars).length;
|
|
46
|
+
|
|
47
|
+
// Apply to process.env so child processes inherit them
|
|
48
|
+
Object.assign(process.env, envVars);
|
|
49
|
+
|
|
50
|
+
ctx.ui.notify(`direnv: loaded ${count} env vars`, "info");
|
|
51
|
+
} catch (err: unknown) {
|
|
52
|
+
const stderr =
|
|
53
|
+
err && typeof err === "object" && "stderr" in err
|
|
54
|
+
? String((err as { stderr: unknown }).stderr)
|
|
55
|
+
: "";
|
|
56
|
+
|
|
57
|
+
if (stderr.includes("is blocked")) {
|
|
58
|
+
ctx.ui.notify("direnv: .envrc is blocked. Run `direnv allow` to enable.", "warning");
|
|
59
|
+
}
|
|
60
|
+
// Other errors (parse failures, etc.) — skip silently
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function findGitRoot(pi: ExtensionAPI): Promise<string | null> {
|
|
66
|
+
try {
|
|
67
|
+
const result = await pi.exec("git", ["rev-parse", "--show-toplevel"]);
|
|
68
|
+
return result.stdout?.trim() || null;
|
|
69
|
+
} catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function findEnvrc(startDir: string, stopAt: string | null): string | null {
|
|
75
|
+
const boundary = stopAt || "/";
|
|
76
|
+
let current = startDir;
|
|
77
|
+
|
|
78
|
+
while (true) {
|
|
79
|
+
const envrcPath = join(current, ".envrc");
|
|
80
|
+
if (existsSync(envrcPath)) return envrcPath;
|
|
81
|
+
|
|
82
|
+
if (current === boundary || current === "/") break;
|
|
83
|
+
|
|
84
|
+
const parent = dirname(current);
|
|
85
|
+
if (parent === current) break; // filesystem root
|
|
86
|
+
current = parent;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return null;
|
|
90
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pi-direnv",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Auto-load direnv environment at session start — ensures bash commands have project-specific env vars from .envrc",
|
|
6
|
+
"main": "./index.ts",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"pi",
|
|
9
|
+
"pi-extension",
|
|
10
|
+
"pi-package",
|
|
11
|
+
"direnv",
|
|
12
|
+
"nix",
|
|
13
|
+
"envrc"
|
|
14
|
+
],
|
|
15
|
+
"author": "Edmund Miller <edmundmiller@hey.com>",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/edmundmiller/dotfiles.git",
|
|
20
|
+
"directory": "pi-packages/pi-direnv"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"index.ts",
|
|
24
|
+
"README.md"
|
|
25
|
+
],
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"@mariozechner/pi-coding-agent": "*"
|
|
28
|
+
},
|
|
29
|
+
"pi": {
|
|
30
|
+
"extensions": [
|
|
31
|
+
"./index.ts"
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"typecheck": "tsc --noEmit"
|
|
36
|
+
}
|
|
37
|
+
}
|