infra-kit 0.1.74 → 0.1.75

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "infra-kit",
3
3
  "type": "module",
4
- "version": "0.1.74",
4
+ "version": "0.1.75",
5
5
  "description": "infra-kit",
6
6
  "main": "dist/cli.js",
7
7
  "module": "dist/cli.js",
@@ -3,24 +3,26 @@ import path from 'node:path'
3
3
  import process from 'node:process'
4
4
  import { z } from 'zod'
5
5
 
6
- import type { EnvCache } from 'src/lib/constants'
7
6
  import {
8
- ENV_CACHE_DIR,
9
- ENV_CACHE_FILE,
7
+ ENV_CLEAR_FILE,
8
+ ENV_LOAD_FILE,
9
+ getSessionCacheDir,
10
10
  INFRA_KIT_ENV_CONFIG_VAR,
11
11
  INFRA_KIT_ENV_LOADED_AT_VAR,
12
12
  INFRA_KIT_ENV_PROJECT_VAR,
13
+ parseVarNamesFromEnvFile,
13
14
  } from 'src/lib/constants'
14
15
  import { logger } from 'src/lib/logger'
15
16
  import type { ToolsExecutionResult } from 'src/types'
16
17
 
17
18
  /**
18
- * Clear previously loaded environment variables. Usage: source <(infra-kit env-clear)
19
+ * Clear previously loaded environment variables. Usage: env-clear (after running eval "$(infra-kit env-init)" in shell)
19
20
  */
