@gajae-code/utils 0.4.4 → 0.5.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/dist/types/dirs.d.ts +16 -0
- package/dist/types/env.d.ts +14 -0
- package/package.json +2 -2
- package/src/dirs.ts +52 -0
- package/src/env.ts +73 -8
package/dist/types/dirs.d.ts
CHANGED
|
@@ -18,6 +18,22 @@ export declare const CONFIG_DIR_NAME: string;
|
|
|
18
18
|
export declare const VERSION: string;
|
|
19
19
|
/** Minimum Bun version */
|
|
20
20
|
export declare const MIN_BUN_VERSION: string;
|
|
21
|
+
/**
|
|
22
|
+
* Build the diagnostic shown when the Bun runtime executing `gjc` is older
|
|
23
|
+
* than {@link MIN_BUN_VERSION}. This is the most common Windows native-install
|
|
24
|
+
* failure (issue #525): `bun install -g gajae-code` probes a recent Bun while
|
|
25
|
+
* the `gjc` launcher resolves an older Bun still on PATH. The message names the
|
|
26
|
+
* exact detected runtime path and gives a platform-specific upgrade + PATH fix
|
|
27
|
+
* instead of a bare `bun upgrade`.
|
|
28
|
+
*
|
|
29
|
+
* Pure and platform-parameterized so it can be unit-tested cross-platform.
|
|
30
|
+
*/
|
|
31
|
+
export declare function formatBunRuntimeError(opts: {
|
|
32
|
+
currentVersion: string;
|
|
33
|
+
minVersion: string;
|
|
34
|
+
execPath?: string;
|
|
35
|
+
platform?: NodeJS.Platform;
|
|
36
|
+
}): string;
|
|
21
37
|
export declare function resolveEquivalentPath(inputPath: string): string;
|
|
22
38
|
export declare function normalizePathForComparison(inputPath: string): string;
|
|
23
39
|
export declare function pathIsWithin(root: string, candidate: string): boolean;
|
package/dist/types/env.d.ts
CHANGED
|
@@ -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
|
+
"version": "0.5.0",
|
|
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.
|
|
34
|
+
"@gajae-code/natives": "0.5.0",
|
|
35
35
|
"beautiful-mermaid": "^1.1.3",
|
|
36
36
|
"handlebars": "^4.7.9",
|
|
37
37
|
"winston": "^3.19.0",
|
package/src/dirs.ts
CHANGED
|
@@ -28,6 +28,58 @@ export const VERSION: string = version;
|
|
|
28
28
|
/** Minimum Bun version */
|
|
29
29
|
export const MIN_BUN_VERSION: string = engines.bun.replace(/[^0-9.]/g, "");
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Build the diagnostic shown when the Bun runtime executing `gjc` is older
|
|
33
|
+
* than {@link MIN_BUN_VERSION}. This is the most common Windows native-install
|
|
34
|
+
* failure (issue #525): `bun install -g gajae-code` probes a recent Bun while
|
|
35
|
+
* the `gjc` launcher resolves an older Bun still on PATH. The message names the
|
|
36
|
+
* exact detected runtime path and gives a platform-specific upgrade + PATH fix
|
|
37
|
+
* instead of a bare `bun upgrade`.
|
|
38
|
+
*
|
|
39
|
+
* Pure and platform-parameterized so it can be unit-tested cross-platform.
|
|
40
|
+
*/
|
|
41
|
+
export function formatBunRuntimeError(opts: {
|
|
42
|
+
currentVersion: string;
|
|
43
|
+
minVersion: string;
|
|
44
|
+
execPath?: string;
|
|
45
|
+
platform?: NodeJS.Platform;
|
|
46
|
+
}): string {
|
|
47
|
+
const platform = opts.platform ?? process.platform;
|
|
48
|
+
const lines = [
|
|
49
|
+
`error: ${APP_NAME} requires Bun >= ${opts.minVersion}, but the running Bun is v${opts.currentVersion}.`,
|
|
50
|
+
];
|
|
51
|
+
if (opts.execPath) {
|
|
52
|
+
lines.push(` detected Bun runtime: ${opts.execPath}`);
|
|
53
|
+
}
|
|
54
|
+
if (platform === "win32") {
|
|
55
|
+
lines.push(
|
|
56
|
+
"",
|
|
57
|
+
"The 'gjc' launcher is using an older Bun than the one used to install it.",
|
|
58
|
+
"Upgrade Bun, then restart your terminal so PATH and the runtime refresh:",
|
|
59
|
+
"",
|
|
60
|
+
' powershell -c "irm bun.sh/install.ps1|iex"',
|
|
61
|
+
"",
|
|
62
|
+
"After restarting the terminal, verify both versions match:",
|
|
63
|
+
" bun --version",
|
|
64
|
+
" gjc --version",
|
|
65
|
+
"",
|
|
66
|
+
"If 'gjc' still loads the old runtime, make sure %USERPROFILE%\\.bun\\bin is",
|
|
67
|
+
"first on PATH and remove any stale Bun installs shadowing it.",
|
|
68
|
+
);
|
|
69
|
+
} else {
|
|
70
|
+
lines.push(
|
|
71
|
+
"",
|
|
72
|
+
"Upgrade Bun, then restart your terminal:",
|
|
73
|
+
" bun upgrade",
|
|
74
|
+
"",
|
|
75
|
+
"Then verify:",
|
|
76
|
+
" bun --version",
|
|
77
|
+
" gjc --version",
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
return `${lines.join("\n")}\n`;
|
|
81
|
+
}
|
|
82
|
+
|
|
31
83
|
// =============================================================================
|
|
32
84
|
// Project directory
|
|
33
85
|
// =============================================================================
|
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
|
-
|
|
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 =
|
|
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,29 @@ 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
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
177
|
+
const inheritedEnv = filterCredentialInheritedEnv(Bun.env);
|
|
178
|
+
|
|
179
|
+
export function $inheritedEnv(name: string): string | undefined {
|
|
180
|
+
return resolveFileEnvValue(inheritedEnv, name);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function resolveLiveCredentialEnvValue(name: string): string | undefined {
|
|
184
|
+
if (!isSafeEnvName(name)) return undefined;
|
|
185
|
+
const value = Bun.env[name];
|
|
186
|
+
if (value === undefined || !isSafeEnvValue(value)) return undefined;
|
|
187
|
+
const trimmed = value.trim();
|
|
188
|
+
if (trimmed.length === 0) return undefined;
|
|
189
|
+
|
|
190
|
+
const projectValue = resolveFileEnvValue(projectEnv, name);
|
|
191
|
+
if (
|
|
192
|
+
projectValue !== undefined &&
|
|
193
|
+
projectValue === trimmed &&
|
|
194
|
+
resolveFileEnvValue(inheritedEnv, name) === undefined
|
|
195
|
+
) {
|
|
196
|
+
return undefined;
|
|
165
197
|
}
|
|
198
|
+
|
|
199
|
+
return trimmed;
|
|
166
200
|
}
|
|
167
201
|
|
|
168
202
|
for (const file of [projectEnv, agentEnv, piEnv, homeEnv, homeShellEnv]) {
|
|
@@ -179,6 +213,9 @@ for (const file of [projectEnv, agentEnv, piEnv, homeEnv, homeShellEnv]) {
|
|
|
179
213
|
* All users should import this env module (import { $env } from "@gajae-code/utils")
|
|
180
214
|
* before using environment variables. This ensures that .env files have been loaded and
|
|
181
215
|
* overrides (project, home) have been applied, so $env always reflects the correct values.
|
|
216
|
+
*
|
|
217
|
+
* Provider credential resolution must not use this merged view because it includes the
|
|
218
|
+
* caller's cwd/.env. Use $credentialEnv/$pickCredentialEnv for model authentication.
|
|
182
219
|
*/
|
|
183
220
|
export const $env: Record<string, string> = Bun.env as Record<string, string>;
|
|
184
221
|
|
|
@@ -197,6 +234,34 @@ export function $pickenv(...keys: string[]): string | undefined {
|
|
|
197
234
|
return undefined;
|
|
198
235
|
}
|
|
199
236
|
|
|
237
|
+
/**
|
|
238
|
+
* Resolve credential-bearing environment variables without consulting the caller's project .env.
|
|
239
|
+
*
|
|
240
|
+
* GJC loads cwd/.env into $env for project-aware tools, but model-provider authentication should
|
|
241
|
+
* only use values explicitly inherited from the launching shell or GJC/user-owned config files.
|
|
242
|
+
*/
|
|
243
|
+
export function $credentialEnv(name: string): string | undefined {
|
|
244
|
+
return (
|
|
245
|
+
$inheritedEnv(name) ??
|
|
246
|
+
resolveLiveCredentialEnvValue(name) ??
|
|
247
|
+
resolveFileEnvValue(agentEnv, name) ??
|
|
248
|
+
resolveFileEnvValue(piEnv, name) ??
|
|
249
|
+
resolveFileEnvValue(homeEnv, name) ??
|
|
250
|
+
resolveFileEnvValue(homeShellEnv, name)
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Resolve the first credential env value from the given keys, excluding cwd/.env overlays.
|
|
256
|
+
*/
|
|
257
|
+
export function $pickCredentialEnv(...keys: string[]): string | undefined {
|
|
258
|
+
for (const key of keys) {
|
|
259
|
+
const value = $credentialEnv(key);
|
|
260
|
+
if (value) return value;
|
|
261
|
+
}
|
|
262
|
+
return undefined;
|
|
263
|
+
}
|
|
264
|
+
|
|
200
265
|
/**
|
|
201
266
|
* Parses a positive decimal integer from `$env[name]`.
|
|
202
267
|
* Empty, invalid, NaN, zero, or negative values return `defaultValue`.
|