infra-kit 0.1.87 → 0.1.88
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/.eslintcache +1 -1
- package/.turbo/turbo-eslint-check.log +5 -4
- package/.turbo/turbo-prettier-check.log +5 -4
- package/.turbo/turbo-test.log +17 -14
- package/.turbo/turbo-ts-check.log +5 -4
- package/dist/cli.js +31 -31
- package/dist/cli.js.map +4 -4
- package/dist/mcp.js +19 -19
- package/dist/mcp.js.map +4 -4
- package/package.json +1 -1
- package/src/commands/doctor/doctor.ts +15 -2
- package/src/commands/env-clear/env-clear.ts +1 -1
- package/src/commands/env-list/env-list.ts +4 -3
- package/src/commands/env-load/env-load.ts +4 -2
- package/src/commands/gh-release-deploy-all/gh-release-deploy-all.ts +5 -3
- package/src/commands/gh-release-deploy-selected/gh-release-deploy-selected.ts +5 -3
- package/src/commands/init/init.ts +45 -3
- package/src/integrations/doppler/doppler-project.ts +4 -17
- package/src/lib/constants.ts +0 -10
- package/src/lib/infra-kit-config.ts +49 -0
- package/tsconfig.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -26,7 +26,7 @@ const checkCommand = async (
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
|
-
* Check installation and authentication status of gh and
|
|
29
|
+
* Check installation and authentication status of gh, doppler, and aws CLIs
|
|
30
30
|
*/
|
|
31
31
|
export const doctor = async (): Promise<ToolsExecutionResult> => {
|
|
32
32
|
const checks: CheckResult[] = await Promise.all([
|
|
@@ -54,6 +54,19 @@ export const doctor = async (): Promise<ToolsExecutionResult> => {
|
|
|
54
54
|
'Doppler CLI is authenticated',
|
|
55
55
|
'Doppler CLI is not authenticated. Run: doppler login',
|
|
56
56
|
),
|
|
57
|
+
checkCommand(
|
|
58
|
+
'aws installed',
|
|
59
|
+
['aws', '--version'],
|
|
60
|
+
'AWS CLI is installed',
|
|
61
|
+
'AWS CLI is not installed. Install from: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html',
|
|
62
|
+
),
|
|
63
|
+
// INFO: no need now, util the user does not load the env variables, the aws cli is not authenticated
|
|
64
|
+
// checkCommand(
|
|
65
|
+
// 'aws authenticated',
|
|
66
|
+
// ['aws', 'sts', 'get-caller-identity'],
|
|
67
|
+
// 'AWS CLI is authenticated',
|
|
68
|
+
// 'AWS CLI is not authenticated. Run: aws configure (or aws sso login)',
|
|
69
|
+
// ),
|
|
57
70
|
])
|
|
58
71
|
|
|
59
72
|
logger.info('Doctor check results:\n')
|
|
@@ -87,7 +100,7 @@ export const doctor = async (): Promise<ToolsExecutionResult> => {
|
|
|
87
100
|
// MCP Tool Registration
|
|
88
101
|
export const doctorMcpTool = {
|
|
89
102
|
name: 'doctor',
|
|
90
|
-
description: 'Check installation and authentication status of gh and
|
|
103
|
+
description: 'Check installation and authentication status of gh, doppler, and aws CLIs',
|
|
91
104
|
inputSchema: {},
|
|
92
105
|
outputSchema: {
|
|
93
106
|
checks: z
|
|
@@ -80,7 +80,7 @@ export const envClear = async (): Promise<ToolsExecutionResult> => {
|
|
|
80
80
|
export const envClearMcpTool = {
|
|
81
81
|
name: 'env-clear',
|
|
82
82
|
description:
|
|
83
|
-
'Generate a shell script that unsets every env var previously loaded by env-load for this session, plus the infra-kit session metadata vars. Does NOT mutate the calling process
|
|
83
|
+
'Generate a shell script that unsets every env var previously loaded by env-load for this session, plus the infra-kit session metadata vars. Does NOT mutate the calling process. When `infra-kit init` has installed the zsh shell integration, the user\'s terminal auto-sources the unset script on its next prompt (precmd hook) — so calling this via MCP will clear the vars in the shell that launched Claude Code automatically. Other callers must source "<filePath>" themselves or surface it to the user. Errors if no env is currently loaded.',
|
|
84
84
|
inputSchema: {},
|
|
85
85
|
outputSchema: {
|
|
86
86
|
filePath: z.string().describe('Path to the file that must be sourced to apply'),
|
|
@@ -2,7 +2,7 @@ import { z } from 'zod'
|
|
|
2
2
|
|
|
3
3
|
import { validateDopplerCliAndAuth } from 'src/integrations/doppler'
|
|
4
4
|
import { getDopplerProject } from 'src/integrations/doppler/doppler-project'
|
|
5
|
-
import {
|
|
5
|
+
import { getInfraKitConfig } from 'src/lib/infra-kit-config'
|
|
6
6
|
import { logger } from 'src/lib/logger'
|
|
7
7
|
import type { ToolsExecutionResult } from 'src/types'
|
|
8
8
|
|
|
@@ -13,17 +13,18 @@ export const envList = async (): Promise<ToolsExecutionResult> => {
|
|
|
13
13
|
await validateDopplerCliAndAuth()
|
|
14
14
|
|
|
15
15
|
const project = await getDopplerProject()
|
|
16
|
+
const { environments } = await getInfraKitConfig()
|
|
16
17
|
|
|
17
18
|
logger.info(`Doppler project: ${project}\n`)
|
|
18
19
|
logger.info('Available configs:')
|
|
19
20
|
|
|
20
|
-
for (const env of
|
|
21
|
+
for (const env of environments) {
|
|
21
22
|
logger.info(` - ${env}`)
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
const structuredContent = {
|
|
25
26
|
project,
|
|
26
|
-
configs:
|
|
27
|
+
configs: environments,
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
return {
|
|
@@ -10,12 +10,12 @@ import { getDopplerProject } from 'src/integrations/doppler/doppler-project'
|
|
|
10
10
|
import { commandEcho } from 'src/lib/command-echo'
|
|
11
11
|
import {
|
|
12
12
|
ENV_LOAD_FILE,
|
|
13
|
-
ENVs,
|
|
14
13
|
INFRA_KIT_ENV_CONFIG_VAR,
|
|
15
14
|
INFRA_KIT_ENV_LOADED_AT_VAR,
|
|
16
15
|
INFRA_KIT_ENV_PROJECT_VAR,
|
|
17
16
|
getSessionCacheDir,
|
|
18
17
|
} from 'src/lib/constants'
|
|
18
|
+
import { getInfraKitConfig } from 'src/lib/infra-kit-config'
|
|
19
19
|
import type { ToolsExecutionResult } from 'src/types'
|
|
20
20
|
|
|
21
21
|
interface EnvLoadArgs {
|
|
@@ -37,11 +37,13 @@ export const envLoad = async (args: EnvLoadArgs): Promise<ToolsExecutionResult>
|
|
|
37
37
|
if (config) {
|
|
38
38
|
selectedConfig = config
|
|
39
39
|
} else {
|
|
40
|
+
const { environments } = await getInfraKitConfig()
|
|
41
|
+
|
|
40
42
|
commandEcho.setInteractive()
|
|
41
43
|
selectedConfig = await select(
|
|
42
44
|
{
|
|
43
45
|
message: 'Select environment config',
|
|
44
|
-
choices:
|
|
46
|
+
choices: environments.map((env) => {
|
|
45
47
|
return { name: env, value: env }
|
|
46
48
|
}),
|
|
47
49
|
},
|
|
@@ -5,7 +5,7 @@ import { $ } from 'zx'
|
|
|
5
5
|
|
|
6
6
|
import { getReleasePRsWithInfo } from 'src/integrations/gh'
|
|
7
7
|
import { commandEcho } from 'src/lib/command-echo'
|
|
8
|
-
import {
|
|
8
|
+
import { getInfraKitConfig } from 'src/lib/infra-kit-config'
|
|
9
9
|
import { logger } from 'src/lib/logger'
|
|
10
10
|
import { detectReleaseType, formatBranchChoices, getJiraDescriptions } from 'src/lib/release-utils'
|
|
11
11
|
import type { ReleaseType } from 'src/lib/release-utils'
|
|
@@ -56,6 +56,8 @@ export const ghReleaseDeployAll = async (args: GhReleaseDeployAllArgs): Promise<
|
|
|
56
56
|
|
|
57
57
|
commandEcho.addOption('--version', selectedVersion)
|
|
58
58
|
|
|
59
|
+
const { environments } = await getInfraKitConfig()
|
|
60
|
+
|
|
59
61
|
let selectedEnv = ''
|
|
60
62
|
|
|
61
63
|
if (env) {
|
|
@@ -65,7 +67,7 @@ export const ghReleaseDeployAll = async (args: GhReleaseDeployAllArgs): Promise<
|
|
|
65
67
|
|
|
66
68
|
selectedEnv = await select({
|
|
67
69
|
message: '🧪 Select environment',
|
|
68
|
-
choices:
|
|
70
|
+
choices: environments.map((env) => {
|
|
69
71
|
return {
|
|
70
72
|
name: env,
|
|
71
73
|
value: env,
|
|
@@ -76,7 +78,7 @@ export const ghReleaseDeployAll = async (args: GhReleaseDeployAllArgs): Promise<
|
|
|
76
78
|
|
|
77
79
|
commandEcho.addOption('--env', selectedEnv)
|
|
78
80
|
|
|
79
|
-
if (!
|
|
81
|
+
if (!environments.includes(selectedEnv)) {
|
|
80
82
|
logger.error(`❌ Invalid environment: ${selectedEnv}. Exiting...`)
|
|
81
83
|
process.exit(1)
|
|
82
84
|
}
|
|
@@ -9,8 +9,8 @@ import { $ } from 'zx'
|
|
|
9
9
|
|
|
10
10
|
import { getReleasePRsWithInfo } from 'src/integrations/gh'
|
|
11
11
|
import { commandEcho } from 'src/lib/command-echo'
|
|
12
|
-
import { ENVs } from 'src/lib/constants'
|
|
13
12
|
import { getProjectRoot } from 'src/lib/git-utils'
|
|
13
|
+
import { getInfraKitConfig } from 'src/lib/infra-kit-config'
|
|
14
14
|
import { logger } from 'src/lib/logger'
|
|
15
15
|
import { detectReleaseType, formatBranchChoices, getJiraDescriptions } from 'src/lib/release-utils'
|
|
16
16
|
import type { ReleaseType } from 'src/lib/release-utils'
|
|
@@ -63,6 +63,8 @@ export const ghReleaseDeploySelected = async (args: GhReleaseDeploySelectedArgs)
|
|
|
63
63
|
|
|
64
64
|
commandEcho.addOption('--version', selectedVersion)
|
|
65
65
|
|
|
66
|
+
const { environments } = await getInfraKitConfig()
|
|
67
|
+
|
|
66
68
|
let selectedEnv = ''
|
|
67
69
|
|
|
68
70
|
if (env) {
|
|
@@ -72,7 +74,7 @@ export const ghReleaseDeploySelected = async (args: GhReleaseDeploySelectedArgs)
|
|
|
72
74
|
|
|
73
75
|
selectedEnv = await select({
|
|
74
76
|
message: '🧪 Select environment',
|
|
75
|
-
choices:
|
|
77
|
+
choices: environments.map((env) => {
|
|
76
78
|
return {
|
|
77
79
|
name: env,
|
|
78
80
|
value: env,
|
|
@@ -83,7 +85,7 @@ export const ghReleaseDeploySelected = async (args: GhReleaseDeploySelectedArgs)
|
|
|
83
85
|
|
|
84
86
|
commandEcho.addOption('--env', selectedEnv)
|
|
85
87
|
|
|
86
|
-
if (!
|
|
88
|
+
if (!environments.includes(selectedEnv)) {
|
|
87
89
|
logger.error(`❌ Invalid environment: ${selectedEnv}. Exiting...`)
|
|
88
90
|
process.exit(1)
|
|
89
91
|
}
|
|
@@ -38,7 +38,14 @@ const isBlockLine = (line: string): boolean => {
|
|
|
38
38
|
line.startsWith('env-status') ||
|
|
39
39
|
line.startsWith('if ') ||
|
|
40
40
|
line.startsWith(' export INFRA_KIT_SESSION') ||
|
|
41
|
-
line.startsWith('
|
|
41
|
+
line.startsWith('export _INFRA_KIT_LAST_') ||
|
|
42
|
+
line.startsWith('export _INFRA_KIT_') ||
|
|
43
|
+
line.startsWith(': ${_INFRA_KIT_') ||
|
|
44
|
+
line.startsWith('fi') ||
|
|
45
|
+
line.startsWith('zmodload ') ||
|
|
46
|
+
line.startsWith('autoload ') ||
|
|
47
|
+
line.startsWith('add-zsh-hook ') ||
|
|
48
|
+
line.startsWith('_infra_kit_autoload')
|
|
42
49
|
)
|
|
43
50
|
}
|
|
44
51
|
|
|
@@ -93,14 +100,49 @@ const buildShellBlock = (): string => {
|
|
|
93
100
|
|
|
94
101
|
return [
|
|
95
102
|
MARKER_START,
|
|
103
|
+
'zmodload zsh/stat 2>/dev/null',
|
|
104
|
+
'zmodload zsh/datetime 2>/dev/null',
|
|
96
105
|
// eslint-disable-next-line no-template-curly-in-string
|
|
97
106
|
'if [[ -z "${INFRA_KIT_SESSION}" ]]; then',
|
|
98
107
|
' export INFRA_KIT_SESSION=$(head -c 4 /dev/urandom | xxd -p)',
|
|
99
108
|
'fi',
|
|
100
|
-
|
|
101
|
-
|
|
109
|
+
// eslint-disable-next-line no-template-curly-in-string
|
|
110
|
+
': ${_INFRA_KIT_LAST_LOAD_MTIME:=0}',
|
|
111
|
+
// eslint-disable-next-line no-template-curly-in-string
|
|
112
|
+
': ${_INFRA_KIT_LAST_CLEAR_MTIME:=0}',
|
|
113
|
+
// eslint-disable-next-line no-template-curly-in-string
|
|
114
|
+
': ${_INFRA_KIT_SHELL_STARTED:=${EPOCHSECONDS:-0}}',
|
|
115
|
+
'export _INFRA_KIT_LAST_LOAD_MTIME _INFRA_KIT_LAST_CLEAR_MTIME _INFRA_KIT_SHELL_STARTED',
|
|
116
|
+
`env-load() { local f; f=$(${runCmd} env-load "$@") && source "$f" && _INFRA_KIT_LAST_LOAD_MTIME=$(zstat +mtime -- "$f" 2>/dev/null || echo 0) && ${runCmd} env-status; }`,
|
|
117
|
+
`env-clear() { local f; f=$(${runCmd} env-clear) && source "$f" && _INFRA_KIT_LAST_CLEAR_MTIME=$(zstat +mtime -- "$f" 2>/dev/null || echo 0) && ${runCmd} env-status; }`,
|
|
102
118
|
`env-status() { ${runCmd} env-status; }`,
|
|
103
119
|
`alias ik='${runCmd}'`,
|
|
120
|
+
'_infra_kit_autoload() {',
|
|
121
|
+
' [[ -z "$INFRA_KIT_SESSION" ]] && return',
|
|
122
|
+
' local dir="./node_modules/.cache/infra-kit/$INFRA_KIT_SESSION"',
|
|
123
|
+
' local load_file="$dir/env-load.sh"',
|
|
124
|
+
' local clear_file="$dir/env-clear.sh"',
|
|
125
|
+
' local mtime',
|
|
126
|
+
' if [[ -f "$load_file" ]]; then',
|
|
127
|
+
' mtime=$(zstat +mtime -- "$load_file" 2>/dev/null || echo 0)',
|
|
128
|
+
' if (( mtime > _INFRA_KIT_LAST_LOAD_MTIME && mtime >= _INFRA_KIT_SHELL_STARTED )); then',
|
|
129
|
+
' source "$load_file"',
|
|
130
|
+
' _INFRA_KIT_LAST_LOAD_MTIME=$mtime',
|
|
131
|
+
// eslint-disable-next-line no-template-curly-in-string
|
|
132
|
+
' print -u2 "infra-kit: auto-loaded vars for ${INFRA_KIT_ENV_CONFIG:-?}"',
|
|
133
|
+
' fi',
|
|
134
|
+
' fi',
|
|
135
|
+
' if [[ -f "$clear_file" ]]; then',
|
|
136
|
+
' mtime=$(zstat +mtime -- "$clear_file" 2>/dev/null || echo 0)',
|
|
137
|
+
' if (( mtime > _INFRA_KIT_LAST_CLEAR_MTIME && mtime >= _INFRA_KIT_SHELL_STARTED )); then',
|
|
138
|
+
' source "$clear_file"',
|
|
139
|
+
' _INFRA_KIT_LAST_CLEAR_MTIME=$mtime',
|
|
140
|
+
' print -u2 "infra-kit: auto-cleared env"',
|
|
141
|
+
' fi',
|
|
142
|
+
' fi',
|
|
143
|
+
'}',
|
|
144
|
+
'autoload -Uz add-zsh-hook',
|
|
145
|
+
'add-zsh-hook precmd _infra_kit_autoload',
|
|
104
146
|
MARKER_END,
|
|
105
147
|
].join('\n')
|
|
106
148
|
}
|
|
@@ -1,23 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import { DOPPLER_PROJECT_MAP } from 'src/lib/constants'
|
|
4
|
-
import { getProjectRoot } from 'src/lib/git-utils'
|
|
1
|
+
import { getInfraKitConfig } from 'src/lib/infra-kit-config'
|
|
5
2
|
|
|
6
3
|
/**
|
|
7
|
-
* Resolve Doppler project name from the
|
|
4
|
+
* Resolve Doppler project name from infra-kit.yml at the project root
|
|
8
5
|
*/
|
|
9
6
|
export const getDopplerProject = async (): Promise<string> => {
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
const dirName = path.basename(projectRoot)
|
|
13
|
-
const dopplerProject = DOPPLER_PROJECT_MAP[dirName]
|
|
14
|
-
|
|
15
|
-
if (!dopplerProject) {
|
|
16
|
-
throw new Error(
|
|
17
|
-
`Could not determine Doppler project for directory "${dirName}". ` +
|
|
18
|
-
`Expected one of: ${Object.keys(DOPPLER_PROJECT_MAP).join(', ')}`,
|
|
19
|
-
)
|
|
20
|
-
}
|
|
7
|
+
const { dopplerProjectName } = await getInfraKitConfig()
|
|
21
8
|
|
|
22
|
-
return
|
|
9
|
+
return dopplerProjectName
|
|
23
10
|
}
|
package/src/lib/constants.ts
CHANGED
|
@@ -2,16 +2,6 @@ import fs from 'node:fs'
|
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import process from 'node:process'
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* List of environments for the project deployment
|
|
7
|
-
*/
|
|
8
|
-
export const ENVs = ['dev', 'arthur', 'renana', 'roman', 'eliran', 'oriana']
|
|
9
|
-
|
|
10
|
-
export const DOPPLER_PROJECT_MAP: Record<string, string> = {
|
|
11
|
-
'hulyo-monorepo': 'hulyo',
|
|
12
|
-
'travelist-monorepo': 'travelist',
|
|
13
|
-
}
|
|
14
|
-
|
|
15
5
|
export const ENV_CACHE_DIR = './node_modules/.cache/infra-kit'
|
|
16
6
|
export const ENV_LOAD_FILE = 'env-load.sh'
|
|
17
7
|
export const ENV_CLEAR_FILE = 'env-clear.sh'
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import fs from 'node:fs/promises'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import yaml from 'yaml'
|
|
4
|
+
import { z } from 'zod'
|
|
5
|
+
|
|
6
|
+
import { getProjectRoot } from 'src/lib/git-utils'
|
|
7
|
+
|
|
8
|
+
const INFRA_KIT_CONFIG_FILE = 'infra-kit.yml'
|
|
9
|
+
|
|
10
|
+
const infraKitConfigSchema = z.object({
|
|
11
|
+
dopplerProjectName: z.string().min(1),
|
|
12
|
+
environments: z.array(z.string().min(1)).min(1),
|
|
13
|
+
taskManagerProvider: z.union([z.string(), z.literal(false)]),
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
export type InfraKitConfig = z.infer<typeof infraKitConfigSchema>
|
|
17
|
+
|
|
18
|
+
let cached: Promise<InfraKitConfig> | null = null
|
|
19
|
+
|
|
20
|
+
export const getInfraKitConfig = async (): Promise<InfraKitConfig> => {
|
|
21
|
+
if (!cached) {
|
|
22
|
+
cached = loadInfraKitConfig()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return cached
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const loadInfraKitConfig = async (): Promise<InfraKitConfig> => {
|
|
29
|
+
const projectRoot = await getProjectRoot()
|
|
30
|
+
|
|
31
|
+
const configPath = path.join(projectRoot, INFRA_KIT_CONFIG_FILE)
|
|
32
|
+
|
|
33
|
+
let raw: string
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
raw = await fs.readFile(configPath, 'utf-8')
|
|
37
|
+
} catch {
|
|
38
|
+
throw new Error(`infra-kit.yml not found at ${configPath}`)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const parsed = yaml.parse(raw)
|
|
42
|
+
const result = infraKitConfigSchema.safeParse(parsed)
|
|
43
|
+
|
|
44
|
+
if (!result.success) {
|
|
45
|
+
throw new Error(`Invalid infra-kit.yml at ${configPath}: ${result.error.message}`)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return result.data
|
|
49
|
+
}
|