@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.
@@ -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.1",
4
+ "version": "0.1.3",
5
5
  "description": "Shared utilities for pi packages",
6
- "homepage": "https://gajae-code.dev",
7
- "author": "Can Boluk",
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.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];