infra-kit 0.1.81 → 0.1.85

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,27 +1,27 @@
1
1
  {
2
2
  "name": "infra-kit",
3
3
  "type": "module",
4
- "version": "0.1.81",
4
+ "version": "0.1.85",
5
5
  "description": "infra-kit",
6
6
  "main": "dist/cli.js",
7
7
  "module": "dist/cli.js",
8
8
  "bin": {
9
- "infra-kit": "dist/cli.js"
9
+ "infra-kit": "dist/cli.js",
10
+ "ik": "dist/cli.js"
10
11
  },
11
12
  "engines": {
12
- "node": ">=20.x"
13
+ "node": ">=24.x"
13
14
  },
14
15
  "scripts": {
15
16
  "inspector": "npx @modelcontextprotocol/inspector node ./dist/mcp.js --debug",
16
17
  "build": "pnpm run clean-artifacts && node ./scripts/build.js",
17
- "clean-artifacts": "rimraf dist",
18
- "clean-cache": "rimraf node_modules/.cache .eslintcache tsconfig.tsbuildinfo .turbo .swc",
18
+ "clean-artifacts": "rm -rf dist",
19
+ "clean-cache": "rm -rf node_modules/.cache .eslintcache tsconfig.tsbuildinfo .turbo .swc",
19
20
  "prettier-fix": "pnpm exec prettier **/* --write --no-error-on-unmatched-pattern --log-level warn --ignore-path ../../.prettierignore",
20
21
  "prettier-check": "pnpm exec prettier **/* --check --no-error-on-unmatched-pattern --log-level warn --ignore-path ../../.prettierignore",
21
22
  "eslint-check": "pnpm exec eslint --cache --quiet --report-unused-disable-directives ./src",
22
23
  "eslint-fix": "pnpm exec eslint --cache --quiet --report-unused-disable-directives ./src --fix",
23
24
  "ts-check": "tsc --noEmit",
24
- "ts-report": "rimraf .coverage/typescript && mkdir -p .coverage/typescript && typescript-coverage-report -s -t 95 -o .coverage/typescript",
25
25
  "test": "pnpm exec vitest run --reporter=dot",
26
26
  "test-watch": "pnpm exec vitest --watch",
27
27
  "test-ui": "pnpm exec vitest --ui",
@@ -30,21 +30,21 @@
30
30
  "fix": "pnpm run prettier-fix && pnpm run eslint-fix && pnpm run qa"
31
31
  },
32
32
  "dependencies": {
33
- "@inquirer/checkbox": "^5.1.2",
34
- "@inquirer/confirm": "^6.0.10",
35
- "@inquirer/select": "^5.1.2",
36
- "@modelcontextprotocol/sdk": "^1.27.1",
33
+ "@inquirer/checkbox": "^5.1.3",
34
+ "@inquirer/confirm": "^6.0.11",
35
+ "@inquirer/select": "^5.1.3",
36
+ "@modelcontextprotocol/sdk": "^1.29.0",
37
37
  "commander": "^14.0.3",
38
38
  "pino": "^10.3.1",
39
39
  "pino-pretty": "^13.1.3",
40
- "yaml": "^2.8.2",
40
+ "yaml": "^2.8.3",
41
41
  "zod": "^3.25.76",
42
42
  "zx": "^8.8.5"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@pkg/eslint-config": "workspace:*",
46
46
  "@pkg/vitest-config": "workspace:*",
47
- "esbuild": "^0.27.4",
47
+ "esbuild": "^0.28.0",
48
48
  "typescript": "^5.9.3"
49
49
  }
50
50
  }