20
21
  export const envClear = async (): Promise<ToolsExecutionResult> => {
21
- const cachePath = path.join(ENV_CACHE_DIR, ENV_CACHE_FILE)
22
+ const cacheDir = getSessionCacheDir()
23
+ const envLoadPath = path.join(cacheDir, ENV_LOAD_FILE)
22
24
 
23
- if (!process.env[INFRA_KIT_ENV_CONFIG_VAR]) {
25
+ if (!fs.existsSync(envLoadPath)) {
24
26
  logger.error('No loaded environment found. Run `env-load` first.')
25
27
 
26
28
  return {
@@ -33,46 +35,35 @@ export const envClear = async (): Promise<ToolsExecutionResult> => {
33
35
  }
34
36
  }
35
37
 
36
- const cache: EnvCache = JSON.parse(fs.readFileSync(cachePath, 'utf-8'))
37
- const varNames = cache.varNames
38
+ const varNames = parseVarNamesFromEnvFile(envLoadPath)
38
39
 
39
- // Only unset vars that are actually set in the current session
40
- const activeVars = varNames.filter((v) => {
41
- return v in process.env
42
- })
40
+ // Build unset script
41
+ const unsetLines = [
42
+ ...varNames.map((v) => {
43
+ return `unset ${v}`
44
+ }),
45
+ `unset ${INFRA_KIT_ENV_CONFIG_VAR}`,
46
+ `unset ${INFRA_KIT_ENV_PROJECT_VAR}`,
47
+ `unset ${INFRA_KIT_ENV_LOADED_AT_VAR}`,
48
+ ]
43
49
 
44
- if (activeVars.length === 0) {
45
- fs.unlinkSync(cachePath)
46
- logger.info('Current session is clear, no environment variables to unset.')
50
+ // Write unset script to cache
51
+ const clearFilePath = path.resolve(cacheDir, ENV_CLEAR_FILE)
47
52
 
48
- return {
49
- content: [
50
- {
51
- type: 'text',
52
- text: 'Current session is clear, no environment variables to unset.',
53
- },
54
- ],
55
- }
56
- }
53
+ fs.mkdirSync(cacheDir, { recursive: true })
54
+ fs.writeFileSync(clearFilePath, `${unsetLines.join('\n')}\n`)
57
55
 
58
- // Output unset statements for shell sourcing
59
- for (const varName of activeVars) {
60
- process.stdout.write(`unset ${varName}\n`)
61
- }
62
- process.stdout.write(`unset ${INFRA_KIT_ENV_CONFIG_VAR}\n`)
63
- process.stdout.write(`unset ${INFRA_KIT_ENV_PROJECT_VAR}\n`)
64
- process.stdout.write(`unset ${INFRA_KIT_ENV_LOADED_AT_VAR}\n`)
56
+ // REQUIRED
57
+ process.stdout.write(`${clearFilePath}\n`)
65
58
 
66
- // Remove cache file
67
- fs.unlinkSync(cachePath)
59
+ // Remove env load file so env-clear can detect "no env loaded" next time
60
+ fs.unlinkSync(envLoadPath)
68
61
 
69
- logger.info(`Cleared ${activeVars.length} environment variables`)
62
+ logger.info(`Cleared ${varNames.length} environment variables`)
70
63
 
71
64
  const structuredContent = {
72
- variableCount: activeVars.length,
73
- unsetStatements: activeVars.map((v) => {
74
- return `unset ${v}`
75
- }),
65
+ variableCount: varNames.length,
66
+ unsetStatements: unsetLines,
76
67
  }
77
68
 
78
69
  return {
@@ -89,7 +80,8 @@ export const envClear = async (): Promise<ToolsExecutionResult> => {
89
80
  // MCP Tool Registration
90
81
  export const envClearMcpTool = {
91
82
  name: 'env-clear',
92
- description: 'Clear previously loaded environment variables. Usage: source <(infra-kit env-clear)',
83
+ description:
84
+ 'Clear previously loaded environment variables. Usage: env-clear (after running eval "$(infra-kit env-init)" in shell)',
93
85
  inputSchema: {},
94
86
  outputSchema: {
95
87
  variableCount: z.number().describe('Number of variables cleared'),
@@ -0,0 +1,83 @@
1
+ import fs from 'node:fs'
2
+ import os from 'node:os'
3
+ import path from 'node:path'
4
+ import process from 'node:process'
5
+
6
+ import { logger } from 'src/lib/logger'
7
+
8
+ const MARKER_COMMENT = '# infra-kit shell functions'
9
+
10
+ /**
11
+ * Append infra-kit shell functions directly to .zshrc.
12
+ */
13
+ export const envInit = async (): Promise<void> => {
14
+ const zshrcPath = path.join(os.homedir(), '.zshrc')
15
+ const binPath = getBinPath()
16
+
17
+ if (!fs.existsSync(binPath)) {
18
+ logger.error(`Could not find infra-kit binary at ${binPath}`)
19
+
20
+ return
21
+ }
22
+
23
+ const shellBlock = buildShellBlock(binPath)
24
+
25
+ if (fs.existsSync(zshrcPath)) {
26
+ const content = fs.readFileSync(zshrcPath, 'utf-8')
27
+ const cleaned = removeExistingBlock(content)
28
+
29
+ fs.writeFileSync(zshrcPath, cleaned)
30
+ }
31
+
32
+ fs.appendFileSync(zshrcPath, `\n${shellBlock}\n`)
33
+ logger.info(`Added infra-kit shell functions to ${zshrcPath}`)
34
+ logger.info('Run `source ~/.zshrc` or open a new terminal to activate.')
35
+ }
36
+
37
+ const getBinPath = (): string => {
38
+ // resolve the absolute path to the infra-kit binary
39
+ return path.resolve(path.join(path.dirname(process.argv[1]!), 'cli.js'))
40
+ }
41
+
42
+ const isBlockLine = (line: string): boolean => {
43
+ return (
44
+ line.startsWith('#') ||
45
+ line.startsWith('env-load') ||
46
+ line.startsWith('env-clear') ||
47
+ line.startsWith('if ') ||
48
+ line.startsWith(' export INFRA_KIT_SESSION') ||
49
+ line.startsWith('fi')
50
+ )
51
+ }
52
+
53
+ const removeExistingBlock = (content: string): string => {
54
+ const markerIdx = content.indexOf(MARKER_COMMENT)
55
+
56
+ if (markerIdx === -1) return content
57
+
58
+ const before = content.slice(0, markerIdx).replace(/\n+$/, '')
59
+ const afterLines = content.slice(markerIdx).split('\n')
60
+
61
+ let i = 0
62
+
63
+ while (i < afterLines.length && isBlockLine(afterLines[i]!)) {
64
+ i++
65
+ }
66
+
67
+ const remaining = afterLines.slice(i).join('\n')
68
+
69
+ return before + (remaining ? `\n${remaining}` : '')
70
+ }
71
+
72
+ const buildShellBlock = (binPath: string): string => {
73
+ const runCmd = `node ${binPath}`
74
+
75
+ return [
76
+ MARKER_COMMENT,
77
+ 'if [[ -z "${INFRA_KIT_SESSION}" ]]; then',
78
+ ' export INFRA_KIT_SESSION=$(head -c 4 /dev/urandom | xxd -p)',
79
+ 'fi',
80
+ `env-load() { local f; f=$(${runCmd} env-load "$@") && source "$f"; }`,
81
+ `env-clear() { local f; f=$(${runCmd} env-clear) && source "$f"; }`,
82
+ ].join('\n')
83
+ }
@@ -0,0 +1 @@
1
+ export { envInit } from './env-init'
@@ -1,3 +1,4 @@
1
+ import select from '@inquirer/select'
1
2
  import fs from 'node:fs'
2
3
  import path from 'node:path'
3
4
  import process from 'node:process'
@@ -6,19 +7,21 @@ import { $ } from 'zx'
6
7
 
7
8
  import { validateDopplerCliAndAuth } from 'src/integrations/doppler'
8
9
  import { getDopplerProject } from 'src/integrations/doppler/doppler-project'
9
- import type { EnvCache } from 'src/lib/constants'
10
+ import { commandEcho } from 'src/lib/command-echo'
10
11
  import {
11
- ENV_CACHE_DIR,
12
- ENV_CACHE_FILE,
12
+ ENV_LOAD_FILE,
13
+ ENVs,
13
14
  INFRA_KIT_ENV_CONFIG_VAR,
14
15
  INFRA_KIT_ENV_LOADED_AT_VAR,
15
16
  INFRA_KIT_ENV_PROJECT_VAR,
17
+ getSessionCacheDir,
16
18
  } from 'src/lib/constants'
17
19
  import { logger } from 'src/lib/logger'
18
20
  import type { ToolsExecutionResult } from 'src/types'
19
21
 
20
22
  interface EnvLoadArgs {
21
- config: string
23
+ config?: string
24
+ quiet?: boolean
22
25
  }
23
26
 
24
27
  /**
@@ -27,44 +30,66 @@ interface EnvLoadArgs {
27
30
  export const envLoad = async (args: EnvLoadArgs): Promise<ToolsExecutionResult> => {
28
31
  await validateDopplerCliAndAuth()
29
32
 
30
- const { config } = args
33
+ const { config, quiet } = args
34
+
35
+ commandEcho.start('env-load')
36
+
37
+ let selectedConfig = ''
38
+
39
+ if (config) {
40
+ selectedConfig = config
41
+ } else {
42
+ commandEcho.setInteractive()
43
+ selectedConfig = await select({
44
+ message: 'Select environment config',
45
+ choices: ENVs.map((env) => {
46
+ return { name: env, value: env }
47
+ }),
48
+ })
49
+ }
50
+
51
+ commandEcho.addOption('--config', selectedConfig)
31
52
 
32
53
  const project = await getDopplerProject()
33
54
 
34
- const result = await $`doppler secrets download --no-file --format env --project ${project} --config ${config}`
55
+ $.quiet = true
56
+ const result =
57
+ await $`doppler secrets download --no-file --format env --project ${project} --config ${selectedConfig}`
58
+
59
+ $.quiet = false
35
60
  const envContent = result.stdout.trim()
36
61
 
37
- // Output shell-sourceable format
38
- process.stdout.write('set -a\n')
39
- process.stdout.write(`${envContent}\n`)
40
- process.stdout.write('set +a\n')
41
- process.stdout.write(`export ${INFRA_KIT_ENV_CONFIG_VAR}=${config}\n`)
42
- process.stdout.write(`export ${INFRA_KIT_ENV_PROJECT_VAR}=${project}\n`)
43
- process.stdout.write(`export ${INFRA_KIT_ENV_LOADED_AT_VAR}=${new Date().toISOString()}\n`)
44
-
45
- // Extract variable names and save to cache
46
- const varNames = envContent
47
- .split('\n')
48
- .filter((line) => {
49
- return line.includes('=')
50
- })
51
- .map((line) => {
52
- return line.split('=')[0]!
53
- })
62
+ // Build env file content in dotenv format
63
+ const loadedAt = new Date().toISOString()
64
+ const envFileLines = [
65
+ 'set -a',
66
+ envContent,
67
+ `${INFRA_KIT_ENV_CONFIG_VAR}=${selectedConfig}`,
68
+ `${INFRA_KIT_ENV_PROJECT_VAR}=${project}`,
69
+ `${INFRA_KIT_ENV_LOADED_AT_VAR}=${loadedAt}`,
70
+ 'set +a',
71
+ ]
54
72
 
55
- const cachePath = path.join(ENV_CACHE_DIR, ENV_CACHE_FILE)
73
+ // Write env file to cache
74
+ const cacheDir = getSessionCacheDir()
75
+ const envFilePath = path.resolve(cacheDir, ENV_LOAD_FILE)
56
76
 
57
- const cache: EnvCache = { config, loadedAt: new Date().toISOString(), varNames }
77
+ fs.mkdirSync(cacheDir, { recursive: true })
78
+ fs.writeFileSync(envFilePath, `${envFileLines.join('\n')}\n`)
58
79
 
59
- fs.mkdirSync(ENV_CACHE_DIR, { recursive: true })
60
- fs.writeFileSync(cachePath, JSON.stringify(cache, null, 2))
80
+ // REQUIRED
81
+ process.stdout.write(`${envFilePath}\n`)
61
82
 
62
- logger.info(`Loaded ${varNames.length} variables from ${project}/${config}`)
83
+ const varCount = envContent.split('\n').filter((line) => line.includes('=')).length
84
+
85
+ if (!quiet) {
86
+ logger.info(`Loaded ${varCount} variables from ${project}/${selectedConfig}`)
87
+ }
63
88
 
64
89
  const structuredContent = {
65
- variableCount: varNames.length,
90
+ variableCount: varCount,
66
91
  project,
67
- config,
92
+ config: selectedConfig,
68
93
  }
69
94
 
70
95
  return {
@@ -81,7 +106,8 @@ export const envLoad = async (args: EnvLoadArgs): Promise<ToolsExecutionResult>
81
106
  // MCP Tool Registration
82
107
  export const envLoadMcpTool = {
83
108
  name: 'env-load',
84
- description: 'Load environment variables from Doppler for a given config. Usage: source <(infra-kit env-load -c dev)',
109
+ description:
110
+ 'Load environment variables from Doppler for a given config. Usage: env-load -c dev (after running eval "$(infra-kit env-init)" in shell)',
85
111
  inputSchema: {
86
112
  config: z.string().describe('Environment config name to load (e.g. dev, arthur, renana)'),
87
113
  },
@@ -1,18 +1,18 @@
1
- import fs from 'node:fs'
2
1
  import path from 'node:path'
3
2
  import process from 'node:process'
4
3
  import { z } from 'zod'
5
4
 
6
5
  import { validateDopplerCliAndAuth } from 'src/integrations/doppler'
7
6
  import { getDopplerProject } from 'src/integrations/doppler/doppler-project'
8
- import type { EnvCache } from 'src/lib/constants'
9
7
  import {
10
- ENV_CACHE_DIR,
11
- ENV_CACHE_FILE,
8
+ ENV_LOAD_FILE,
12
9
  ENVs,
13
10
  INFRA_KIT_ENV_CONFIG_VAR,
14
11
  INFRA_KIT_ENV_LOADED_AT_VAR,
15
12
  INFRA_KIT_ENV_PROJECT_VAR,
13
+ INFRA_KIT_SESSION_VAR,
14
+ getSessionCacheDir,
15
+ parseVarNamesFromEnvFile,
16
16
  } from 'src/lib/constants'
17
17
  import { logger } from 'src/lib/logger'
18
18
  import type { ToolsExecutionResult } from 'src/types'
@@ -30,8 +30,11 @@ export const envStatus = async (): Promise<ToolsExecutionResult> => {
30
30
  logger.info(` Detected Project: ${project}`)
31
31
  logger.info(` Available Configs: ${ENVs.join(', ')}`)
32
32
 
33
- // Check session-loaded vars
34
- const cachePath = path.join(ENV_CACHE_DIR, ENV_CACHE_FILE)
33
+ // Check session-loaded vars — getSessionCacheDir() throws if INFRA_KIT_SESSION is unset
34
+ const cacheDir = getSessionCacheDir()
35
+
36
+ const sessionId = process.env[INFRA_KIT_SESSION_VAR]!
37
+ const envLoadPath = path.join(cacheDir, ENV_LOAD_FILE)
35
38
 
36
39
  let sessionLoadedCount = 0
37
40
  let sessionTotalCount = 0
@@ -40,11 +43,11 @@ export const envStatus = async (): Promise<ToolsExecutionResult> => {
40
43
  const sessionLoadedAt = process.env[INFRA_KIT_ENV_LOADED_AT_VAR] ?? null
41
44
 
42
45
  if (sessionConfig) {
43
- if (fs.existsSync(cachePath)) {
44
- const cache: EnvCache = JSON.parse(fs.readFileSync(cachePath, 'utf-8'))
46
+ const varNames = parseVarNamesFromEnvFile(envLoadPath)
45
47
 
46
- sessionTotalCount = cache.varNames.length
47
- sessionLoadedCount = cache.varNames.filter((v) => {
48
+ if (varNames.length > 0) {
49
+ sessionTotalCount = varNames.length
50
+ sessionLoadedCount = varNames.filter((v) => {
48
51
  return v in process.env
49
52
  }).length
50
53
  }
@@ -52,6 +55,7 @@ export const envStatus = async (): Promise<ToolsExecutionResult> => {
52
55
  logger.info(
53
56
  ` Session: ${sessionLoadedCount} of ${sessionTotalCount} vars loaded (project: ${sessionProject}, config: ${sessionConfig}, loaded at: ${sessionLoadedAt})`,
54
57
  )
58
+ logger.info(` Session ID: ${sessionId}`)
55
59
  } else {
56
60
  logger.info(' Session: no env loaded')
57
61
  }
@@ -60,6 +64,7 @@ export const envStatus = async (): Promise<ToolsExecutionResult> => {
60
64
  authenticated: true,
61
65
  project,
62
66
  configs: ENVs,
67
+ sessionId,
63
68
  sessionLoadedCount,
64
69
  sessionTotalCount,
65
70
  sessionConfig,
@@ -87,6 +92,7 @@ export const envStatusMcpTool = {
87
92
  authenticated: z.boolean().describe('Whether the user is authenticated'),
88
93
  project: z.string().describe('Detected Doppler project name'),
89
94
  configs: z.array(z.string()).describe('Available environment configs'),
95
+ sessionId: z.string().describe('Current terminal session ID'),
90
96
  sessionLoadedCount: z.number().describe('Number of cached vars active in the current session'),
91
97
  sessionTotalCount: z.number().describe('Total number of cached var names'),
92
98
  sessionConfig: z.string().nullable().describe('Doppler config name of the loaded session'),
package/src/entry/cli.ts CHANGED
@@ -2,6 +2,7 @@ import { Command } from 'commander'
2
2
 
3
3
  import { doctor } from 'src/commands/doctor'
4
4
  import { envClear } from 'src/commands/env-clear'
5
+ import { envInit } from 'src/commands/env-init'
5
6
  import { envList } from 'src/commands/env-list'
6
7
  import { envLoad } from 'src/commands/env-load'
7
8
  import { envStatus } from 'src/commands/env-status'
@@ -18,10 +19,6 @@ import { worktreesAdd } from 'src/commands/worktrees-add'
18
19
  import { worktreesList } from 'src/commands/worktrees-list'
19
20
  import { worktreesRemove } from 'src/commands/worktrees-remove'
20
21
  import { worktreesSync } from 'src/commands/worktrees-sync'
21
- import { loadEnvFromGitRoot } from 'src/lib/load-env'
22
-
23
- // Load .env before anything else
24
- await loadEnvFromGitRoot()
25
22
 
26
23
  const program = new Command()
27
24
 
@@ -177,17 +174,25 @@ program
177
174
  await envList()
178
175
  })
179
176
 
177
+ program
178
+ .command('env-init')
179
+ .description('Set up shell functions for env-load/env-clear in .zshrc')
180
+ .action(async () => {
181
+ await envInit()
182
+ })
183
+
180
184
  program
181
185
  .command('env-load')
182
- .description('Load environment variables from Doppler. Usage: source <(infra-kit env-load -c dev)')
183
- .requiredOption('-c, --config <config>', 'Environment config name to load (e.g. dev, arthur)')
186
+ .description('Load environment variables from Doppler. Usage: env-load -c dev (after shell init)')
187
+ .option('-c, --config <config>', 'Environment config name to load (e.g. dev, arthur)')
188
+ .option('-q, --quiet', 'Suppress info logging')
184
189
  .action(async (options) => {
185
- await envLoad({ config: options.config })
190
+ await envLoad({ config: options.config, quiet: options.quiet })
186
191
  })
187
192
 
188
193
  program
189
194
  .command('env-clear')
190
- .description('Clear previously loaded environment variables. Usage: source <(infra-kit env-clear)')
195
+ .description('Clear previously loaded environment variables. Usage: env-clear (after shell init)')
191
196
  .action(async () => {
192
197
  await envClear()
193
198
  })
package/src/entry/mcp.ts CHANGED
@@ -1,16 +1,11 @@
1
- /* eslint-disable antfu/no-top-level-await */
2
1
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
3
2
  import process from 'node:process'
4
3
 
5
4
  import { setupErrorHandlers } from 'src/lib/error-handlers'
6
- import { loadEnvFromGitRoot } from 'src/lib/load-env'
7
5
  import { initLoggerMcp } from 'src/lib/logger'
8
6
 
9
7
  import { createMcpServer } from '../mcp/server'
10
8
 
11
- // Load .env before anything else
12
- await loadEnvFromGitRoot()
13
-
14
9
  const logger = initLoggerMcp()
15
10
 
16
11
  const startServer = async () => {
@@ -1,3 +1,7 @@
1
+ import fs from 'node:fs'
2
+ import path from 'node:path'
3
+ import process from 'node:process'
4
+
1
5
  /**
2
6
  * List of environments for the project deployment
3
7
  */
@@ -9,16 +13,33 @@ export const DOPPLER_PROJECT_MAP: Record<string, string> = {
9
13
  }
10
14
 
11
15
  export const ENV_CACHE_DIR = './node_modules/.cache/infra-kit'
12
- export const ENV_CACHE_FILE = 'env-cache.json'
16
+ export const ENV_LOAD_FILE = 'env-load.env'
17
+ export const ENV_CLEAR_FILE = 'env-clear.sh'
13
18
 
19
+ export const INFRA_KIT_SESSION_VAR = 'INFRA_KIT_SESSION'
14
20
  export const INFRA_KIT_ENV_CONFIG_VAR = 'INFRA_KIT_ENV_CONFIG'
15
21
  export const INFRA_KIT_ENV_PROJECT_VAR = 'INFRA_KIT_ENV_PROJECT'
16
22
  export const INFRA_KIT_ENV_LOADED_AT_VAR = 'INFRA_KIT_ENV_LOADED_AT'
17
23
 
18
- export interface EnvCache {
19
- config: string
20
- loadedAt: string
21
- varNames: string[]
24
+ export const parseVarNamesFromEnvFile = (filePath: string): string[] => {
25
+ if (!fs.existsSync(filePath)) return []
26
+
27
+ const content = fs.readFileSync(filePath, 'utf-8')
28
+
29
+ return content
30
+ .split('\n')
31
+ .filter((line) => line.includes('=') && !line.startsWith('set '))
32
+ .map((line) => line.split('=')[0]!)
33
+ }
34
+
35
+ export const getSessionCacheDir = (): string => {
36
+ const session = process.env[INFRA_KIT_SESSION_VAR]
37
+
38
+ if (!session) {
39
+ throw new Error('INFRA_KIT_SESSION is not set. Run `source ~/.zshrc` or `infra-kit env-init` first.')
40
+ }
41
+
42
+ return path.join(ENV_CACHE_DIR, session)
22
43
  }
23
44
 
24
45
  export const WORKTREES_DIR_SUFFIX = '-worktrees'
@@ -27,6 +27,7 @@ export const initLoggerCLI = () => {
27
27
  const logger = pino(
28
28
  { level: logLevel },
29
29
  pretty({
30
+ destination: 2,
30
31
  ignore: ignoreFields.join(','),
31
32
  colorize: true,
32
33
  }),
@@ -1 +0,0 @@
1
- export { loadEnvFromGitRoot } from './load-env'
@@ -1,28 +0,0 @@
1
- import { config } from 'dotenv'
2
- import { resolve } from 'node:path'
3
- import { $ } from 'zx'
4
-
5
- import { getProjectRoot } from 'src/lib/git-utils'
6
- import { logger } from 'src/lib/logger'
7
-
8
- /**
9
- * Load .env file from git repository root
10
- * Uses getProjectRoot to find the repository root, works regardless of where package is installed
11
- */
12
- export const loadEnvFromGitRoot = async (): Promise<void> => {
13
- try {
14
- $.quiet = true
15
-
16
- const gitRoot = await getProjectRoot()
17
-
18
- // TODO: remove this after new env managemement
19
- config({ path: resolve(gitRoot, '.env'), quiet: true })
20
-
21
- logger.info('Loaded .env file from git repository root')
22
- } catch {
23
- // Git command failed - not in a git repository or git not available
24
- // This is acceptable, env vars might be provided another way
25
- } finally {
26
- $.quiet = false
27
- }
28
- }