infra-kit 0.1.67 → 0.1.71

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.67",
4
+ "version": "0.1.71",
5
5
  "description": "infra-kit",
6
6
  "main": "dist/cli.js",
7
7
  "module": "dist/cli.js",
@@ -35,8 +35,8 @@
35
35
  "@inquirer/select": "^5.0.4",
36
36
  "@modelcontextprotocol/sdk": "^1.26.0",
37
37
  "commander": "^14.0.3",
38
- "dotenv": "^17.2.3",
39
- "pino": "^10.3.0",
38
+ "dotenv": "^17.2.4",
39
+ "pino": "^10.3.1",
40
40
  "pino-pretty": "^13.1.3",
41
41
  "yaml": "^2.8.2",
42
42
  "zod": "^3.25.76",
@@ -45,7 +45,7 @@
45
45
  "devDependencies": {
46
46
  "@pkg/eslint-config": "workspace:*",
47
47
  "@pkg/vitest-config": "workspace:*",
48
- "esbuild": "^0.27.2",
48
+ "esbuild": "^0.27.3",
49
49
  "typescript": "^5.9.3"
50
50
  }
51
51
  }
@@ -1,3 +1,4 @@
1
+ /* eslint-disable sonarjs/cognitive-complexity */
1
2
  import checkbox from '@inquirer/checkbox'
2
3
  import confirm from '@inquirer/confirm'
3
4
  import process from 'node:process'
@@ -23,6 +24,22 @@ export const ghMergeDev = async (args: GhMergeDevArgs): Promise<ToolsExecutionRe
23
24
 
24
25
  const releasePRsList = await getReleasePRs()
25
26
 
27
+ if (releasePRsList.length === 0) {
28
+ logger.info('ℹ️ No open release branches found')
29
+
30
+ commandEcho.print()
31
+
32
+ return {
33
+ content: [
34
+ {
35
+ type: 'text',
36
+ text: JSON.stringify({ successfulMerges: 0, failedMerges: 0, failedBranches: [], totalBranches: 0 }, null, 2),
37
+ },
38
+ ],
39
+ structuredContent: { successfulMerges: 0, failedMerges: 0, failedBranches: [], totalBranches: 0 },
40
+ }
41
+ }
42
+
26
43
  let selectedReleaseBranches: string[] = []
27
44
 
28
45
  if (all) {
@@ -33,10 +50,12 @@ export const ghMergeDev = async (args: GhMergeDevArgs): Promise<ToolsExecutionRe
33
50
  selectedReleaseBranches = await checkbox({
34
51
  required: true,
35
52
  message: '🌿 Select release branches',
36
- choices: releasePRsList.map((pr) => ({
37
- name: pr.replace('release/v', ''),
38
- value: pr,
39
- })),
53
+ choices: releasePRsList.map((pr) => {
54
+ return {
55
+ name: pr.replace('release/v', ''),
56
+ value: pr,
57
+ }
58
+ }),
40
59
  })
41
60
  }
42
61
 
@@ -33,10 +33,12 @@ export const ghReleaseDeliver = async (args: GhReleaseDeliverArgs): Promise<Tool
33
33
 
34
34
  selectedReleaseBranch = await select({
35
35
  message: '🌿 Select release branch',
36
- choices: releasePRsList.map((pr) => ({
37
- name: pr.replace('release/v', ''),
38
- value: pr,
39
- })),
36
+ choices: releasePRsList.map((pr) => {
37
+ return {
38
+ name: pr.replace('release/v', ''),
39
+ value: pr,
40
+ }
41
+ }),
40
42
  })
41
43
  }
42
44
 
@@ -41,10 +41,12 @@ export const ghReleaseDeployAll = async (args: GhReleaseDeployAllArgs): Promise<
41
41
 
42
42
  selectedReleaseBranch = await select({
43
43
  message: '🌿 Select release branch',
44
- choices: releasePRsList.map((pr) => ({
45
- name: pr.replace('release/v', ''),
46
- value: pr,
47
- })),
44
+ choices: releasePRsList.map((pr) => {
45
+ return {
46
+ name: pr.replace('release/v', ''),
47
+ value: pr,
48
+ }
49
+ }),
48
50
  })
