infra-kit 0.1.80 → 0.1.81

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.80",
4
+ "version": "0.1.81",
5
5
  "description": "infra-kit",
6
6
  "main": "dist/cli.js",
7
7
  "module": "dist/cli.js",
@@ -101,7 +101,7 @@ export const ghMergeDev = async (args: GhMergeDevArgs): Promise<ToolsExecutionRe
101
101
  }
102
102
 
103
103
  // Track --yes flag if confirmation was interactive (user confirmed)
104
- if (allSelected) {
104
+ if (!confirmedCommand) {
105
105
  commandEcho.addOption('--yes', true)
106
106
  }
107
107
 
@@ -126,13 +126,11 @@ export const ghMergeDev = async (args: GhMergeDevArgs): Promise<ToolsExecutionRe
126
126
 
127
127
  if (failedBranches.length > 0) {
128
128
  logger.info(`\n⚠️ ${failedBranches.length} branch(es) failed to merge automatically.\n`)
129
- logger.info('📋 Manual merge script for failed branches:\n')
130
- logger.info('```bash')
129
+ logger.info('📋 Manual merge script for failed branches:')
131
130
  for (const branch of failedBranches) {
132
- logger.info(`# Phase #1: Merge dev into ${branch}`)
133
- logger.info(`git switch ${branch} && git pull origin ${branch} && git merge origin/dev`)
134
- logger.info(`# Phase #2:Resolve conflicts if any, then:`)
135
- logger.info(`git push origin ${branch} && git switch dev`)
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`,
133
+ )
136
134
  }
137
135
  logger.info(
138
136
  `✅ ${selectedReleaseBranches.length - failedBranches.length}/${selectedReleaseBranches.length} merges completed successfully.`,
@@ -25,22 +25,6 @@ export const ghReleaseDeployAll = async (args: GhReleaseDeployAllArgs): Promise<
25
25
 
26
26
  commandEcho.start('release-deploy-all')
27
27
 
28
- // TODO: add validation for semver version for version variable
29
-
30
- const releasePRsInfo = await getReleasePRsWithInfo()
31
-
32
- const branches = releasePRsInfo.map((pr) => {
33
- return pr.branch
34
- })
35
-
36
- const releaseTypes = new Map<string, ReleaseType>(
37
- releasePRsInfo.map((pr) => {
38
- return [pr.branch, detectReleaseType(pr.title)]
39
- }),
40
- )
41
-
42
- const releasePRsList: string[] = ['dev', ...branches]
43
-
44
28
  let selectedReleaseBranch = '' // "release/v1.8.0"
45
29
 
46
30
  if (version) {
@@ -48,6 +32,18 @@ export const ghReleaseDeployAll = async (args: GhReleaseDeployAllArgs): Promise<
48
32
  } else {
49
33
  commandEcho.setInteractive()
50
34
 
35
+ const releasePRsInfo = await getReleasePRsWithInfo()
36
+
37
+ const branches = releasePRsInfo.map((pr) => {
38
+ return pr.branch
39
+ })
40
+
41
+ const releaseTypes = new Map<string, ReleaseType>(
42
+ releasePRsInfo.map((pr) => {
43
+ return [pr.branch, detectReleaseType(pr.title)]
44
+ }),
45
+ )
46
+
51
47
  const descriptions = await getJiraDescriptions()
52
48
 
53
49
  selectedReleaseBranch = await select({
@@ -60,12 +56,6 @@ export const ghReleaseDeployAll = async (args: GhReleaseDeployAllArgs): Promise<
60
56
 
61
57
  commandEcho.addOption('--version', selectedVersion)
62
58
 
63
- // Check if release branch exists in the list
64
- if (!releasePRsList.includes(selectedReleaseBranch)) {
65
- logger.error(`❌ Release branch ${selectedReleaseBranch} not found in open PRs. Exiting...`)
66
- process.exit(1)
67
- }
68
-
69
59
  let selectedEnv = ''
70
60
 
71
61
  if (env) {
@@ -32,20 +32,6 @@ export const ghReleaseDeploySelected = async (args: GhReleaseDeploySelectedArgs)
32
32
 
33
33
  commandEcho.start('release-deploy-selected')
34
34
 
35
- const releasePRsInfo = await getReleasePRsWithInfo()
36
-
37
- const branches = releasePRsInfo.map((pr) => {
38
- return pr.branch
39
- })
40
-
41
- const releaseTypes = new Map<string, ReleaseType>(
42
- releasePRsInfo.map((pr) => {
43
- return [pr.branch, detectReleaseType(pr.title)]
44
- }),
45
- )
46
-
47
- const releasePRsList: string[] = ['dev', ...branches]
48
-
49
35
  let selectedReleaseBranch = ''
50
36
 
51
37
  if (version) {
@@ -53,6 +39,18 @@ export const ghReleaseDeploySelected = async (args: GhReleaseDeploySelectedArgs)
53
39
  } else {
54
40
  commandEcho.setInteractive()
55
41
 
42
+ const releasePRsInfo = await getReleasePRsWithInfo()
43
+
44
+ const branches = releasePRsInfo.map((pr) => {
45
+ return pr.branch
46
+ })
47
+
48
+ const releaseTypes = new Map<string, ReleaseType>(
49
+ releasePRsInfo.map((pr) => {
50
+ return [pr.branch, detectReleaseType(pr.title)]
51
+ }),
52
+ )
53
+
56
54
  const descriptions = await getJiraDescriptions()
57
55
 
58
56
  selectedReleaseBranch = await select({
@@ -65,12 +63,6 @@ export const ghReleaseDeploySelected = async (args: GhReleaseDeploySelectedArgs)
65
63
 
66
64
  commandEcho.addOption('--version', selectedVersion)
67
65
 
68
- // Check if release branch exists in the list
69
- if (!releasePRsList.includes(selectedReleaseBranch)) {
70
- logger.error(`❌ Release branch ${selectedReleaseBranch} not found in open PRs. Exiting...`)
71
- process.exit(1)
72
- }
73
-
74
66
  let selectedEnv = ''
75
67
 
76
68
  if (env) {
@@ -30,22 +30,6 @@ export const ghReleaseDeployService = async (args: GhReleaseDeployServiceArgs):
30
30
 
31
31
  commandEcho.start('release-deploy-service')
32
32
 
33
- // TODO: add validation for semver version for version variable
34
-
35
- const releasePRsInfo = await getReleasePRsWithInfo()
36
-
37
- const branches = releasePRsInfo.map((pr) => {
38
- return pr.branch
39
- })
40
-
41
- const releaseTypes = new Map<string, ReleaseType>(
42
- releasePRsInfo.map((pr) => {
43
- return [pr.branch, detectReleaseType(pr.title)]
44
- }),
45
- )
46
-
47
- const releasePRsList: string[] = ['dev', ...branches]
48
-
49
33
  let selectedReleaseBranch = '' // "release/v1.8.0"
50
34
 
51
35
  if (version) {
@@ -53,6 +37,18 @@ export const ghReleaseDeployService = async (args: GhReleaseDeployServiceArgs):
53
37
  } else {
54
38
  commandEcho.setInteractive()
55
39
 
40
+ const releasePRsInfo = await getReleasePRsWithInfo()
41
+
42
+ const branches = releasePRsInfo.map((pr) => {
43
+ return pr.branch
44
+ })
45
+
46
+ const releaseTypes = new Map<string, ReleaseType>(
47
+ releasePRsInfo.map((pr) => {
48
+ return [pr.branch, detectReleaseType(pr.title)]
49
+ }),
50
+ )
51
+
56
52
  const descriptions = await getJiraDescriptions()
57
53
 
58
54
  selectedReleaseBranch = await select({
@@ -65,12 +61,6 @@ export const ghReleaseDeployService = async (args: GhReleaseDeployServiceArgs):
65
61
 
66
62
  commandEcho.addOption('--version', selectedVersion)
67
63
 
68
- // Check if release branch exists in the list
69
- if (!releasePRsList.includes(selectedReleaseBranch)) {
70
- logger.error(`❌ Release branch ${selectedReleaseBranch} not found in open PRs. Exiting...`)
71
- process.exit(1)
72
- }
73
-
74
64
  let selectedEnv = ''
75
65
 
76
66
  if (env) {
@@ -30,9 +30,12 @@ const resolveInputs = async (args: ReleaseCreateBatchArgs): Promise<{ versionsLi
30
30
  versionInput = await question('Enter versions by comma (e.g. 1.2.5, 1.2.6): ')
31
31
  }
32
32
 
33
- const versionsList = versionInput.split(',').map((version) => {
34
- return version.trim()
35
- })
33
+ const versionsList = versionInput
34
+ .split(',')
35
+ .map((version) => {
36
+ return version.trim()
37
+ })
38
+ .filter(Boolean)
36
39
 
37
40
  commandEcho.addOption('--versions', versionsList.join(', '))
38
41
 
@@ -44,53 +44,53 @@ export const worktreesAdd = async (options: WorktreeManagementArgs): Promise<Too
44
44
  await ensureWorktreeDirectory(`${worktreeDir}/${RELEASE_DIR}`)
45
45
  await ensureWorktreeDirectory(`${worktreeDir}/${FEATURE_DIR}`)
46
46
 
47
- const releasePRsInfo = await getReleasePRsWithInfo()
47
+ let selectedReleaseBranches: string[] = []
48
48
 
49
- const releasePRsList = releasePRsInfo.map((pr) => {
50
- return pr.branch
51
- })
49
+ if (versions) {
50
+ selectedReleaseBranches = versions.split(',').map((v) => {
51
+ return `release/v${v.trim()}`
52
+ })
53
+ } else {
54
+ const releasePRsInfo = await getReleasePRsWithInfo()
52
55
 
53
- const releaseTypes = new Map<string, ReleaseType>(
54
- releasePRsInfo.map((pr) => {
55
- return [pr.branch, detectReleaseType(pr.title)]
56
- }),
57
- )
56
+ const releasePRsList = releasePRsInfo.map((pr) => {
57
+ return pr.branch
58
+ })
58
59
 
59
- if (releasePRsList.length === 0) {
60
- logger.info('ℹ️ No open release branches found')
60
+ if (releasePRsList.length === 0) {
61
+ logger.info('ℹ️ No open release branches found')
61
62
 
62
- commandEcho.print()
63
+ commandEcho.print()
63
64
 
64
- return {
65
- content: [{ type: 'text', text: JSON.stringify({ createdWorktrees: [], count: 0 }, null, 2) }],
66
- structuredContent: { createdWorktrees: [], count: 0 },
65
+ return {
66
+ content: [{ type: 'text', text: JSON.stringify({ createdWorktrees: [], count: 0 }, null, 2) }],
67
+ structuredContent: { createdWorktrees: [], count: 0 },
68
+ }
67
69
  }
68
- }
69
70
 
70
- let selectedReleaseBranches: string[] = []
71
+ if (all) {
72
+ selectedReleaseBranches = releasePRsList
73
+ } else {
74
+ commandEcho.setInteractive()
71
75
 
72
- if (all) {
73
- selectedReleaseBranches = releasePRsList
74
- } else if (versions) {
75
- selectedReleaseBranches = versions.split(',').map((v) => {
76
- return `release/v${v.trim()}`
77
- })
78
- } else {
79
- commandEcho.setInteractive()
76
+ const releaseTypes = new Map<string, ReleaseType>(
77
+ releasePRsInfo.map((pr) => {
78
+ return [pr.branch, detectReleaseType(pr.title)]
79
+ }),
80
+ )
80
81
 
81
- const descriptions = await getJiraDescriptions()
82
+ const descriptions = await getJiraDescriptions()
82
83
 
83
- selectedReleaseBranches = await checkbox({
84
- required: true,
85
- message: '🌿 Select release branches',
86
- choices: formatBranchChoices({ branches: releasePRsList, descriptions, types: releaseTypes }),
87
- })
84
+ selectedReleaseBranches = await checkbox({
85
+ required: true,
86
+ message: '🌿 Select release branches',
87
+ choices: formatBranchChoices({ branches: releasePRsList, descriptions, types: releaseTypes }),
88
+ })
89
+ }
88
90
  }
89
91
 
90
92
  // Track --all flag if all branches were selected (either via flag or interactively)
91
- const allSelected = selectedReleaseBranches.length === releasePRsList.length
92
-
93
- if (allSelected) {
93
+ if (all) {
94
94
  commandEcho.addOption('--all', true)
95
95
  } else {
96
96
  commandEcho.addOption(
@@ -118,7 +118,7 @@ export const worktreesAdd = async (options: WorktreeManagementArgs): Promise<Too
118
118
  }
119
119
 
120
120
  // Track --yes flag if confirmation was interactive (user confirmed)
121
- if (allSelected) {
121
+ if (!confirmedCommand) {
122
122
  commandEcho.addOption('--yes', true)
123
123
  }
124
124
 
@@ -1,300 +1,82 @@
1
1
  import { z } from 'zod'
2
- import { $ } from 'zx'
3
2
 
4
- import { getCurrentWorktrees, getProjectRoot } from 'src/lib/git-utils'
3
+ import { getReleasePRsWithInfo } from 'src/integrations/gh'
4
+ import { getCurrentWorktrees } from 'src/lib/git-utils'
5
5
  import { logger } from 'src/lib/logger'
6
+ import { detectReleaseType, formatVersionLabel, getJiraDescriptions } from 'src/lib/release-utils'
7
+ import type { ReleaseType } from 'src/lib/release-utils'
6
8
  import type { ToolsExecutionResult } from 'src/types'
7
9
 
8
10
  interface WorktreeInfo {
9
- branch: string
10
- path: string
11
- commit: string
12
- isCurrent: boolean
13
- type: 'release' | 'feature'
14
- status: string
15
- lastCommitMessage: string
16
- aheadBehind: string
11
+ version: string
12
+ type: ReleaseType
13
+ description: string | null
17
14
  }
18
15
 
19
16
  /**
20
- * List all (features and releases) git worktrees with detailed information
17
+ * List all release git worktrees with version, type, and Jira description
21
18
  */
22
19
  export const worktreesList = async (): Promise<ToolsExecutionResult> => {
23
- try {
24
- const [releaseWorktrees, featureWorktrees] = await Promise.all([
25
- getCurrentWorktrees('release'),
26
- getCurrentWorktrees('feature'),
27
- ])
20
+ const currentWorktrees = await getCurrentWorktrees('release')
28
21
 
29
- const projectRoot = await getProjectRoot()
30
- const worktreesInfo = await processWorktrees(releaseWorktrees, featureWorktrees, projectRoot)
31
-
32
- logResults(worktreesInfo)
33
-
34
- const structuredContent = {
35
- worktrees: worktreesInfo,
36
- totalCount: worktreesInfo.length,
37
- releaseCount: releaseWorktrees.length,
38
- featureCount: featureWorktrees.length,
39
- }
22
+ if (currentWorktrees.length === 0) {
23
+ logger.info('ℹ️ No active worktrees found')
40
24
 
41
25
  return {
42
- content: [
43
- {
44
- type: 'text',
45
- text: JSON.stringify(structuredContent, null, 2),
46
- },
47
- ],
48
- structuredContent,
49
- }
50
- } catch (error) {
51
- logger.error({ error }, '❌ Error listing worktrees')
52
- throw error
53
- }
54
- }
55
-
56
- /**
57
- * Process worktrees to get detailed information
58
- */
59
- const processWorktrees = async (
60
- releaseWorktrees: string[],
61
- featureWorktrees: string[],
62
- projectRoot: string,
63
- ): Promise<WorktreeInfo[]> => {
64
- const allWorktrees = [
65
- ...releaseWorktrees.map((branch) => {
66
- return { branch, type: 'release' as const }
67
- }),
68
- ...featureWorktrees.map((branch) => {
69
- return { branch, type: 'feature' as const }
70
- }),
71
- ]
72
-
73
- const worktreesInfo: WorktreeInfo[] = []
74
-
75
- for (const { branch, type } of allWorktrees) {
76
- try {
77
- const worktreePath = `${projectRoot}/${branch}`
78
- const isCurrent = await isCurrentWorktree(branch)
79
- const commit = await getWorktreeCommit(worktreePath)
80
- const status = await getWorktreeStatus(worktreePath)
81
- const lastCommitMessage = await getLastCommitMessage(worktreePath)
82
- const aheadBehind = await getAheadBehind(worktreePath)
83
-
84
- worktreesInfo.push({
85
- branch,
86
- path: worktreePath,
87
- commit: commit.substring(0, 8),
88
- isCurrent,
89
- type,
90
- status,
91
- lastCommitMessage: lastCommitMessage.substring(0, 60) + (lastCommitMessage.length > 60 ? '...' : ''),
92
- aheadBehind,
93
- })
94
- } catch (error) {
95
- logger.warn({ error, branch }, `⚠️ Could not process worktree ${branch}`)
96
- }
97
- }
98
-
99
- return worktreesInfo.sort((a, b) => {
100
- // Sort by type first (releases before features), then by branch name
101
- if (a.type !== b.type) {
102
- return a.type === 'release' ? -1 : 1
26
+ content: [{ type: 'text', text: JSON.stringify({ worktrees: [], count: 0 }, null, 2) }],
27
+ structuredContent: { worktrees: [], count: 0 },
103
28
  }
104
-
105
- return a.branch.localeCompare(b.branch)
106
- })
107
- }
108
-
109
- /**
110
- * Check if a worktree is currently active
111
- */
112
- const isCurrentWorktree = async (branch: string): Promise<boolean> => {
113
- try {
114
- const currentBranch = await $`git branch --show-current`
115
-
116
- return currentBranch.stdout.trim() === branch
117
- } catch {
118
- return false
119
- }
120
- }
121
-
122
- /**
123
- * Get the commit hash for a worktree
124
- */
125
- const getWorktreeCommit = async (worktreePath: string): Promise<string> => {
126
- try {
127
- const result = await $`cd ${worktreePath} && git rev-parse HEAD`
128
-
129
- return result.stdout.trim()
130
- } catch {
131
- return 'unknown'
132
- }
133
- }
134
-
135
- /**
136
- * Get the status of a worktree
137
- */
138
- const getWorktreeStatus = async (worktreePath: string): Promise<string> => {
139
- try {
140
- const result = await $`cd ${worktreePath} && git status --porcelain`
141
- const changes = result.stdout.trim().split('\n').filter(Boolean)
142
-
143
- if (changes.length === 0) return 'clean'
144
- if (changes.length <= 3) return 'modified'
145
-
146
- return 'dirty'
147
- } catch {
148
- return 'unknown'
149
- }
150
- }
151
-
152
- /**
153
- * Get the last commit message for a worktree
154
- */
155
- const getLastCommitMessage = async (worktreePath: string): Promise<string> => {
156
- try {
157
- const result = await $`cd ${worktreePath} && git log -1 --pretty=format:"%s"`
158
-
159
- return result.stdout.trim()
160
- } catch {
161
- return 'No commit message available'
162
- }
163
- }
164
-
165
- /**
166
- * Get ahead/behind information for a worktree
167
- */
168
- const getAheadBehind = async (worktreePath: string): Promise<string> => {
169
- try {
170
- const result =
171
- await $`cd ${worktreePath} && git rev-list --count --left-right @{u}...HEAD 2>/dev/null || echo "0 0"`
172
-
173
- const parts = result.stdout.trim().split('\t').map(Number)
174
- const behind = parts[0] || 0
175
- const ahead = parts[1] || 0
176
-
177
- if (ahead === 0 && behind === 0) return 'up to date'
178
- if (ahead > 0 && behind === 0) return `↑${ahead} ahead`
179
- if (behind > 0 && ahead === 0) return `↓${behind} behind`
180
-
181
- return `↑${ahead} ↓${behind}`
182
- } catch {
183
- return 'unknown'
184
- }
185
- }
186
-
187
- /**
188
- * Log the worktrees list in a beautiful formatted way
189
- */
190
- const logResults = (worktrees: WorktreeInfo[]): void => {
191
- if (worktrees.length === 0) {
192
- logger.info('\n🌿 Git Worktrees')
193
- logger.info('─'.repeat(80))
194
- logger.info('ℹ️ No worktrees found')
195
- logger.info('─'.repeat(80))
196
-
197
- return
198
29
  }
199
30
 
200
- logger.info('\n🌿 Git Worktrees')
201
- logger.info('═'.repeat(100))
202
-
203
- // Separate releases and features
204
- const releases = worktrees.filter((w) => {
205
- return w.type === 'release'
206
- })
207
- const features = worktrees.filter((w) => {
208
- return w.type === 'feature'
209
- })
210
-
211
- // Display releases first
212
- displayWorktreeSection('🚀 Releases', releases)
31
+ const [releasePRsInfo, jiraDescriptions] = await Promise.all([getReleasePRsWithInfo(), getJiraDescriptions()])
213
32
 
214
- // Display features second
215
- if (features.length > 0 && releases.length > 0) {
216
- logger.info('')
217
- }
33
+ const releaseTypes = new Map<string, ReleaseType>(
34
+ releasePRsInfo.map((pr) => {
35
+ return [pr.branch, detectReleaseType(pr.title)]
36
+ }),
37
+ )
218
38
 
219
- displayWorktreeSection('✨ Features', features)
39
+ const worktrees: WorktreeInfo[] = currentWorktrees.map((branch) => {
40
+ const version = branch.replace('release/', '')
41
+ const type = releaseTypes.get(branch) || 'regular'
42
+ const description = jiraDescriptions.get(version) || null
220
43
 
221
- // Summary
222
- const current = worktrees.find((w) => {
223
- return w.isCurrent
44
+ return { version, type, description }
224
45
  })
225
46
 
226
- logger.info(`\n${'═'.repeat(100)}`)
227
- logger.info(
228
- `📊 Summary: ${worktrees.length} total git worktrees (${releases.length} releases, ${features.length} features)`,
47
+ // Log formatted output
48
+ const maxVersionLength = Math.max(
49
+ ...worktrees.map((w) => {
50
+ return w.version.length
51
+ }),
229
52
  )
230
53
 
231
- if (current) {
232
- logger.info(`📍 Currently on: ${current.branch}`)
233
- }
234
-
235
- logger.info('')
236
- }
237
-
238
- /**
239
- * Display a section of worktrees
240
- */
241
- const displayWorktreeSection = (sectionTitle: string, worktrees: WorktreeInfo[]): void => {
242
- if (worktrees.length === 0) return
243
-
244
- logger.info(`\n${sectionTitle}`)
245
- logger.info('─'.repeat(50))
54
+ const formattedLines = worktrees.map((worktree) => {
55
+ const label = formatVersionLabel(worktree.version, worktree.type, maxVersionLength)
246
56
 
247
- for (const [index, worktree] of worktrees.entries()) {
248
- displayWorktree(worktree)
249
-
250
- if (index < worktrees.length - 1) {
251
- logger.info('')
57
+ if (worktree.description) {
58
+ return `${label} ${worktree.description}`
252
59
  }
253
- }
254
- }
255
-
256
- /**
257
- * Display a single worktree entry
258
- */
259
- const displayWorktree = (worktree: WorktreeInfo): void => {
260
- // Worktree status indicators
261
- const currentIndicator = worktree.isCurrent ? '📍' : ' '
262
- const statusIndicator = getStatusIndicator(worktree.status)
263
-
264
- const typeIcon = worktree.type === 'release' ? '🚀' : '✨'
265
-
266
- // Branch name with color coding
267
- const branchDisplay = `${typeIcon} ${worktree.branch}`
268
-
269
- logger.info(`${currentIndicator} ${statusIndicator} ${branchDisplay}`)
270
-
271
- // Commit and sync info
272
- const syncInfo = worktree.aheadBehind !== 'unknown' ? ` | ${worktree.aheadBehind}` : ''
273
-
274
- logger.info(` 📝 ${worktree.commit}${syncInfo}`)
275
60
 
276
- // Last commit message
277
- logger.info(` 💬 ${worktree.lastCommitMessage}`)
61
+ return label
62
+ })
278
63
 
279
- // Path (shortened for display)
280
- const shortPath = worktree.path.split('/').slice(-2).join('/')
64
+ logger.info('🌿 Active worktrees:')
65
+ logger.info(`\n${formattedLines.join('\n')}\n`)
281
66
 
282
- logger.info(` 📁 ${shortPath}`)
283
- }
67
+ const structuredContent = {
68
+ worktrees,
69
+ count: worktrees.length,
70
+ }
284
71
 
285
- /**
286
- * Get status indicator based on worktree status
287
- */
288
- const getStatusIndicator = (status: string): string => {
289
- switch (status) {
290
- case 'clean':
291
- return '✅'
292
- case 'modified':
293
- return '⚠️ '
294
- case 'dirty':
295
- return '🔴'
296
- default:
297
- return '❓'
72
+ return {
73
+ content: [
74
+ {
75
+ type: 'text',
76
+ text: JSON.stringify(structuredContent, null, 2),
77
+ },
78
+ ],
79
+ structuredContent,
298
80
  }
299
81
  }
300
82
 
@@ -307,20 +89,13 @@ export const worktreesListMcpTool = {
307
89
  worktrees: z
308
90
  .array(
309
91
  z.object({
310
- branch: z.string(),
311
- path: z.string(),
312
- commit: z.string(),
313
- isCurrent: z.boolean(),
314
- type: z.enum(['release', 'feature']),
315
- status: z.string(),
316
- lastCommitMessage: z.string(),
317
- aheadBehind: z.string(),
92
+ version: z.string().describe('Release version'),
93
+ type: z.enum(['regular', 'hotfix']).describe('Release type'),
94
+ description: z.string().nullable().describe('Jira version description'),
318
95
  }),
319
96
  )
320
97
  .describe('List of all worktrees with details'),
321
- totalCount: z.number().describe('Total number of worktrees'),
322
- releaseCount: z.number().describe('Number of release worktrees'),
323
- featureCount: z.number().describe('Number of feature worktrees'),
98
+ count: z.number().describe('Number of worktrees'),
324
99
  },
325
100
  handler: worktreesList,
326
101
  }