@@ -14,8 +14,8 @@ export const envList = async (): Promise<ToolsExecutionResult> => {
14
14
 
15
15
  const project = await getDopplerProject()
16
16
 
17
- logger.info(`Doppler Project: ${project}\n`)
18
- logger.info('Available Configs:')
17
+ logger.info(`Doppler project: ${project}\n`)
18
+ logger.info('Available configs:')
19
19
 
20
20
  for (const env of ENVs) {
21
21
  logger.info(` - ${env}`)
@@ -129,14 +129,14 @@ export const ghMergeDev = async (args: GhMergeDevArgs): Promise<ToolsExecutionRe
129
129
  logger.info('📋 Manual merge script for failed branches:')
130
130
  for (const branch of failedBranches) {
131
131
  logger.info(
132
- `# Merge dev into ${branch} and resolve conflicts if any \ngit switch ${branch} && git pull origin ${branch} && git merge origin/dev\ngit push origin ${branch} && git switch dev\n`,
132
+ `# Merge dev into ${branch} and resolve conflicts if any \n\ngit switch ${branch} && git pull origin ${branch} && git merge origin/dev\ngit push origin ${branch} && git switch dev\n`,
133
133
  )
134
134
  }
135
135
  logger.info(
136
136
  `✅ ${selectedReleaseBranches.length - failedBranches.length}/${selectedReleaseBranches.length} merges completed successfully.`,
137
137
  )
138
138
  } else {
139
- logger.info('✅ All merges completed successfully!')
139
+ logger.info('✅ All merges completed successfully!\n')
140
140
  }
141
141
 
142
142
  commandEcho.print()
@@ -0,0 +1 @@
1
+ export { init } from './init'
@@ -4,12 +4,16 @@ import path from 'node:path'
4
4
 
5
5
  import { logger } from 'src/lib/logger'
6
6
 
7
- const MARKER_COMMENT = '# infra-kit shell functions'
7
+ const MARKER_START = '# -- infra-kit:begin --'
8
+ const MARKER_END = '# -- infra-kit:end --'
9
+
10
+ const LEGACY_PAIRED: [start: string, end: string][] = [['# region infra-kit', '# endregion infra-kit']]
11
+ const LEGACY_SINGLE = '# infra-kit shell functions'
8
12
 
9
13
  /**
10
14
  * Append infra-kit shell functions directly to .zshrc.
11
15
  */
12
- export const envInit = async (): Promise<void> => {
16
+ export const init = async (): Promise<void> => {
13
17
  const zshrcPath = path.join(os.homedir(), '.zshrc')
14
18
  const shellBlock = buildShellBlock()
15
19
 
@@ -28,6 +32,7 @@ export const envInit = async (): Promise<void> => {
28
32
  const isBlockLine = (line: string): boolean => {
29
33
  return (
30
34
  line.startsWith('#') ||
35
+ line.startsWith('alias ') ||
31
36
  line.startsWith('env-load') ||
32
37
  line.startsWith('env-clear') ||
33
38
  line.startsWith('env-status') ||
@@ -37,14 +42,40 @@ const isBlockLine = (line: string): boolean => {
37
42
  )
38
43
  }
39
44
 
45
+ const removeBetween = (content: string, start: string, end: string): string | null => {
46
+ const startIdx = content.indexOf(start)
47
+ const endIdx = content.indexOf(end)
48
+
49
+ if (startIdx === -1 || endIdx === -1) return null
50
+
51
+ // eslint-disable-next-line sonarjs/slow-regex
52
+ const before = content.slice(0, startIdx).replace(/\n+$/, '')
53
+ const after = content.slice(endIdx + end.length).replace(/^\n+/, '')
54
+
55
+ return before + (after ? `\n${after}` : '')
56
+ }
57
+
40
58
  const removeExistingBlock = (content: string): string => {
41
- const markerIdx = content.indexOf(MARKER_COMMENT)
59
+ // 1. Current markers
60
+ const result = removeBetween(content, MARKER_START, MARKER_END)
61
+
62
+ if (result !== null) return result
63
+
64
+ // 2. Legacy paired markers (# region / # endregion)
65
+ for (const [start, end] of LEGACY_PAIRED) {
66
+ const legacyResult = removeBetween(content, start, end)
67
+
68
+ if (legacyResult !== null) return legacyResult
69
+ }
70
+
71
+ // 3. Oldest format: single marker + heuristic scan
72
+ const legacyIdx = content.indexOf(LEGACY_SINGLE)
42
73
 
43
- if (markerIdx === -1) return content
74
+ if (legacyIdx === -1) return content
44
75
 
45
76
  // eslint-disable-next-line sonarjs/slow-regex
46
- const before = content.slice(0, markerIdx).replace(/\n+$/, '')
47
- const afterLines = content.slice(markerIdx).split('\n')
77
+ const before = content.slice(0, legacyIdx).replace(/\n+$/, '')
78
+ const afterLines = content.slice(legacyIdx).split('\n')
48
79
 
49
80
  let i = 0
50
81
 
@@ -61,7 +92,7 @@ const buildShellBlock = (): string => {
61
92
  const runCmd = 'pnpm exec infra-kit'
62
93
 
63
94
  return [
64
- MARKER_COMMENT,
95
+ MARKER_START,
65
96
  // eslint-disable-next-line no-template-curly-in-string
66
97
  'if [[ -z "${INFRA_KIT_SESSION}" ]]; then',
67
98
  ' export INFRA_KIT_SESSION=$(head -c 4 /dev/urandom | xxd -p)',
@@ -69,5 +100,7 @@ const buildShellBlock = (): string => {
69
100
  `env-load() { local f; f=$(${runCmd} env-load "$@") && source "$f" && ${runCmd} env-status; }`,
70
101
  `env-clear() { local f; f=$(${runCmd} env-clear) && source "$f" && ${runCmd} env-status; }`,
71
102
  `env-status() { ${runCmd} env-status; }`,
103
+ `alias ik='${runCmd}'`,
104
+ MARKER_END,
72
105
  ].join('\n')
73
106
  }
package/src/entry/cli.ts CHANGED
@@ -1,8 +1,9 @@
1
+ import select, { Separator } from '@inquirer/select'
1
2
  import { Command, Option } from 'commander'
3
+ import process from 'node:process'
2
4
 
3
5
  import { doctor } from 'src/commands/doctor'
4
6
  import { envClear } from 'src/commands/env-clear'
5
- import { envInit } from 'src/commands/env-init'
6
7
  import { envList } from 'src/commands/env-list'
7
8
  import { envLoad } from 'src/commands/env-load'
8
9
  import { envStatus } from 'src/commands/env-status'
@@ -12,6 +13,7 @@ import { ghReleaseDeployAll } from 'src/commands/gh-release-deploy-all'
12
13
  import { ghReleaseDeploySelected } from 'src/commands/gh-release-deploy-selected'
13
14
  import { ghReleaseDeployService } from 'src/commands/gh-release-deploy-service'
14
15
  import { ghReleaseList } from 'src/commands/gh-release-list'
16
+ import { init } from 'src/commands/init'
15
17
  import { releaseCreate } from 'src/commands/release-create'
16
18
  import { releaseCreateBatch } from 'src/commands/release-create-batch'
17
19
  import { worktreesAdd } from 'src/commands/worktrees-add'
@@ -187,10 +189,10 @@ program
187
189
  })
188
190
 
189
191
  program
190
- .command('env-init')
191
- .description('Set up shell functions for env-load/env-clear in .zshrc')
192
+ .command('init')
193
+ .description('Inject shell integration into your profile .zshrc')
192
194
  .action(async () => {
193
- await envInit()
195
+ await init()
194
196
  })
195
197
 
196
198
  program
@@ -208,4 +210,65 @@ program
208
210
  await envClear()
209
211
  })
210
212
 
211
- program.parse()
213
+ if (process.argv.length <= 2) {
214
+ const releaseCommands = [
215
+ 'merge-dev',
216
+ 'release-list',
217
+ 'release-create',
218
+ 'release-create-batch',
219
+ 'release-deploy-all',
220
+ 'release-deploy-service',
221
+ 'release-deploy-selected',
222
+ 'release-deliver',
223
+ ]
224
+ const worktreeCommands = ['worktrees-add', 'worktrees-list', 'worktrees-remove', 'worktrees-sync']
225
+ const envCommands = ['doctor', 'init', 'env-status', 'env-list', 'env-load', 'env-clear']
226
+
227
+ const commandMap = new Map(
228
+ program.commands.map((cmd) => {
229
+ return [cmd.name(), cmd]
230
+ }),
231
+ )
232
+
233
+ const allNames = [...releaseCommands, ...worktreeCommands, ...envCommands]
234
+ const maxLen = Math.max(
235
+ ...allNames.map((n) => {
236
+ return n.length
237
+ }),
238
+ )
239
+
240
+ const toChoices = (names: string[]) => {
241
+ return names
242
+ .filter((n) => {
243
+ return commandMap.has(n)
244
+ })
245
+ .map((n) => {
246
+ return {
247
+ name: `${n.padEnd(maxLen)} ${commandMap.get(n)!.description()}`,
248
+ value: n,
249
+ }
250
+ })
251
+ }
252
+
253
+ const selected = await select(
254
+ {
255
+ message: 'Select a command to run',
256
+ choices: [
257
+ new Separator(' '),
258
+ new Separator('— Release Management —'),
259
+ ...toChoices(releaseCommands),
260
+ new Separator(' '),
261
+ new Separator('— Worktrees —'),
262
+ ...toChoices(worktreeCommands),
263
+ new Separator(' '),
264
+ new Separator('— Environment —'),
265
+ ...toChoices(envCommands),
266
+ ],
267
+ },
268
+ { output: process.stderr },
269
+ )
270
+
271
+ program.parse(['node', 'infra-kit', selected])
272
+ } else {
273
+ program.parse()
274
+ }
@@ -55,13 +55,12 @@ const createCommandEcho = () => {
55
55
  return `${opt.flag} "${opt.value.join(', ')}"`
56
56
  }
57
57
 
58
- return `${opt.flag} ${opt.value}`
58
+ return `${opt.flag} "${opt.value}"`
59
59
  })
60
60
  .filter(Boolean)
61
61
  .join(' ')
62
62
 
63
- logger.info(`📟 Equivalent command: \npnpm exec infra-kit ${commandName} ${formattedOptions}`)
64
- logger.info('')
63
+ logger.info(`📟 Equivalent command: \npnpm exec infra-kit ${commandName} ${formattedOptions}\n`)
65
64
  },
