@gajae-code/utils 0.1.1 → 0.1.3
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/dist/types/env.d.ts +8 -0
- package/package.json +4 -4
- package/src/env.ts +65 -1
package/dist/types/env.d.ts
CHANGED
|
@@ -15,6 +15,14 @@ export declare function isValidEnvName(name: string): boolean;
|
|
|
15
15
|
export declare function isSafeEnvName(name: string): boolean;
|
|
16
16
|
export declare function isSafeEnvValue(value: string): boolean;
|
|
17
17
|
export declare function filterProcessEnv(env: Record<string, string | undefined>): Record<string, string>;
|
|
18
|
+
/**
|
|
19
|
+
* Parses simple POSIX shell environment assignments from files such as
|
|
20
|
+
* ~/.zshrc without executing user shell code. Supports `export KEY=value` and
|
|
21
|
+
* `KEY=value`, including single/double quoted literal values. Dynamic shell
|
|
22
|
+
* expressions are intentionally ignored because evaluating startup files would
|
|
23
|
+
* run arbitrary code during CLI startup.
|
|
24
|
+
*/
|
|
25
|
+
export declare function parseShellEnvFile(filePath: string): Record<string, string>;
|
|
18
26
|
/**
|
|
19
27
|
* Parses a .env file synchronously and extracts key-value string pairs.
|
|
20
28
|
* Ignores lines that are empty or start with '#'. Trims whitespace.
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gajae-code/utils",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.3",
|
|
5
5
|
"description": "Shared utilities for pi packages",
|
|
6
|
-
"homepage": "https://gajae
|
|
7
|
-
"author": "
|
|
6
|
+
"homepage": "https://gaebal-gajae.dev",
|
|
7
|
+
"author": "Yeachan-Heo",
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"fmt": "biome format --write ."
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@gajae-code/natives": "0.1.
|
|
34
|
+
"@gajae-code/natives": "0.1.3",
|
|
35
35
|
"beautiful-mermaid": "^1.1.3",
|
|
36
36
|
"handlebars": "^4.7.9",
|
|
37
37
|
"winston": "^3.19.0",
|
package/src/env.ts
CHANGED
|
@@ -40,6 +40,63 @@ export function filterProcessEnv(env: Record<string, string | undefined>): Recor
|
|
|
40
40
|
return result;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
function stripInlineShellComment(value: string): string {
|
|
44
|
+
let quote: '"' | "'" | undefined;
|
|
45
|
+
for (let i = 0; i < value.length; i++) {
|
|
46
|
+
const char = value[i];
|
|
47
|
+
if (char === "\\") {
|
|
48
|
+
i++;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if ((char === '"' || char === "'") && (!quote || quote === char)) {
|
|
52
|
+
quote = quote ? undefined : char;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (char === "#" && !quote && (i === 0 || /\s/.test(value[i - 1] ?? ""))) {
|
|
56
|
+
return value.slice(0, i).trimEnd();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return value.trimEnd();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Parses simple POSIX shell environment assignments from files such as
|
|
64
|
+
* ~/.zshrc without executing user shell code. Supports `export KEY=value` and
|
|
65
|
+
* `KEY=value`, including single/double quoted literal values. Dynamic shell
|
|
66
|
+
* expressions are intentionally ignored because evaluating startup files would
|
|
67
|
+
* run arbitrary code during CLI startup.
|
|
68
|
+
*/
|
|
69
|
+
export function parseShellEnvFile(filePath: string): Record<string, string> {
|
|
70
|
+
const result: Record<string, string> = {};
|
|
71
|
+
try {
|
|
72
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
73
|
+
for (const line of content.split("\n")) {
|
|
74
|
+
const trimmed = line.trim();
|
|
75
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
76
|
+
|
|
77
|
+
const match = /^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)=(.*)$/.exec(trimmed);
|
|
78
|
+
if (!match) continue;
|
|
79
|
+
|
|
80
|
+
const key = match[1];
|
|
81
|
+
if (!isValidEnvName(key)) continue;
|
|
82
|
+
|
|
83
|
+
let value = stripInlineShellComment(match[2] ?? "").trim();
|
|
84
|
+
if (value.endsWith(";")) value = value.slice(0, -1).trimEnd();
|
|
85
|
+
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
86
|
+
value = value.slice(1, -1);
|
|
87
|
+
}
|
|
88
|
+
if (!isSafeEnvValue(value)) continue;
|
|
89
|
+
if (/[$`]/.test(value)) continue;
|
|
90
|
+
|
|
91
|
+
result[key] = value;
|
|
92
|
+
}
|
|
93
|
+
} catch {
|
|
94
|
+
// File doesn't exist or can't be read - return empty result
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
|
|
43
100
|
/**
|
|
44
101
|
* Parses a .env file synchronously and extracts key-value string pairs.
|
|
45
102
|
* Ignores lines that are empty or start with '#'. Trims whitespace.
|
|
@@ -79,6 +136,13 @@ export function parseEnvFile(filePath: string): Record<string, string> {
|
|
|
79
136
|
}
|
|
80
137
|
|
|
81
138
|
// Eagerly parse the user's $HOME/.env and the current project's .env (from cwd)
|
|
139
|
+
const homeShellEnv = {
|
|
140
|
+
...parseShellEnvFile(path.join(os.homedir(), ".zshenv")),
|
|
141
|
+
...parseShellEnvFile(path.join(os.homedir(), ".zprofile")),
|
|
142
|
+
...parseShellEnvFile(path.join(os.homedir(), ".zshrc")),
|
|
143
|
+
...parseShellEnvFile(path.join(os.homedir(), ".bash_profile")),
|
|
144
|
+
...parseShellEnvFile(path.join(os.homedir(), ".bashrc")),
|
|
145
|
+
};
|
|
82
146
|
const homeEnv = parseEnvFile(path.join(os.homedir(), ".env"));
|
|
83
147
|
const piEnv = parseEnvFile(path.join(getConfigRootDir(), ".env"));
|
|
84
148
|
const agentEnv = parseEnvFile(path.join(getAgentDir(), ".env"));
|
|
@@ -91,7 +155,7 @@ for (const key of Object.keys(Bun.env)) {
|
|
|
91
155
|
}
|
|
92
156
|
}
|
|
93
157
|
|
|
94
|
-
for (const file of [projectEnv, agentEnv, piEnv, homeEnv]) {
|
|
158
|
+
for (const file of [projectEnv, agentEnv, piEnv, homeEnv, homeShellEnv]) {
|
|
95
159
|
for (const key in file) {
|
|
96
160
|
if (!Bun.env[key]) {
|
|
97
161
|
Bun.env[key] = file[key];
|