49
51
  }
50
52
 
@@ -67,10 +69,12 @@ export const ghReleaseDeployAll = async (args: GhReleaseDeployAllArgs): Promise<
67
69
 
68
70
  selectedEnv = await select({
69
71
  message: '🧪 Select environment',
70
- choices: ENVs.map((env) => ({
71
- name: env,
72
- value: env,
73
- })),
72
+ choices: ENVs.map((env) => {
73
+ return {
74
+ name: env,
75
+ value: env,
76
+ }
77
+ }),
74
78
  })
75
79
  }
76
80
 
@@ -102,6 +106,7 @@ export const ghReleaseDeployAll = async (args: GhReleaseDeployAllArgs): Promise<
102
106
  $.quiet = true
103
107
 
104
108
  const skipTerraformFlag = shouldSkipTerraform ? ['-f', 'skip_terraform_deploy=true'] : []
109
+
105
110
  await $`gh workflow run deploy-all.yml --ref ${selectedReleaseBranch} -f environment=${selectedEnv} ${skipTerraformFlag}`
106
111
 
107
112
  $.quiet = false
@@ -46,10 +46,12 @@ export const ghReleaseDeploySelected = async (args: GhReleaseDeploySelectedArgs)
46
46
 
47
47
  selectedReleaseBranch = await select({
48
48
  message: '🌿 Select release branch',
49
- choices: releasePRsList.map((pr) => ({
50
- name: pr.replace('release/v', ''),
51
- value: pr,
52
- })),
49
+ choices: releasePRsList.map((pr) => {
50
+ return {
51
+ name: pr.replace('release/v', ''),
52
+ value: pr,
53
+ }
54
+ }),
53
55
  })
54
56
  }
55
57
 
@@ -72,10 +74,12 @@ export const ghReleaseDeploySelected = async (args: GhReleaseDeploySelectedArgs)
72
74
 
73
75
  selectedEnv = await select({
74
76
  message: '🧪 Select environment',
75
- choices: ENVs.map((env) => ({
76
- name: env,
77
- value: env,
78
- })),
77
+ choices: ENVs.map((env) => {
78
+ return {
79
+ name: env,
80
+ value: env,
81
+ }
82
+ }),
79
83
  })
80
84
  }
81
85
 
@@ -89,6 +93,12 @@ export const ghReleaseDeploySelected = async (args: GhReleaseDeploySelectedArgs)
89
93
  // Parse available services from workflow file
90
94
  const availableServices = await parseServicesFromWorkflow()
91
95
 
96
+ if (availableServices.length === 0) {
97
+ logger.error('❌ No services found in workflow file. Exiting...')
98
+
99
+ process.exit(1)
100
+ }
101
+
92
102
  let selectedServices: string[] = []
93
103
 
94
104
  if (services && services.length > 0) {
@@ -98,10 +108,12 @@ export const ghReleaseDeploySelected = async (args: GhReleaseDeploySelectedArgs)
98
108
 
99
109
  selectedServices = await checkbox({
100
110
  message: '🚀 Select services to deploy (space to select, enter to confirm)',
101
- choices: availableServices.map((svc) => ({
102
- name: svc,
103
- value: svc,
104
- })),
111
+ choices: availableServices.map((svc) => {
112
+ return {
113
+ name: svc,
114
+ value: svc,
115
+ }
116
+ }),
105
117
  })
106
118
  }
107
119
 
@@ -113,7 +125,9 @@ export const ghReleaseDeploySelected = async (args: GhReleaseDeploySelectedArgs)
113
125
  }
114
126
 
115
127
  // Validate all selected services
116
- const invalidServices = selectedServices.filter((svc) => !availableServices.includes(svc))
128
+ const invalidServices = selectedServices.filter((svc) => {
129
+ return !availableServices.includes(svc)
130
+ })
117
131
 
