infra-kit 0.1.39 → 0.1.41
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/dist/cli.js +18 -18
- package/dist/cli.js.map +4 -4
- package/dist/mcp.js +18 -1
- package/dist/mcp.js.map +4 -4
- package/package.json +3 -2
- package/src/commands/gh-merge-dev/gh-merge-dev.ts +59 -22
- package/src/commands/gh-merge-dev/index.ts +1 -1
- package/src/commands/gh-release-create/gh-release-create.ts +58 -20
- package/src/commands/gh-release-create/index.ts +1 -1
- package/src/commands/gh-release-deliver/gh-release-deliver.ts +47 -11
- package/src/commands/gh-release-deliver/index.ts +1 -1
- package/src/commands/gh-release-deploy/gh-release-deploy.ts +47 -7
- package/src/commands/gh-release-deploy/index.ts +1 -1
- package/src/commands/gh-release-list/gh-release-list.ts +37 -5
- package/src/commands/gh-release-list/index.ts +1 -1
- package/src/commands/worktrees-add/index.ts +1 -1
- package/src/commands/worktrees-add/worktrees-add.ts +45 -19
- package/src/commands/worktrees-list/index.ts +1 -1
- package/src/commands/worktrees-list/worktrees-list.ts +69 -33
- package/src/commands/worktrees-remove/index.ts +1 -1
- package/src/commands/worktrees-remove/worktrees-remove.ts +44 -18
- package/src/commands/worktrees-sync/index.ts +1 -1
- package/src/commands/worktrees-sync/worktrees-sync.ts +42 -19
- package/src/entry/cli.ts +6 -6
- package/src/entry/mcp.ts +4 -4
- package/src/lib/error-handlers/index.ts +8 -2
- package/src/lib/logger/index.ts +23 -2
- package/src/mcp/prompts/index.ts +1 -1
- package/src/mcp/resources/index.ts +1 -1
- package/src/mcp/server.ts +2 -2
- package/src/mcp/tools/index.ts +39 -1
- package/src/shared/gh-cli-auth/gh-cli-auth.ts +6 -4
- package/src/shared/gh-release-prs/gh-release-prs.ts +4 -2
- package/src/shared/logger/index.ts +4 -0
- package/src/shared/tool-handler/index.ts +1 -0
- package/src/shared/tool-handler/tool-handler.ts +29 -0
- package/src/types.ts +11 -0
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
1
|
import confirm from '@inquirer/confirm'
|
|
3
2
|
import select from '@inquirer/select'
|
|
4
3
|
import process from 'node:process'
|
|
4
|
+
import { z } from 'zod'
|
|
5
5
|
import { $ } from 'zx'
|
|
6
6
|
|
|
7
7
|
import { getReleasePRs } from 'src/shared/gh-release-prs'
|
|
8
|
+
import { logger } from 'src/shared/logger'
|
|
9
|
+
import type { RequiredConfirmedOptionArg, ToolsExecutionResult } from 'src/types'
|
|
8
10
|
|
|
9
|
-
interface GhReleaseDeliverArgs {
|
|
11
|
+
interface GhReleaseDeliverArgs extends RequiredConfirmedOptionArg {
|
|
10
12
|
version: string
|
|
11
|
-
yes: boolean
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Deliver a release branch to production
|
|
16
17
|
*/
|
|
17
|
-
export const ghReleaseDeliver = async (args: GhReleaseDeliverArgs): Promise<
|
|
18
|
-
const { version,
|
|
18
|
+
export const ghReleaseDeliver = async (args: GhReleaseDeliverArgs): Promise<ToolsExecutionResult> => {
|
|
19
|
+
const { version, confirmedCommand } = args
|
|
19
20
|
|
|
20
21
|
const releasePRsList = await getReleasePRs()
|
|
21
22
|
|
|
@@ -35,18 +36,18 @@ export const ghReleaseDeliver = async (args: GhReleaseDeliverArgs): Promise<void
|
|
|
35
36
|
|
|
36
37
|
// Check if release branch exists in the list
|
|
37
38
|
if (!releasePRsList.includes(selectedReleaseBranch)) {
|
|
38
|
-
|
|
39
|
+
logger.error(`❌ Release branch ${selectedReleaseBranch} not found in open PRs. Exiting...`)
|
|
39
40
|
process.exit(1)
|
|
40
41
|
}
|
|
41
42
|
|
|
42
|
-
const answer =
|
|
43
|
+
const answer = confirmedCommand
|
|
43
44
|
? true
|
|
44
45
|
: await confirm({
|
|
45
46
|
message: `Are you sure you want to deliver version ${selectedReleaseBranch} to production?`,
|
|
46
47
|
})
|
|
47
48
|
|
|
48
49
|
if (!answer) {
|
|
49
|
-
|
|
50
|
+
logger.info('Operation cancelled. Exiting...')
|
|
50
51
|
process.exit(0)
|
|
51
52
|
}
|
|
52
53
|
|
|
@@ -62,10 +63,45 @@ export const ghReleaseDeliver = async (args: GhReleaseDeliverArgs): Promise<void
|
|
|
62
63
|
// Merge main into dev
|
|
63
64
|
await $`git switch main && git pull && git switch dev && git pull && git merge main --no-edit && git push`
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
logger.info('\n')
|
|
67
|
+
logger.info(`✔️ Successfully delivered ${selectedReleaseBranch} to production!`)
|
|
68
|
+
|
|
69
|
+
const structuredContent = {
|
|
70
|
+
releaseBranch: selectedReleaseBranch,
|
|
71
|
+
version: selectedReleaseBranch.replace('release/v', ''),
|
|
72
|
+
success: true,
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
content: [
|
|
77
|
+
{
|
|
78
|
+
type: 'text',
|
|
79
|
+
text: JSON.stringify(structuredContent, null, 2),
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
structuredContent,
|
|
83
|
+
}
|
|
67
84
|
} catch (error: unknown) {
|
|
68
|
-
|
|
85
|
+
logger.error({ error }, '❌ Error merging release branch into dev')
|
|
69
86
|
process.exit(1)
|
|
70
87
|
}
|
|
71
88
|
}
|
|
89
|
+
|
|
90
|
+
// MCP Tool Registration
|
|
91
|
+
const ghReleaseDeliverSchema = z.object({
|
|
92
|
+
version: z.string().describe('Version to deliver to production (e.g., "1.2.5")'),
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
const ghReleaseDeliverOutputSchema = z.object({
|
|
96
|
+
releaseBranch: z.string().describe('The release branch that was delivered'),
|
|
97
|
+
version: z.string().describe('The version that was delivered'),
|
|
98
|
+
success: z.boolean().describe('Whether the delivery was successful'),
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
export const ghReleaseDeliverMcpTool = {
|
|
102
|
+
name: 'gh-release-deliver',
|
|
103
|
+
description: 'Deliver a release branch to production',
|
|
104
|
+
inputSchema: ghReleaseDeliverSchema,
|
|
105
|
+
outputSchema: ghReleaseDeliverOutputSchema,
|
|
106
|
+
handler: ghReleaseDeliver,
|
|
107
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { ghReleaseDeliver } from './gh-release-deliver'
|
|
1
|
+
export { ghReleaseDeliver, ghReleaseDeliverMcpTool } from './gh-release-deliver'
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
1
|
import select from '@inquirer/select'
|
|
3
2
|
import process from 'node:process'
|
|
3
|
+
import { z } from 'zod'
|
|
4
4
|
import { $ } from 'zx'
|
|
5
5
|
|
|
6
6
|
import { ENVs } from 'src/shared/constants'
|
|
7
7
|
import { getReleasePRs } from 'src/shared/gh-release-prs'
|
|
8
|
+
import { logger } from 'src/shared/logger'
|
|
9
|
+
import type { ToolsExecutionResult } from 'src/types'
|
|
8
10
|
|
|
9
11
|
interface GhReleaseDeployArgs {
|
|
10
12
|
version: string
|
|
@@ -14,7 +16,7 @@ interface GhReleaseDeployArgs {
|
|
|
14
16
|
/**
|
|
15
17
|
* Deploy a release branch to an environment
|
|
16
18
|
*/
|
|
17
|
-
export const ghReleaseDeploy = async (args: GhReleaseDeployArgs): Promise<
|
|
19
|
+
export const ghReleaseDeploy = async (args: GhReleaseDeployArgs): Promise<ToolsExecutionResult> => {
|
|
18
20
|
const { version, env } = args
|
|
19
21
|
|
|
20
22
|
// TODO: add validation for semver version for version variable
|
|
@@ -41,7 +43,7 @@ export const ghReleaseDeploy = async (args: GhReleaseDeployArgs): Promise<void>
|
|
|
41
43
|
|
|
42
44
|
// Check if release branch exists in the list
|
|
43
45
|
if (!releasePRsList.includes(selectedReleaseBranch)) {
|
|
44
|
-
|
|
46
|
+
logger.error(`❌ Release branch ${selectedReleaseBranch} not found in open PRs. Exiting...`)
|
|
45
47
|
process.exit(1)
|
|
46
48
|
}
|
|
47
49
|
|
|
@@ -60,19 +62,57 @@ export const ghReleaseDeploy = async (args: GhReleaseDeployArgs): Promise<void>
|
|
|
60
62
|
}
|
|
61
63
|
|
|
62
64
|
if (!ENVs.includes(selectedEnv)) {
|
|
63
|
-
|
|
65
|
+
logger.error(`❌ Invalid environment: ${selectedEnv}. Exiting...`)
|
|
64
66
|
process.exit(1)
|
|
65
67
|
}
|
|
66
68
|
|
|
67
69
|
try {
|
|
68
70
|
await $`gh workflow run deploy-all.yml --ref ${selectedReleaseBranch} -f environment=${selectedEnv}`
|
|
69
71
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
logger.info('\n')
|
|
73
|
+
logger.info(
|
|
72
74
|
`✅ Successfully launched deploy-all workflow_dispatch for release branch: ${selectedReleaseBranch} and environment: ${selectedEnv}`,
|
|
73
75
|
)
|
|
76
|
+
|
|
77
|
+
const structuredContent = {
|
|
78
|
+
releaseBranch: selectedReleaseBranch,
|
|
79
|
+
version: selectedReleaseBranch.replace('release/v', ''),
|
|
80
|
+
environment: selectedEnv,
|
|
81
|
+
success: true,
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
content: [
|
|
86
|
+
{
|
|
87
|
+
type: 'text',
|
|
88
|
+
text: JSON.stringify(structuredContent, null, 2),
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
structuredContent,
|
|
92
|
+
}
|
|
74
93
|
} catch (error: unknown) {
|
|
75
|
-
|
|
94
|
+
logger.error({ error }, '❌ Error launching workflow')
|
|
76
95
|
process.exit(1)
|
|
77
96
|
}
|
|
78
97
|
}
|
|
98
|
+
|
|
99
|
+
// MCP Tool Registration
|
|
100
|
+
const ghReleaseDeploySchema = z.object({
|
|
101
|
+
version: z.string().describe('Version to deploy (e.g., "1.2.5")'),
|
|
102
|
+
env: z.string().describe('Environment to deploy to (e.g., "dev", "renana", "oriana")'),
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
const ghReleaseDeployOutputSchema = z.object({
|
|
106
|
+
releaseBranch: z.string().describe('The release branch that was deployed'),
|
|
107
|
+
version: z.string().describe('The version that was deployed'),
|
|
108
|
+
environment: z.string().describe('The environment deployed to'),
|
|
109
|
+
success: z.boolean().describe('Whether the deployment was successful'),
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
export const ghReleaseDeployMcpTool = {
|
|
113
|
+
name: 'gh-release-deploy',
|
|
114
|
+
description: 'Deploy a release branch to a specified environment',
|
|
115
|
+
inputSchema: ghReleaseDeploySchema,
|
|
116
|
+
outputSchema: ghReleaseDeployOutputSchema,
|
|
117
|
+
handler: ghReleaseDeploy,
|
|
118
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { ghReleaseDeploy } from './gh-release-deploy'
|
|
1
|
+
export { ghReleaseDeploy, ghReleaseDeployMcpTool } from './gh-release-deploy'
|
|
@@ -1,18 +1,50 @@
|
|
|
1
|
-
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
2
3
|
import { getReleasePRs } from 'src/shared/gh-release-prs'
|
|
4
|
+
import { logger } from 'src/shared/logger'
|
|
3
5
|
import { sortVersions } from 'src/shared/version-utils'
|
|
6
|
+
import type { ToolsExecutionResult } from 'src/types'
|
|
4
7
|
|
|
5
8
|
/**
|
|
6
9
|
* List all open release branches
|
|
7
10
|
*/
|
|
8
|
-
export const ghReleaseList = async () => {
|
|
11
|
+
export const ghReleaseList = async (): Promise<ToolsExecutionResult> => {
|
|
9
12
|
const releasePRs = await getReleasePRs()
|
|
10
13
|
|
|
11
14
|
const releasePRsList = releasePRs.map((pr) => pr.replace('release/', ''))
|
|
12
15
|
const sortedReleases = sortVersions(releasePRsList)
|
|
13
16
|
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
logger.info('All release branches: \n')
|
|
18
|
+
logger.info(sortedReleases.join('\n'))
|
|
19
|
+
|
|
20
|
+
const structuredContent = {
|
|
21
|
+
releases: sortedReleases,
|
|
22
|
+
count: sortedReleases.length,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
content: [
|
|
27
|
+
{
|
|
28
|
+
type: 'text',
|
|
29
|
+
text: JSON.stringify(structuredContent, null, 2),
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
structuredContent,
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// MCP Tool Registration
|
|
37
|
+
const ghReleaseListSchema = z.object({})
|
|
38
|
+
|
|
39
|
+
const ghReleaseListOutputSchema = z.object({
|
|
40
|
+
releases: z.array(z.string()).describe('List of all release branches'),
|
|
41
|
+
count: z.number().describe('Number of release branches'),
|
|
42
|
+
})
|
|
16
43
|
|
|
17
|
-
|
|
44
|
+
export const ghReleaseListMcpTool = {
|
|
45
|
+
name: 'gh-release-list',
|
|
46
|
+
description: 'List all open release branches',
|
|
47
|
+
inputSchema: ghReleaseListSchema,
|
|
48
|
+
outputSchema: ghReleaseListOutputSchema,
|
|
49
|
+
handler: ghReleaseList,
|
|
18
50
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { ghReleaseList } from './gh-release-list'
|
|
1
|
+
export { ghReleaseList, ghReleaseListMcpTool } from './gh-release-list'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { worktreesAdd } from './worktrees-add'
|
|
1
|
+
export { worktreesAdd, worktreesAddMcpTool } from './worktrees-add'
|
|
@@ -1,33 +1,30 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
1
|
import checkbox from '@inquirer/checkbox'
|
|
3
2
|
import confirm from '@inquirer/confirm'
|
|
4
3
|
import process from 'node:process'
|
|
4
|
+
import { z } from 'zod'
|
|
5
5
|
import { $ } from 'zx'
|
|
6
6
|
|
|
7
7
|
import { WORKTREES_DIR_SUFFIX } from 'src/shared/constants'
|
|
8
8
|
import { getReleasePRs } from 'src/shared/gh-release-prs'
|
|
9
9
|
import { getCurrentWorktrees, getProjectRoot } from 'src/shared/git-utils'
|
|
10
|
+
import { logger } from 'src/shared/logger'
|
|
11
|
+
import type { RequiredConfirmedOptionArg, ToolsExecutionResult } from 'src/types'
|
|
10
12
|
|
|
11
13
|
// Constants
|
|
12
14
|
const FEATURE_DIR = 'feature'
|
|
13
15
|
const RELEASE_DIR = 'release'
|
|
14
16
|
const RELEASE_BRANCH_PREFIX = 'release/v'
|
|
15
17
|
|
|
16
|
-
interface WorktreeManagementArgs {
|
|
17
|
-
yes: boolean
|
|
18
|
+
interface WorktreeManagementArgs extends RequiredConfirmedOptionArg {
|
|
18
19
|
all: boolean
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
interface WorktreeManagementResult {
|
|
22
|
-
created: string[]
|
|
23
|
-
}
|
|
24
|
-
|
|
25
22
|
/**
|
|
26
23
|
* Manage git worktrees for release branches
|
|
27
24
|
* Creates worktrees for active release branches and removes unused ones
|
|
28
25
|
*/
|
|
29
|
-
export const worktreesAdd = async (options: WorktreeManagementArgs): Promise<
|
|
30
|
-
const {
|
|
26
|
+
export const worktreesAdd = async (options: WorktreeManagementArgs): Promise<ToolsExecutionResult> => {
|
|
27
|
+
const { confirmedCommand, all } = options
|
|
31
28
|
|
|
32
29
|
try {
|
|
33
30
|
const currentWorktrees = await getCurrentWorktrees('release')
|
|
@@ -55,14 +52,14 @@ export const worktreesAdd = async (options: WorktreeManagementArgs): Promise<Wor
|
|
|
55
52
|
}
|
|
56
53
|
|
|
57
54
|
// Ask for confirmation
|
|
58
|
-
const answer =
|
|
55
|
+
const answer = confirmedCommand
|
|
59
56
|
? true
|
|
60
57
|
: await confirm({
|
|
61
58
|
message: 'Are you sure you want to proceed with these worktree changes?',
|
|
62
59
|
})
|
|
63
60
|
|
|
64
61
|
if (!answer) {
|
|
65
|
-
|
|
62
|
+
logger.info('Operation cancelled. Exiting...')
|
|
66
63
|
process.exit(0)
|
|
67
64
|
}
|
|
68
65
|
|
|
@@ -75,11 +72,22 @@ export const worktreesAdd = async (options: WorktreeManagementArgs): Promise<Wor
|
|
|
75
72
|
|
|
76
73
|
logResults(createdWorktrees)
|
|
77
74
|
|
|
75
|
+
const structuredContent = {
|
|
76
|
+
createdWorktrees,
|
|
77
|
+
count: createdWorktrees.length,
|
|
78
|
+
}
|
|
79
|
+
|
|
78
80
|
return {
|
|
79
|
-
|
|
81
|
+
content: [
|
|
82
|
+
{
|
|
83
|
+
type: 'text',
|
|
84
|
+
text: JSON.stringify(structuredContent, null, 2),
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
structuredContent,
|
|
80
88
|
}
|
|
81
89
|
} catch (error) {
|
|
82
|
-
|
|
90
|
+
logger.error({ error }, '❌ Error managing worktrees')
|
|
83
91
|
throw error
|
|
84
92
|
}
|
|
85
93
|
}
|
|
@@ -123,7 +131,7 @@ const createWorktrees = async (branches: string[], worktreeDir: string): Promise
|
|
|
123
131
|
|
|
124
132
|
created.push(branch)
|
|
125
133
|
} catch (error) {
|
|
126
|
-
|
|
134
|
+
logger.error({ error, branch }, `❌ Failed to create worktree for ${branch}`)
|
|
127
135
|
}
|
|
128
136
|
}
|
|
129
137
|
|
|
@@ -135,11 +143,29 @@ const createWorktrees = async (branches: string[], worktreeDir: string): Promise
|
|
|
135
143
|
*/
|
|
136
144
|
const logResults = (created: string[]): void => {
|
|
137
145
|
if (created.length > 0) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
146
|
+
logger.info('\n')
|
|
147
|
+
logger.info('✅ Created worktrees:')
|
|
148
|
+
logger.info(created.join('\n'))
|
|
149
|
+
logger.info('')
|
|
142
150
|
} else {
|
|
143
|
-
|
|
151
|
+
logger.info('ℹ️ No new worktrees to create')
|
|
144
152
|
}
|
|
145
153
|
}
|
|
154
|
+
|
|
155
|
+
// MCP Tool Registration
|
|
156
|
+
const worktreesAddSchema = z.object({
|
|
157
|
+
all: z.boolean().describe('Add worktrees for all release branches without prompting'),
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
const worktreesAddOutputSchema = z.object({
|
|
161
|
+
createdWorktrees: z.array(z.string()).describe('List of created worktree branches'),
|
|
162
|
+
count: z.number().describe('Number of worktrees created'),
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
export const worktreesAddMcpTool = {
|
|
166
|
+
name: 'worktrees-add',
|
|
167
|
+
description: 'Create worktrees for selected release branches',
|
|
168
|
+
inputSchema: worktreesAddSchema,
|
|
169
|
+
outputSchema: worktreesAddOutputSchema,
|
|
170
|
+
handler: worktreesAdd,
|
|
171
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { worktreesList } from './worktrees-list'
|
|
1
|
+
export { worktreesList, worktreesListMcpTool } from './worktrees-list'
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import { z } from 'zod'
|
|
2
2
|
import { $ } from 'zx'
|
|
3
3
|
|
|
4
4
|
import { getCurrentWorktrees, getProjectRoot } from 'src/shared/git-utils'
|
|
5
|
+
import { logger } from 'src/shared/logger'
|
|
6
|
+
import type { ToolsExecutionResult } from 'src/types'
|
|
5
7
|
|
|
6
8
|
interface WorktreeInfo {
|
|
7
9
|
branch: string
|
|
@@ -14,17 +16,10 @@ interface WorktreeInfo {
|
|
|
14
16
|
aheadBehind: string
|
|
15
17
|
}
|
|
16
18
|
|
|
17
|
-
interface WorktreesListResult {
|
|
18
|
-
worktrees: WorktreeInfo[]
|
|
19
|
-
total: number
|
|
20
|
-
releases: number
|
|
21
|
-
features: number
|
|
22
|
-
}
|
|
23
|
-
|
|
24
19
|
/**
|
|
25
20
|
* List all (features and releases) git worktrees with detailed information
|
|
26
21
|
*/
|
|
27
|
-
export const worktreesList = async (): Promise<
|
|
22
|
+
export const worktreesList = async (): Promise<ToolsExecutionResult> => {
|
|
28
23
|
try {
|
|
29
24
|
const [releaseWorktrees, featureWorktrees] = await Promise.all([
|
|
30
25
|
getCurrentWorktrees('release'),
|
|
@@ -36,14 +31,24 @@ export const worktreesList = async (): Promise<WorktreesListResult> => {
|
|
|
36
31
|
|
|
37
32
|
logResults(worktreesInfo)
|
|
38
33
|
|
|
39
|
-
|
|
34
|
+
const structuredContent = {
|
|
40
35
|
worktrees: worktreesInfo,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
36
|
+
totalCount: worktreesInfo.length,
|
|
37
|
+
releaseCount: releaseWorktrees.length,
|
|
38
|
+
featureCount: featureWorktrees.length,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
content: [
|
|
43
|
+
{
|
|
44
|
+
type: 'text',
|
|
45
|
+
text: JSON.stringify(structuredContent, null, 2),
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
structuredContent,
|
|
44
49
|
}
|
|
45
50
|
} catch (error) {
|
|
46
|
-
|
|
51
|
+
logger.error({ error }, '❌ Error listing worktrees')
|
|
47
52
|
throw error
|
|
48
53
|
}
|
|
49
54
|
}
|
|
@@ -83,7 +88,7 @@ const processWorktrees = async (
|
|
|
83
88
|
aheadBehind,
|
|
84
89
|
})
|
|
85
90
|
} catch (error) {
|
|
86
|
-
|
|
91
|
+
logger.warn({ error, branch }, `⚠️ Could not process worktree ${branch}`)
|
|
87
92
|
}
|
|
88
93
|
}
|
|
89
94
|
|
|
@@ -176,15 +181,15 @@ const getAheadBehind = async (worktreePath: string): Promise<string> => {
|
|
|
176
181
|
*/
|
|
177
182
|
const logResults = (worktrees: WorktreeInfo[]): void => {
|
|
178
183
|
if (worktrees.length === 0) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
184
|
+
logger.info('\n🌿 Git Worktrees')
|
|
185
|
+
logger.info('─'.repeat(80))
|
|
186
|
+
logger.info('ℹ️ No worktrees found')
|
|
187
|
+
logger.info('─'.repeat(80))
|
|
183
188
|
return
|
|
184
189
|
}
|
|
185
190
|
|
|
186
|
-
|
|
187
|
-
|
|
191
|
+
logger.info('\n🌿 Git Worktrees')
|
|
192
|
+
logger.info('═'.repeat(100))
|
|
188
193
|
|
|
189
194
|
// Separate releases and features
|
|
190
195
|
const releases = worktrees.filter((w) => w.type === 'release')
|
|
@@ -195,23 +200,23 @@ const logResults = (worktrees: WorktreeInfo[]): void => {
|
|
|
195
200
|
|
|
196
201
|
// Display features second
|
|
197
202
|
if (features.length > 0 && releases.length > 0) {
|
|
198
|
-
|
|
203
|
+
logger.info('')
|
|
199
204
|
}
|
|
200
205
|
|
|
201
206
|
displayWorktreeSection('✨ Features', features)
|
|
202
207
|
|
|
203
208
|
// Summary
|
|
204
209
|
const current = worktrees.find((w) => w.isCurrent)
|
|
205
|
-
|
|
206
|
-
|
|
210
|
+
logger.info(`\n${'═'.repeat(100)}`)
|
|
211
|
+
logger.info(
|
|
207
212
|
`📊 Summary: ${worktrees.length} total worktrees (${releases.length} releases, ${features.length} features)`,
|
|
208
213
|
)
|
|
209
214
|
|
|
210
215
|
if (current) {
|
|
211
|
-
|
|
216
|
+
logger.info(`📍 Currently on: ${current.branch}`)
|
|
212
217
|
}
|
|
213
218
|
|
|
214
|
-
|
|
219
|
+
logger.info('')
|
|
215
220
|
}
|
|
216
221
|
|
|
217
222
|
/**
|
|
@@ -220,14 +225,14 @@ const logResults = (worktrees: WorktreeInfo[]): void => {
|
|
|
220
225
|
const displayWorktreeSection = (sectionTitle: string, worktrees: WorktreeInfo[]): void => {
|
|
221
226
|
if (worktrees.length === 0) return
|
|
222
227
|
|
|
223
|
-
|
|
224
|
-
|
|
228
|
+
logger.info(`\n${sectionTitle}`)
|
|
229
|
+
logger.info('─'.repeat(50))
|
|
225
230
|
|
|
226
231
|
for (const [index, worktree] of worktrees.entries()) {
|
|
227
232
|
displayWorktree(worktree)
|
|
228
233
|
|
|
229
234
|
if (index < worktrees.length - 1) {
|
|
230
|
-
|
|
235
|
+
logger.info('')
|
|
231
236
|
}
|
|
232
237
|
}
|
|
233
238
|
}
|
|
@@ -245,18 +250,18 @@ const displayWorktree = (worktree: WorktreeInfo): void => {
|
|
|
245
250
|
// Branch name with color coding
|
|
246
251
|
const branchDisplay = `${typeIcon} ${worktree.branch}`
|
|
247
252
|
|
|
248
|
-
|
|
253
|
+
logger.info(`${currentIndicator} ${statusIndicator} ${branchDisplay}`)
|
|
249
254
|
|
|
250
255
|
// Commit and sync info
|
|
251
256
|
const syncInfo = worktree.aheadBehind !== 'unknown' ? ` | ${worktree.aheadBehind}` : ''
|
|
252
|
-
|
|
257
|
+
logger.info(` 📝 ${worktree.commit}${syncInfo}`)
|
|
253
258
|
|
|
254
259
|
// Last commit message
|
|
255
|
-
|
|
260
|
+
logger.info(` 💬 ${worktree.lastCommitMessage}`)
|
|
256
261
|
|
|
257
262
|
// Path (shortened for display)
|
|
258
263
|
const shortPath = worktree.path.split('/').slice(-2).join('/')
|
|
259
|
-
|
|
264
|
+
logger.info(` 📁 ${shortPath}`)
|
|
260
265
|
}
|
|
261
266
|
|
|
262
267
|
/**
|
|
@@ -274,3 +279,34 @@ const getStatusIndicator = (status: string): string => {
|
|
|
274
279
|
return '❓'
|
|
275
280
|
}
|
|
276
281
|
}
|
|
282
|
+
|
|
283
|
+
// MCP Tool Registration
|
|
284
|
+
const worktreesListSchema = z.object({})
|
|
285
|
+
|
|
286
|
+
const worktreesListOutputSchema = z.object({
|
|
287
|
+
worktrees: z
|
|
288
|
+
.array(
|
|
289
|
+
z.object({
|
|
290
|
+
branch: z.string(),
|
|
291
|
+
path: z.string(),
|
|
292
|
+
commit: z.string(),
|
|
293
|
+
isCurrent: z.boolean(),
|
|
294
|
+
type: z.enum(['release', 'feature']),
|
|
295
|
+
status: z.string(),
|
|
296
|
+
lastCommitMessage: z.string(),
|
|
297
|
+
aheadBehind: z.string(),
|
|
298
|
+
}),
|
|
299
|
+
)
|
|
300
|
+
.describe('List of all worktrees with details'),
|
|
301
|
+
totalCount: z.number().describe('Total number of worktrees'),
|
|
302
|
+
releaseCount: z.number().describe('Number of release worktrees'),
|
|
303
|
+
featureCount: z.number().describe('Number of feature worktrees'),
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
export const worktreesListMcpTool = {
|
|
307
|
+
name: 'worktrees-list',
|
|
308
|
+
description: 'List all git worktrees with detailed information',
|
|
309
|
+
inputSchema: worktreesListSchema,
|
|
310
|
+
outputSchema: worktreesListOutputSchema,
|
|
311
|
+
handler: worktreesList,
|
|
312
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { worktreesRemove } from './worktrees-remove'
|
|
1
|
+
export { worktreesRemove, worktreesRemoveMcpTool } from './worktrees-remove'
|