@gajae-code/utils 0.4.3 → 0.4.5

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.
@@ -37,6 +37,9 @@ export declare function $inheritedEnv(name: string): string | undefined;
37
37
  * All users should import this env module (import { $env } from "@gajae-code/utils")
38
38
  * before using environment variables. This ensures that .env files have been loaded and
39
39
  * overrides (project, home) have been applied, so $env always reflects the correct values.
40
+ *
41
+ * Provider credential resolution must not use this merged view because it includes the
42
+ * caller's cwd/.env. Use $credentialEnv/$pickCredentialEnv for model authentication.
40
43
  */
41
44
  export declare const $env: Record<string, string>;
42
45
  /**
@@ -45,6 +48,17 @@ export declare const $env: Record<string, string>;
45
48
  * @returns The first environment variable value, or undefined if no value is found.
46
49
  */
47
50
  export declare function $pickenv(...keys: string[]): string | undefined;
51
+ /**
52
+ * Resolve credential-bearing environment variables without consulting the caller's project .env.
53
+ *
54
+ * GJC loads cwd/.env into $env for project-aware tools, but model-provider authentication should
55
+ * only use values explicitly inherited from the launching shell or GJC/user-owned config files.
56
+ */
57
+ export declare function $credentialEnv(name: string): string | undefined;
58
+ /**
59
+ * Resolve the first credential env value from the given keys, excluding cwd/.env overlays.
60
+ */
61
+ export declare function $pickCredentialEnv(...keys: string[]): string | undefined;
48
62
  /**
49
63
  * Parses a positive decimal integer from `$env[name]`.
50
64
  * Empty, invalid, NaN, zero, or negative values return `defaultValue`.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@gajae-code/utils",
4
- "version": "0.4.3",
4
+ "version": "0.4.5",
5
5
  "description": "Shared utilities for pi packages",
6
6
  "homepage": "https://gaebal-gajae.dev",
7
7
  "author": "Yeachan-Heo",
@@ -31,7 +31,7 @@
31
31
  "fmt": "biome format --write ."
32
32
  },
33
33
  "dependencies": {
34
- "@gajae-code/natives": "0.4.3",
34
+ "@gajae-code/natives": "0.4.5",
35
35
  "beautiful-mermaid": "^1.1.3",
36
36
  "handlebars": "^4.7.9",
37
37
  "winston": "^3.19.0",
package/src/env.ts CHANGED
@@ -135,16 +135,32 @@ export function parseEnvFile(filePath: string): Record<string, string> {
135
135
  return result;
136
136
  }
137
137
 
138
- const inheritedEnv = filterProcessEnv(Bun.env);
139
-
140
- export function $inheritedEnv(name: string): string | undefined {
138
+ function resolveFileEnvValue(file: Record<string, string>, name: string): string | undefined {
141
139
  if (!isSafeEnvName(name)) return undefined;
142
- const value = inheritedEnv[name];
140
+ const value = file[name];
143
141
  if (value === undefined || !isSafeEnvValue(value)) return undefined;
144
142
  const trimmed = value.trim();
145
143
  return trimmed.length > 0 ? trimmed : undefined;
146
144
  }
147
145
 
146
+ function filterCredentialInheritedEnv(env: Record<string, string | undefined>): Record<string, string> {
147
+ const result: Record<string, string> = {};
148
+ for (const key in env) {
149
+ const value = env[key];
150
+ if (!isSafeEnvName(key) || value === undefined || !isSafeEnvValue(value)) continue;
151
+
152
+ // Bun may have already loaded cwd/.env before JS runs. It does not expose the
153
+ // source of each entry, so an exact match with projectEnv is ambiguous. Use
154
+ // the safer credential rule: ambiguous project matches are excluded from the
155
+ // credential-only inherited snapshot, while remaining available through $env.
156
+ const projectValue = resolveFileEnvValue(projectEnv, key);
157
+ if (projectValue !== undefined && projectValue === value) continue;
158
+
159
+ result[key] = value;
160
+ }
161
+ return result;
162
+ }
163
+
148
164
  // Eagerly parse the user's $HOME/.env and the current project's .env (from cwd)
149
165
  const homeShellEnv = {
150
166
  ...parseShellEnvFile(path.join(os.homedir(), ".zshenv")),
@@ -158,11 +174,10 @@ const piEnv = parseEnvFile(path.join(getConfigRootDir(), ".env"));
158
174
  const agentEnv = parseEnvFile(path.join(getAgentDir(), ".env"));
159
175
  const projectEnv = parseEnvFile(path.join(process.cwd(), ".env"));
160
176
 
161
- for (const key of Object.keys(Bun.env)) {
162
- const value = Bun.env[key];
163
- if (!isSafeEnvName(key) || value === undefined || !isSafeEnvValue(value)) {
164
- delete Bun.env[key];
165
- }
177
+ const inheritedEnv = filterCredentialInheritedEnv(Bun.env);
178
+
179
+ export function $inheritedEnv(name: string): string | undefined {
180
+ return resolveFileEnvValue(inheritedEnv, name);
166
181
  }
167
182
 
168
183
  for (const file of [projectEnv, agentEnv, piEnv, homeEnv, homeShellEnv]) {
@@ -179,6 +194,9 @@ for (const file of [projectEnv, agentEnv, piEnv, homeEnv, homeShellEnv]) {
179
194
  * All users should import this env module (import { $env } from "@gajae-code/utils")
180
195
  * before using environment variables. This ensures that .env files have been loaded and
181
196
  * overrides (project, home) have been applied, so $env always reflects the correct values.
197
+ *
198
+ * Provider credential resolution must not use this merged view because it includes the
199
+ * caller's cwd/.env. Use $credentialEnv/$pickCredentialEnv for model authentication.
182
200
  */
183
201
  export const $env: Record<string, string> = Bun.env as Record<string, string>;
184
202
 
@@ -197,6 +215,33 @@ export function $pickenv(...keys: string[]): string | undefined {
197
215
  return undefined;
198
216
  }
199
217
 
218
+ /**
219
+ * Resolve credential-bearing environment variables without consulting the caller's project .env.
220
+ *
221
+ * GJC loads cwd/.env into $env for project-aware tools, but model-provider authentication should
222
+ * only use values explicitly inherited from the launching shell or GJC/user-owned config files.
223
+ */
224
+ export function $credentialEnv(name: string): string | undefined {
225
+ return (
226
+ $inheritedEnv(name) ??
227
+ resolveFileEnvValue(agentEnv, name) ??
228
+ resolveFileEnvValue(piEnv, name) ??
229
+ resolveFileEnvValue(homeEnv, name) ??
230
+ resolveFileEnvValue(homeShellEnv, name)
231
+ );
232
+ }
233
+
234
+ /**
235
+ * Resolve the first credential env value from the given keys, excluding cwd/.env overlays.
236
+ */
237
+ export function $pickCredentialEnv(...keys: string[]): string | undefined {
238
+ for (const key of keys) {
239
+ const value = $credentialEnv(key);
240
+ if (value) return value;
241
+ }
242
+ return undefined;
243
+ }
244
+
200
245
  /**
201
246
  * Parses a positive decimal integer from `$env[name]`.
202
247
  * Empty, invalid, NaN, zero, or negative values return `defaultValue`.