118
132
  if (invalidServices.length > 0) {
119
133
  logger.error(
@@ -143,7 +157,9 @@ export const ghReleaseDeploySelected = async (args: GhReleaseDeploySelectedArgs)
143
157
  $.quiet = true
144
158
 
145
159
  // Build the workflow command with boolean flags for each selected service
146
- const serviceFlags = selectedServices.flatMap((svc) => ['-f', `${svc}=true`])
160
+ const serviceFlags = selectedServices.flatMap((svc) => {
161
+ return ['-f', `${svc}=true`]
162
+ })
147
163
  const skipTerraformFlag = shouldSkipTerraform ? ['-f', 'skip_terraform_deploy=true'] : []
148
164
 
149
165
  await $`gh workflow run deploy-selected-services.yml --ref ${selectedReleaseBranch} -f environment=${selectedEnv} ${serviceFlags} ${skipTerraformFlag}`
@@ -47,10 +47,12 @@ export const ghReleaseDeployService = async (args: GhReleaseDeployServiceArgs):
47
47
 
48
48
  selectedReleaseBranch = await select({
49
49
  message: '🌿 Select release branch',
50
- choices: releasePRsList.map((pr) => ({
51
- name: pr.replace('release/v', ''),
52
- value: pr,
53
- })),
50
+ choices: releasePRsList.map((pr) => {
51
+ return {
52
+ name: pr.replace('release/v', ''),
53
+ value: pr,
54
+ }
55
+ }),
54
56
  })
55
57
  }
56
58
 
@@ -73,10 +75,12 @@ export const ghReleaseDeployService = async (args: GhReleaseDeployServiceArgs):
73
75
 
74
76
  selectedEnv = await select({
75
77
  message: '🧪 Select environment',
76
- choices: ENVs.map((env) => ({
77
- name: env,
78
- value: env,
79
- })),
78
+ choices: ENVs.map((env) => {
79
+ return {
80
+ name: env,
81
+ value: env,
82
+ }
83
+ }),
80
84
  })
81
85
  }
82
86
 
@@ -99,10 +103,12 @@ export const ghReleaseDeployService = async (args: GhReleaseDeployServiceArgs):
99
103
 
100
104
  selectedService = await select({
101
105
  message: '🚀 Select service to deploy',
102
- choices: availableServices.map((svc) => ({
103
- name: svc,
104
- value: svc,
105
- })),
106
+ choices: availableServices.map((svc) => {
107
+ return {
108
+ name: svc,
109
+ value: svc,
110
+ }
111
+ }),
106
112
  })
107
113
  }
108
114
 
@@ -134,6 +140,7 @@ export const ghReleaseDeployService = async (args: GhReleaseDeployServiceArgs):
134
140
  $.quiet = true
135
141
 
136
142
  const skipTerraformFlag = shouldSkipTerraform ? ['-f', 'skip_terraform_deploy=true'] : []
143
+
137
144
  await $`gh workflow run deploy-single-service.yml --ref ${selectedReleaseBranch} -f environment=${selectedEnv} -f service=${selectedService} ${skipTerraformFlag}`
138
145
 
139
146
  $.quiet = false
@@ -10,7 +10,9 @@ import type { ToolsExecutionResult } from 'src/types'
10
10
  export const ghReleaseList = async (): Promise<ToolsExecutionResult> => {
11
11
  const releasePRs = await getReleasePRs()
12
12
 
13
- const releasePRsList = releasePRs.map((pr) => pr.replace('release/', ''))
13
+ const releasePRsList = releasePRs.map((pr) => {
14
+ return pr.replace('release/', '')
15
+ })
14
16
 
15
17
  logger.info('All release branches: \n')
16
18
  logger.info(`\n${releasePRsList.join('\n')}`)
@@ -35,7 +35,9 @@ export const releaseCreateBatch = async (args: ReleaseCreateBatchArgs): Promise<
35
35
  versionInput = await question('Enter versions by comma (e.g. 1.2.5, 1.2.6): ')
36
36
  }
37
37
 
38
- const versionsList = versionInput.split(',').map((version) => version.trim())
38
+ const versionsList = versionInput.split(',').map((version) => {
39
+ return version.trim()
40
+ })
39
41
 
40
42
  commandEcho.addOption('--versions', versionsList.join(', '))
41
43
 
@@ -113,7 +115,9 @@ export const releaseCreateBatch = async (args: ReleaseCreateBatchArgs): Promise<
113
115
  commandEcho.print()
114
116
 