66
65
 
67
66
  /**
@@ -40,7 +40,7 @@ export const getSessionCacheDir = (): string => {
40
40
  const session = process.env[INFRA_KIT_SESSION_VAR]
41
41
 
42
42
  if (!session) {
43
- throw new Error('INFRA_KIT_SESSION is not set. Run `source ~/.zshrc` or `infra-kit env-init` first.')
43
+ throw new Error('INFRA_KIT_SESSION is not set. Run `source ~/.zshrc` or `infra-kit init` first.')
44
44
  }
45
45
 
46
46
  return path.join(ENV_CACHE_DIR, session)
@@ -111,8 +111,9 @@ export const getJiraDescriptions = async (): Promise<Map<string, string>> => {
111
111
  */
112
112
  export const formatVersionLabel = (version: string, type: ReleaseType, maxVersionLength?: number): string => {
113
113
  const padding = maxVersionLength ? ' '.repeat(maxVersionLength - version.length + 3) : ' '
114
+ const tag = `[${type}]`.padEnd(11)
114
115
 
115
- return `${version}${padding}[${type}]`
116
+ return `${version}${padding}${tag}`
116
117
  }
117
118
 
118
119
  /**
package/src/mcp/server.ts CHANGED
@@ -8,7 +8,7 @@ export async function createMcpServer() {
8
8
  const server = new McpServer(
9
9
  {
10
10
  name: 'infra-kit',
11
- version: '0.1.0',
11
+ version: '1.0.0',
12
12
  },
13
13
  {
14
14
  capabilities: {