115
117
  const structuredContent = {
116
- createdBranches: releases.map((r) => r.branchName),
118
+ createdBranches: releases.map((r) => {
119
+ return r.branchName
120
+ }),
117
121
  successCount,
118
122
  failureCount,
119
123
  releases,
@@ -1,5 +1,7 @@
1
+ /* eslint-disable sonarjs/cognitive-complexity */
1
2
  import checkbox from '@inquirer/checkbox'
2
3
  import confirm from '@inquirer/confirm'
4
+ import { copyFileSync, existsSync } from 'node:fs'
3
5
  import process from 'node:process'
4
6
  import { z } from 'zod'
5
7
  import { $ } from 'zx'
@@ -18,6 +20,7 @@ const RELEASE_BRANCH_PREFIX = 'release/v'
18
20
 
19
21
  interface WorktreeManagementArgs extends RequiredConfirmedOptionArg {
20
22
  all: boolean
23
+ cursor?: boolean
21
24
  }
22
25
 
23
26
  /**
@@ -25,7 +28,7 @@ interface WorktreeManagementArgs extends RequiredConfirmedOptionArg {
25
28
  * Creates worktrees for active release branches and removes unused ones
26
29
  */
27
30
  export const worktreesAdd = async (options: WorktreeManagementArgs): Promise<ToolsExecutionResult> => {
28
- const { confirmedCommand, all } = options
31
+ const { confirmedCommand, all, cursor } = options
29
32
 
30
33
  commandEcho.start('worktrees-add')
31
34
 
@@ -40,6 +43,17 @@ export const worktreesAdd = async (options: WorktreeManagementArgs): Promise<Too
40
43
 
41
44
  const releasePRsList = await getReleasePRs()
42
45
 
46
+ if (releasePRsList.length === 0) {
47
+ logger.info('ℹ️ No open release branches found')
48
+
49
+ commandEcho.print()
50
+
51
+ return {
52
+ content: [{ type: 'text', text: JSON.stringify({ createdWorktrees: [], count: 0 }, null, 2) }],
53
+ structuredContent: { createdWorktrees: [], count: 0 },
54
+ }
55
+ }
56
+
43
57
  let selectedReleaseBranches: string[] = []
44
58
 
45
59
  if (all) {
@@ -50,10 +64,12 @@ export const worktreesAdd = async (options: WorktreeManagementArgs): Promise<Too
50
64
  selectedReleaseBranches = await checkbox({
51
65
  required: true,
52
66
  message: '🌿 Select release branches',
53
- choices: releasePRsList.map((pr) => ({
54
- name: pr.replace('release/v', ''),
55
- value: pr,
56
- })),
67
+ choices: releasePRsList.map((pr) => {
68
+ return {
69
+ name: pr.replace('release/v', ''),
70
+ value: pr,
71
+ }
72
+ }),
57
73
  })
58
74
  }
59
75
 
@@ -87,15 +103,31 @@ export const worktreesAdd = async (options: WorktreeManagementArgs): Promise<Too
87
103
  commandEcho.addOption('--yes', true)
88
104
  }
89
105
 
106
+ const openInCursor = cursor ? true : await confirm({ message: 'Open created worktrees in Cursor?' })
107
+
108
+ if (!openInCursor) {
109
+ commandEcho.setInteractive()
110
+ }
111
+
112
+ if (openInCursor) {
113
+ commandEcho.addOption('--cursor', true)
114
+ }
115
+
90
116
  const { branchesToCreate } = categorizeWorktrees({
91
117
  selectedReleaseBranches,
92
118
  currentWorktrees,
93
119
  })
94
120
 
95
- const createdWorktrees = await createWorktrees(branchesToCreate, worktreeDir)
121
+ const createdWorktrees = await createWorktrees(branchesToCreate, worktreeDir, projectRoot)
96
122
 
97
123
  logResults(createdWorktrees)
98
124
 
125
+ if (openInCursor) {
126
+ for (const branch of createdWorktrees) {
127
+ await $`cursor ${worktreeDir}/${branch}`
128
+ }
129
+ }
130
+
99
131
  commandEcho.print()
100
132
 
101
133
  const structuredContent = {
@@ -136,9 +168,13 @@ interface CategorizeWorktreesArgs {
136
168
  const categorizeWorktrees = (args: CategorizeWorktreesArgs): { branchesToCreate: string[] } => {
137
169
  const { selectedReleaseBranches, currentWorktrees } = args
138
170
 
139
- const currentBranchNames = currentWorktrees.filter((branch) => branch.startsWith(RELEASE_BRANCH_PREFIX))
171
+ const currentBranchNames = currentWorktrees.filter((branch) => {
172
+ return branch.startsWith(RELEASE_BRANCH_PREFIX)
173
+ })
140
174
 
141
- const branchesToCreate = selectedReleaseBranches.filter((branch) => !currentBranchNames.includes(branch))
175
+ const branchesToCreate = selectedReleaseBranches.filter((branch) => {
176
+ return !currentBranchNames.includes(branch)
177
+ })
142
178
 
143
179
  return { branchesToCreate }
144
180
  }
@@ -146,7 +182,7 @@ const categorizeWorktrees = (args: CategorizeWorktreesArgs): { branchesToCreate:
146
182
  /**
147
183
  * Create worktrees for the specified branches
148
184
  */
149
- const createWorktrees = async (branches: string[], worktreeDir: string): Promise<string[]> => {
185
+ const createWorktrees = async (branches: string[], worktreeDir: string, projectRoot: string): Promise<string[]> => {
150
186
  const created: string[] = []
151
187
 
152
188
  for (const branch of branches) {
@@ -155,6 +191,14 @@ const createWorktrees = async (branches: string[], worktreeDir: string): Promise
155
191
 
156
192
  await $`git worktree add ${worktreePath} ${branch}`
157
193
 
194
+ const rootEnvPath = `${projectRoot}/.env`
195
+
196
+ if (existsSync(rootEnvPath)) {
197
+ copyFileSync(rootEnvPath, `${worktreePath}/.env`)
198
+
199
+ logger.info('📋 Copied .env to worktree')
200
+ }
201
+
158
202
  created.push(branch)
159
203
  } catch (error) {
160
204
  logger.error({ error, branch }, `❌ Failed to create worktree for ${branch}`)
@@ -184,6 +228,7 @@ export const worktreesAddMcpTool = {
184
228
  description: 'Create worktrees for selected release branches',
185
229
  inputSchema: {
186
230
  all: z.boolean().describe('Add worktrees for all release branches without prompting'),
231
+ cursor: z.boolean().optional().describe('Open created worktrees in Cursor'),
187
232
  },
188
233
  outputSchema: {
189
234
  createdWorktrees: z.array(z.string()).describe('List of created worktree branches'),
@@ -62,8 +62,12 @@ const processWorktrees = async (
62
62
  projectRoot: string,
63
63
  ): Promise<WorktreeInfo[]> => {
64
64
  const allWorktrees = [
65
- ...releaseWorktrees.map((branch) => ({ branch, type: 'release' as const })),
66
- ...featureWorktrees.map((branch) => ({ branch, type: 'feature' as const })),
65
+ ...releaseWorktrees.map((branch) => {
66
+ return { branch, type: 'release' as const }
67
+ }),
68
+ ...featureWorktrees.map((branch) => {
69
+ return { branch, type: 'feature' as const }
70
+ }),
67
71
  ]
68
72
 
69
73
  const worktreesInfo: WorktreeInfo[] = []
@@ -97,6 +101,7 @@ const processWorktrees = async (
97
101
  if (a.type !== b.type) {
98
102
  return a.type === 'release' ? -1 : 1
99
103
  }
104
+
100
105
  return a.branch.localeCompare(b.branch)
101
106
  })
102
107
  }
@@ -196,8 +201,12 @@ const logResults = (worktrees: WorktreeInfo[]): void => {
196
201
  logger.info('═'.repeat(100))
197
202
 
198
203
  // Separate releases and features
199
- const releases = worktrees.filter((w) => w.type === 'release')
200
- const features = worktrees.filter((w) => w.type === 'feature')
204
+ const releases = worktrees.filter((w) => {
205
+ return w.type === 'release'
206
+ })
207
+ const features = worktrees.filter((w) => {
208
+ return w.type === 'feature'
209
+ })
201
210
 
202
211
  // Display releases first
203
212
  displayWorktreeSection('🚀 Releases', releases)
@@ -210,7 +219,10 @@ const logResults = (worktrees: WorktreeInfo[]): void => {
210
219
  displayWorktreeSection('✨ Features', features)
211
220
 
212
221
  // Summary
213
- const current = worktrees.find((w) => w.isCurrent)
222
+ const current = worktrees.find((w) => {
223
+ return w.isCurrent
224
+ })
225
+
214
226
  logger.info(`\n${'═'.repeat(100)}`)
215
227
  logger.info(
216
228
  `📊 Summary: ${worktrees.length} total worktrees (${releases.length} releases, ${features.length} features)`,
@@ -258,6 +270,7 @@ const displayWorktree = (worktree: WorktreeInfo): void => {
258
270
 
259
271
  // Commit and sync info
260
272
  const syncInfo = worktree.aheadBehind !== 'unknown' ? ` | ${worktree.aheadBehind}` : ''
273
+
261
274
  logger.info(` 📝 ${worktree.commit}${syncInfo}`)
262
275
 
263
276
  // Last commit message
@@ -265,6 +278,7 @@ const displayWorktree = (worktree: WorktreeInfo): void => {
265
278
 
266
279
  // Path (shortened for display)
267
280
  const shortPath = worktree.path.split('/').slice(-2).join('/')
281
+
268
282
  logger.info(` 📁 ${shortPath}`)
269
283
  }
270
284
 
@@ -26,6 +26,18 @@ export const worktreesRemove = async (options: WorktreeManagementArgs): Promise<
26
26
 
27
27
  try {
28
28
  const currentWorktrees = await getCurrentWorktrees('release')
29
+
30
+ if (currentWorktrees.length === 0) {
31
+ logger.info('ℹ️ No active worktrees to remove')
32
+
33
+ commandEcho.print()
34
+
35
+ return {
36
+ content: [{ type: 'text', text: JSON.stringify({ removedWorktrees: [], count: 0 }, null, 2) }],
37
+ structuredContent: { removedWorktrees: [], count: 0 },
38
+ }
39
+ }
40
+
29
41
  const projectRoot = await getProjectRoot()
30
42
 
31
43
  const worktreeDir = `${projectRoot}${WORKTREES_DIR_SUFFIX}`
@@ -40,10 +52,12 @@ export const worktreesRemove = async (options: WorktreeManagementArgs): Promise<
40
52
  selectedReleaseBranches = await checkbox({
41
53
  required: true,
42
54
  message: '🌿 Select release branches',
43
- choices: currentWorktrees.map((pr) => ({
44
- name: pr.replace('release/v', ''),
45
- value: pr,
46
- })),
55
+ choices: currentWorktrees.map((pr) => {
56
+ return {
57
+ name: pr.replace('release/v', ''),
58
+ value: pr,
59
+ }
60
+ }),
47
61
  })
48
62
  }
49
63
 
@@ -112,6 +126,7 @@ const removeWorktrees = async (branches: string[], worktreeDir: string): Promise
112
126
  for (const branch of branches) {
113
127
  try {
114
128
  const worktreePath = `${worktreeDir}/${branch}`
129
+
115
130
  await $`git worktree remove ${worktreePath}`
116
131
  removed.push(branch)
117
132
  } catch (error) {
@@ -96,9 +96,13 @@ interface CategorizeWorktreesArgs {
96
96
  const categorizeWorktrees = (args: CategorizeWorktreesArgs): { branchesToRemove: string[] } => {
97
97
  const { releasePRsList, currentWorktrees } = args
98
98
 
99
- const currentBranchNames = currentWorktrees.filter((branch) => branch.startsWith(RELEASE_BRANCH_PREFIX))
99
+ const currentBranchNames = currentWorktrees.filter((branch) => {
100
+ return branch.startsWith(RELEASE_BRANCH_PREFIX)
101
+ })
100
102
 
101
- const branchesToRemove = currentBranchNames.filter((branch) => !releasePRsList.includes(branch))
103
+ const branchesToRemove = currentBranchNames.filter((branch) => {
104
+ return !releasePRsList.includes(branch)
105
+ })
102
106
 
103
107
  return { branchesToRemove }
104
108
  }
@@ -112,6 +116,7 @@ const removeWorktrees = async (branches: string[], worktreeDir: string): Promise
112
116
  for (const branch of branches) {
113
117
  try {
114
118
  const worktreePath = `${worktreeDir}/${branch}`
119
+
115
120
  await $`git worktree remove ${worktreePath}`
116
121
  removed.push(branch)
117
122
  } catch (error) {
package/src/entry/cli.ts CHANGED
@@ -132,8 +132,9 @@ program
132
132
  .description('Add git worktrees for release branches')
133
133
  .option('-y, --yes', 'Skip confirmation prompt')
134
134
  .option('-a, --all', 'Select all active release branches')
135
+ .option('-c, --cursor', 'Open created worktrees in Cursor')
135
136
  .action(async (options) => {
136
- await worktreesAdd({ confirmedCommand: options.yes, all: options.all })
137
+ await worktreesAdd({ confirmedCommand: options.yes, all: options.all, cursor: options.cursor })
137
138
  })
138
139
 
139
140
  program
@@ -32,7 +32,10 @@ export const getReleasePRs = async (): Promise<string[]> => {
32
32
  process.exit(1)
33
33
  }
34
34
 
35
- const headRefNames = releasePRsArray.map((pr) => pr.headRefName)
35
+ const headRefNames = releasePRsArray.map((pr) => {
36
+ return pr.headRefName
37
+ })
38
+
36
39
  return sortVersions(headRefNames)
37
40
  } catch (error) {
38
41
  logger.error({ error }, '❌ Error fetching release PRs')
@@ -148,7 +148,9 @@ const getProjectVersions = async (config: JiraConfig): Promise<JiraVersion[]> =>
148
148
  const findVersionByName = async (versionName: string, config: JiraConfig): Promise<JiraVersion | null> => {
149
149
  try {
150
150
  const versions = await getProjectVersions(config)
151
- const version = versions.find((v) => v.name === versionName)
151
+ const version = versions.find((v) => {
152
+ return v.name === versionName
153
+ })
152
154
 
153
155
  return version || null
154
156
  } catch (error) {
@@ -280,6 +282,7 @@ export const loadJiraConfig = async (): Promise<JiraConfig> => {
280
282
  const email = process.env.JIRA_EMAIL
281
283
 
282
284
  const missingVars: string[] = []
285
+
283
286
  if (!baseUrl) missingVars.push('JIRA_BASE_URL (e.g., https://your-domain.atlassian.net)')
284
287
  if (!token) missingVars.push('JIRA_TOKEN or JIRA_API_TOKEN (your Jira API token)')
285
288
  if (!projectIdStr) missingVars.push('JIRA_PROJECT_ID (numeric project ID)')
@@ -289,7 +292,9 @@ export const loadJiraConfig = async (): Promise<JiraConfig> => {
289
292
  const errorMessage = [
290
293
  'Jira configuration is required but incomplete.',
291
294
  'Please configure the following environment variables:',
292
- ...missingVars.map((v) => ` - ${v}`),
295
+ ...missingVars.map((v) => {
296
+ return ` - ${v}`
297
+ }),
293
298
  '',
294
299
  'You can set these in your .env file or as environment variables.',
295
300
  ].join('\n')
@@ -323,6 +328,7 @@ export const loadJiraConfigOptional = async (): Promise<JiraConfig | null> => {
323
328
  return config
324
329
  } catch (error) {
325
330
  logger.warn({ error }, 'Jira configuration not available, skipping Jira integration')
331
+
326
332
  return null
327
333
  }
328
334
  }
@@ -15,7 +15,9 @@ export const getCurrentWorktrees = async (type: 'release' | 'feature'): Promise<
15
15
  feature: featureWorktreePredicate,
16
16
  }
17
17
 
18
- return worktreeLines.map(worktreePredicateMap[type]).filter((branch) => branch !== null)
18
+ return worktreeLines.map(worktreePredicateMap[type]).filter((branch) => {
19
+ return branch !== null
20
+ })
19
21
  }
20
22
 
21
23
  const releaseWorktreePredicate = (line: string): string | null => {