infra-kit 0.1.85 → 0.1.87

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.
Files changed (32) hide show
  1. package/.eslintcache +1 -1
  2. package/.turbo/turbo-eslint-check.log +4 -5
  3. package/.turbo/turbo-prettier-check.log +4 -5
  4. package/.turbo/turbo-prettier-fix.log +10 -0
  5. package/.turbo/turbo-test.log +14 -17
  6. package/.turbo/turbo-ts-check.log +4 -5
  7. package/dist/cli.js +26 -26
  8. package/dist/cli.js.map +4 -4
  9. package/dist/mcp.js +23 -23
  10. package/dist/mcp.js.map +4 -4
  11. package/package.json +3 -3
  12. package/src/commands/env-clear/env-clear.ts +2 -1
  13. package/src/commands/env-list/env-list.ts +2 -1
  14. package/src/commands/env-load/env-load.ts +5 -2
  15. package/src/commands/env-status/env-status.ts +2 -1
  16. package/src/commands/gh-merge-dev/gh-merge-dev.ts +8 -2
  17. package/src/commands/gh-release-deliver/gh-release-deliver.ts +3 -2
  18. package/src/commands/gh-release-deploy-all/gh-release-deploy-all.ts +13 -4
  19. package/src/commands/gh-release-deploy-selected/gh-release-deploy-selected.ts +18 -5
  20. package/src/commands/gh-release-list/gh-release-list.ts +2 -1
  21. package/src/commands/release-create/release-create.ts +3 -2
  22. package/src/commands/release-create-batch/release-create-batch.ts +5 -2
  23. package/src/commands/worktrees-add/worktrees-add.ts +26 -5
  24. package/src/commands/worktrees-list/worktrees-list.ts +2 -1
  25. package/src/commands/worktrees-remove/worktrees-remove.ts +14 -3
  26. package/src/commands/worktrees-sync/worktrees-sync.ts +2 -1
  27. package/src/entry/cli.ts +0 -18
  28. package/src/mcp/tools/index.ts +0 -2
  29. package/tsconfig.tsbuildinfo +1 -1
  30. package/.turbo/turbo-build.log +0 -11
  31. package/src/commands/gh-release-deploy-service/gh-release-deploy-service.ts +0 -193
  32. package/src/commands/gh-release-deploy-service/index.ts +0 -1
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "infra-kit",
3
3
  "type": "module",
4
- "version": "0.1.85",
4
+ "version": "0.1.87",
5
5
  "description": "infra-kit",
6
6
  "main": "dist/cli.js",
7
7
  "module": "dist/cli.js",
@@ -17,8 +17,8 @@
17
17
  "build": "pnpm run clean-artifacts && node ./scripts/build.js",
18
18
  "clean-artifacts": "rm -rf dist",
19
19
  "clean-cache": "rm -rf node_modules/.cache .eslintcache tsconfig.tsbuildinfo .turbo .swc",
20
- "prettier-fix": "pnpm exec prettier **/* --write --no-error-on-unmatched-pattern --log-level warn --ignore-path ../../.prettierignore",
21
- "prettier-check": "pnpm exec prettier **/* --check --no-error-on-unmatched-pattern --log-level warn --ignore-path ../../.prettierignore",
20
+ "prettier-fix": "pnpm exec prettier **/* --write --no-error-on-unmatched-pattern --log-level warn --ignore-path ../../../.prettierignore",
21
+ "prettier-check": "pnpm exec prettier **/* --check --no-error-on-unmatched-pattern --log-level warn --ignore-path ../../../.prettierignore",
22
22
  "eslint-check": "pnpm exec eslint --cache --quiet --report-unused-disable-directives ./src",
23
23
  "eslint-fix": "pnpm exec eslint --cache --quiet --report-unused-disable-directives ./src --fix",
24
24
  "ts-check": "tsc --noEmit",
@@ -60,6 +60,7 @@ export const envClear = async (): Promise<ToolsExecutionResult> => {
60
60
  fs.unlinkSync(envLoadPath)
61
61
 
62
62
  const structuredContent = {
63
+ filePath: clearFilePath,
63
64
  variableCount: varNames.length,
64
65
  unsetStatements: unsetLines,
65
66
  }
@@ -79,7 +80,7 @@ export const envClear = async (): Promise<ToolsExecutionResult> => {
79
80
  export const envClearMcpTool = {
80
81
  name: 'env-clear',
81
82
  description:
82
- 'Clear loaded env vars. Returns a file path that must be sourced (source <path>) to apply. The env-clear shell alias does this automatically.',
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 — returns the path to a script that must be sourced ("source <filePath>") for the unsets to take effect. The infra-kit shell wrapper auto-sources; direct MCP callers must handle sourcing themselves or surface filePath to the user. Errors if no env is currently loaded.',
83
84
  inputSchema: {},
84
85
  outputSchema: {
85
86
  filePath: z.string().describe('Path to the file that must be sourced to apply'),
@@ -40,7 +40,8 @@ export const envList = async (): Promise<ToolsExecutionResult> => {
40
40
  // MCP Tool Registration
41
41
  export const envListMcpTool = {
42
42
  name: 'env-list',
43
- description: 'List available Doppler configs for the detected project',
43
+ description:
44
+ 'List the environments the project is configured to support. Returns a static list defined in infra-kit constants (not a live fetch from Doppler) plus the Doppler project name auto-detected from the current directory. Read-only.',
44
45
  inputSchema: {},
45
46
  outputSchema: {
46
47
  project: z.string().describe('Detected Doppler project name'),
@@ -88,6 +88,7 @@ export const envLoad = async (args: EnvLoadArgs): Promise<ToolsExecutionResult>
88
88
  }).length
89
89
 
90
90
  const structuredContent = {
91
+ filePath: envFilePath,
91
92
  variableCount: varCount,
92
93
  project,
93
94
  config: selectedConfig,
@@ -108,9 +109,11 @@ export const envLoad = async (args: EnvLoadArgs): Promise<ToolsExecutionResult>
108
109
  export const envLoadMcpTool = {
109
110
  name: 'env-load',
110
111
  description:
111
- 'Load Doppler env vars for a config. Returns a file path that must be sourced (source <path>) to apply variables. The env-load shell alias does this automatically.',
112
+ 'Download the env vars for a Doppler config and write them to a temporary shell script. Does NOT mutate the calling process — returns the path to a script that must be sourced ("source <filePath>") for the vars to take effect. The infra-kit shell wrapper auto-sources; direct MCP callers must handle sourcing themselves or surface filePath to the user. "config" is required when invoked via MCP (the CLI interactive picker is unreachable without a TTY).',
112
113
  inputSchema: {
113
- config: z.string().describe('Environment config name to load (e.g. dev, arthur, renana)'),
114
+ config: z
115
+ .string()
116
+ .describe('Doppler config / environment name to load (e.g. "dev", "arthur", "renana"). Required for MCP calls.'),
114
117
  },
115
118
  outputSchema: {
116
119
  filePath: z.string().describe('Path to the file that must be sourced to apply variables'),
@@ -78,7 +78,8 @@ export const envStatus = async (): Promise<ToolsExecutionResult> => {
78
78
  // MCP Tool Registration
79
79
  export const envStatusMcpTool = {
80
80
  name: 'env-status',
81
- description: 'Show Doppler authentication status and detected project info',
81
+ description:
82
+ 'Report which Doppler project/config is currently loaded in the terminal session, when it was loaded, and how many variables are cached. Read-only — use env-load / env-clear to change the terminal session.',
82
83
  inputSchema: {},
83
84
  outputSchema: {
84
85
  sessionId: z.string().describe('Current terminal session ID'),
@@ -186,9 +186,15 @@ const mergeDev = async (branch: string): Promise<boolean> => {
186
186
  // MCP Tool Registration
187
187
  export const ghMergeDevMcpTool = {
188
188
  name: 'gh-merge-dev',
189
- description: 'Merge dev branch into selected release branches',
189
+ description:
190
+ 'Merge origin/dev into every open regular (non-hotfix) release branch and push the result. Mutates local git state and the remote release branches. When invoked via MCP, pass all=true — the branch picker is unreachable without a TTY, and the confirmation prompt is auto-skipped for MCP calls, so the caller is responsible for gating. Irreversible once pushed.',
190
191
  inputSchema: {
191
- all: z.boolean().describe('Merge dev into all release branches without prompting'),
192
+ all: z
193
+ .boolean()
194
+ .optional()
195
+ .describe(
196
+ 'Target every open regular release branch. Must be true for MCP calls (the interactive picker is unavailable without a TTY).',
197
+ ),
192
198
  },
193
199
  outputSchema: {
194
200
  successfulMerges: z.number().describe('Number of successful merges'),
@@ -162,9 +162,10 @@ export const ghReleaseDeliver = async (args: GhReleaseDeliverArgs): Promise<Tool
162
162
  // MCP Tool Registration
163
163
  export const ghReleaseDeliverMcpTool = {
164
164
  name: 'gh-release-deliver',
165
- description: 'Deliver a release branch to production',
165
+ description:
166
+ 'Deliver a release to production. For hotfixes: squash-merges the release branch to main and dispatches the deploy-all workflow. For regular releases: squash-merges to dev, opens an RC PR, merges dev into main, dispatches the deploy-all workflow, then syncs main back to dev. Also releases the matching Jira fix version if Jira is configured. Dispatches the deploy workflow fire-and-forget — the tool returns once the workflow is accepted by GitHub, not when the deployment finishes. Irreversible production operation: the confirmation prompt is auto-skipped for MCP calls, so the caller is responsible for gating. "version" is required when invoked via MCP (the picker is unreachable without a TTY).',
166
167
  inputSchema: {
167
- version: z.string().describe('Version to deliver to production (e.g., "1.2.5")'),
168
+ version: z.string().describe('Release version to deliver to production (e.g., "1.2.5"). Required for MCP calls.'),
168
169
  },
169
170
  outputSchema: {
170
171
  releaseBranch: z.string().describe('The release branch that was delivered'),
@@ -128,11 +128,20 @@ export const ghReleaseDeployAll = async (args: GhReleaseDeployAllArgs): Promise<
128
128
  // MCP Tool Registration
129
129
  export const ghReleaseDeployAllMcpTool = {
130
130
  name: 'gh-release-deploy-all',
131
- description: 'Deploy a release branch to a specified environment',
131
+ description:
132
+ 'Dispatch the deploy-all.yml GitHub Actions workflow to deploy every service from a release branch to the given environment. Fire-and-forget — returns once GitHub accepts the workflow_dispatch, NOT when the deployment finishes; watch the workflow run for completion status. Use gh-release-deploy-selected for a subset of services. Pass version="dev" to deploy from the dev branch instead of a release branch. Both "version" and "env" are required when invoked via MCP (interactive pickers are unavailable without a TTY).',
132
133
  inputSchema: {
133
- version: z.string().describe('Version to deploy (e.g., "1.2.5")'),
134
- env: z.string().describe('Environment to deploy to (e.g., "dev", "renana", "oriana")'),
135
- skipTerraform: z.boolean().optional().describe('Skip terraform deployment step'),
134
+ version: z
135
+ .string()
136
+ .describe(
137
+ 'Release version to deploy from (e.g. "1.2.5") — resolves to the release/vX.Y.Z branch. Pass "dev" to deploy from the dev branch instead. Required for MCP calls.',
138
+ ),
139
+ env: z
140
+ .string()
141
+ .describe(
142
+ 'Target environment name — must match an env configured for the project (e.g. "dev", "renana", "oriana"). Required for MCP calls.',
143
+ ),
144
+ skipTerraform: z.boolean().optional().describe('Skip the terraform deployment stage.'),
136
145
  },
137
146
  outputSchema: {
138
147
  releaseBranch: z.string().describe('The release branch that was deployed'),
@@ -211,12 +211,25 @@ const parseServicesFromWorkflow = async (): Promise<string[]> => {
211
211
  // MCP Tool Registration
212
212
  export const ghReleaseDeploySelectedMcpTool = {
213
213
  name: 'gh-release-deploy-selected',
214
- description: 'Deploy selected services from a release branch to a specified environment',
214
+ description:
215
+ 'Dispatch the deploy-selected-services.yml GitHub Actions workflow to deploy a chosen subset of services from a release branch to the given environment. Fire-and-forget — returns once GitHub accepts the workflow_dispatch, NOT when the deployment finishes; watch the workflow run for completion status. Service names are validated against the boolean inputs declared in the workflow. Use gh-release-deploy-all for every service. "version", "env", and "services" are all required when invoked via MCP (interactive pickers are unavailable without a TTY).',
215
216
  inputSchema: {
216
- version: z.string().describe('Version to deploy (e.g., "1.2.5")'),
217
- env: z.string().describe('Environment to deploy to (e.g., "dev", "renana", "oriana")'),
218
- services: z.array(z.string()).describe('List of services to deploy (e.g., ["client-be", "client-fe"])'),
219
- skipTerraform: z.boolean().optional().describe('Skip terraform deployment step'),
217
+ version: z
218
+ .string()
219
+ .describe(
220
+ 'Release version to deploy from (e.g. "1.2.5") — resolves to the release/vX.Y.Z branch. Pass "dev" to deploy from the dev branch instead. Required for MCP calls.',
221
+ ),
222
+ env: z
223
+ .string()
224
+ .describe(
225
+ 'Target environment name — must match an env configured for the project (e.g. "dev", "renana", "oriana"). Required for MCP calls.',
226
+ ),
227
+ services: z
228
+ .array(z.string())
229
+ .describe(
230
+ 'Service names to deploy. Each must match a boolean input declared in .github/workflows/deploy-selected-services.yml (e.g. "client-be", "client-fe"). Required for MCP calls.',
231
+ ),
232
+ skipTerraform: z.boolean().optional().describe('Skip the terraform deployment stage.'),
220
233
  },
221
234
  outputSchema: {
222
235
  releaseBranch: z.string().describe('The release branch that was deployed'),
@@ -65,7 +65,8 @@ export const ghReleaseList = async (): Promise<ToolsExecutionResult> => {
65
65
  // MCP Tool Registration
66
66
  export const ghReleaseListMcpTool = {
67
67
  name: 'gh-release-list',
68
- description: 'List all open release branches',
68
+ description:
69
+ 'List every open release PR with its version, type (regular / hotfix), and associated Jira fix-version description. Read-only; sourced from GitHub and Jira.',
69
70
  inputSchema: {},
70
71
  outputSchema: {
71
72
  releases: z
@@ -160,9 +160,10 @@ export const releaseCreate = async (args: ReleaseCreateArgs): Promise<ToolsExecu
160
160
  // MCP Tool Registration
161
161
  export const releaseCreateMcpTool = {
162
162
  name: 'release-create',
163
- description: 'Create a single release branch for specified version with Jira version creation',
163
+ description:
164
+ 'Create a new release: cuts the release branch off the appropriate base (dev for regular releases, main for hotfixes), opens a GitHub release PR, creates the matching Jira fix version, and optionally checks out to the new branch. Confirmation is auto-skipped for MCP calls, so the caller is responsible for gating. "version" is required when invoked via MCP (the interactive input prompt is unreachable without a TTY); "type" / "description" / "checkout" default to regular / empty / true when omitted.',
164
165
  inputSchema: {
165
- version: z.string().describe('Version to create (e.g., "1.2.5")'),
166
+ version: z.string().describe('Version to create (e.g., "1.2.5"). Required for MCP calls.'),
166
167
  description: z.string().optional().describe('Optional description for the Jira version'),
167
168
  type: z
168
169
  .enum(['regular', 'hotfix'])
@@ -158,9 +158,12 @@ export const releaseCreateBatch = async (args: ReleaseCreateBatchArgs): Promise<
158
158
  // MCP Tool Registration
159
159
  export const releaseCreateBatchMcpTool = {
160
160
  name: 'release-create-batch',
161
- description: 'Create multiple release branches for specified versions with Jira version creation (batch operation)',
161
+ description:
162
+ 'Create several releases in one pass: for each comma-separated version in "versions", cuts the release branch off the appropriate base (dev for regular releases, main for hotfixes), opens a GitHub PR, and creates the Jira fix version. Continues on per-version failure and reports which versions succeeded and which failed. Confirmation is auto-skipped for MCP calls, so the caller is responsible for gating. "versions" is required when invoked via MCP (the interactive input prompt is unreachable without a TTY). Use release-create for a single version with optional checkout.',
162
163
  inputSchema: {
163
- versions: z.string().describe('Comma-separated list of versions to create (e.g., "1.2.5, 1.2.6")'),
164
+ versions: z
165
+ .string()
166
+ .describe('Comma-separated list of versions to create (e.g., "1.2.5, 1.2.6"). Required for MCP calls.'),
164
167
  type: z
165
168
  .enum(['regular', 'hotfix'])
166
169
  .optional()
@@ -268,12 +268,33 @@ const logResults = (created: string[]): void => {
268
268
  // MCP Tool Registration
269
269
  export const worktreesAddMcpTool = {
270
270
  name: 'worktrees-add',
271
- description: 'Create git worktrees for selected release branches',
271
+ description:
272
+ 'Create local git worktrees for release branches under the worktrees directory and run "pnpm install" in each. Mutates the local filesystem. When invoked via MCP, pass either "versions" (comma-separated) or all=true — the branch picker and "open in Cursor / GitHub Desktop" follow-up prompts are unreachable without a TTY, and the CLI confirmation is auto-skipped for MCP calls.',
272
273
  inputSchema: {
273
- all: z.boolean().describe('Add git worktrees for all release branches without prompting'),
274
- versions: z.string().optional().describe('Specify versions by comma, e.g. 1.2.5, 1.2.6'),
275
- cursor: z.boolean().optional().describe('Open created git worktrees in Cursor'),
276
- githubDesktop: z.boolean().optional().describe('Open created git worktrees in GitHub Desktop'),
274
+ all: z
275
+ .boolean()
276
+ .optional()
277
+ .describe(
278
+ 'Add worktrees for every open release branch. Either "all" or "versions" must be provided for MCP calls (the interactive picker is unavailable without a TTY). Ignored if "versions" is provided.',
279
+ ),
280
+ versions: z
281
+ .string()
282
+ .optional()
283
+ .describe(
284
+ 'Comma-separated release versions to target (e.g. "1.2.5, 1.2.6"). Either "versions" or all=true must be provided for MCP calls. Overrides "all" when set.',
285
+ ),
286
+ cursor: z
287
+ .boolean()
288
+ .optional()
289
+ .describe(
290
+ 'Open each created worktree in Cursor. Defaults to false in MCP mode (the follow-up prompt is not shown).',
291
+ ),
292
+ githubDesktop: z
293
+ .boolean()
294
+ .optional()
295
+ .describe(
296
+ 'Open each created worktree in GitHub Desktop. Defaults to false in MCP mode (the follow-up prompt is not shown).',
297
+ ),
277
298
  },
278
299
  outputSchema: {
279
300
  createdWorktrees: z.array(z.string()).describe('List of created git worktree branches'),
@@ -83,7 +83,8 @@ export const worktreesList = async (): Promise<ToolsExecutionResult> => {
83
83
  // MCP Tool Registration
84
84
  export const worktreesListMcpTool = {
85
85
  name: 'worktrees-list',
86
- description: 'List all git worktrees with detailed information',
86
+ description:
87
+ 'List existing release-branch worktrees with version, release type (regular / hotfix), and Jira fix-version description. Read-only.',
87
88
  inputSchema: {},
88
89
  outputSchema: {
89
90
  worktrees: z
@@ -188,10 +188,21 @@ const logResults = (removed: string[]): void => {
188
188
  // MCP Tool Registration
189
189
  export const worktreesRemoveMcpTool = {
190
190
  name: 'worktrees-remove',
191
- description: 'Remove selected worktrees',
191
+ description:
192
+ 'Remove local git worktrees for release branches. When everything is removed, also runs "git worktree prune" and deletes the worktrees directory. When invoked via MCP, pass either "versions" (comma-separated) or all=true — the branch picker is unreachable without a TTY, and the CLI confirmation is auto-skipped for MCP calls, so the caller is responsible for gating.',
192
193
  inputSchema: {
193
- all: z.boolean().describe('Remove all git worktrees without prompting'),
194
- versions: z.string().optional().describe('Specify versions by comma, e.g. 1.2.5, 1.2.6'),
194
+ all: z
195
+ .boolean()
196
+ .optional()
197
+ .describe(
198
+ 'Remove every existing worktree. Either "all" or "versions" must be provided for MCP calls (the interactive picker is unavailable without a TTY). Ignored if "versions" is provided.',
199
+ ),
200
+ versions: z
201
+ .string()
202
+ .optional()
203
+ .describe(
204
+ 'Comma-separated release versions to target (e.g. "1.2.5, 1.2.6"). Either "versions" or all=true must be provided for MCP calls. Overrides "all" when set.',
205
+ ),
195
206
  },
196
207
  outputSchema: {
197
208
  removedWorktrees: z.array(z.string()).describe('List of removed git worktree branches'),
@@ -145,7 +145,8 @@ const logResults = (removed: string[]): void => {
145
145
  // MCP Tool Registration
146
146
  export const worktreesSyncMcpTool = {
147
147
  name: 'worktrees-sync',
148
- description: 'Synchronize worktrees with active release branches',
148
+ description:
149
+ 'Remove worktrees whose release PR is no longer open (stale cleanup). Only removes — never creates; use worktrees-add to create worktrees for new releases. The CLI confirmation is auto-skipped for MCP calls, so the caller is responsible for gating.',
149
150
  inputSchema: {},
150
151
  outputSchema: {
151
152
  removedWorktrees: z.array(z.string()).describe('List of removed worktree branches'),
package/src/entry/cli.ts CHANGED
@@ -11,7 +11,6 @@ import { ghMergeDev } from 'src/commands/gh-merge-dev'
11
11
  import { ghReleaseDeliver } from 'src/commands/gh-release-deliver'
12
12
  import { ghReleaseDeployAll } from 'src/commands/gh-release-deploy-all'
13
13
  import { ghReleaseDeploySelected } from 'src/commands/gh-release-deploy-selected'
14
- import { ghReleaseDeployService } from 'src/commands/gh-release-deploy-service'
15
14
  import { ghReleaseList } from 'src/commands/gh-release-list'
16
15
  import { init } from 'src/commands/init'
17
16
  import { releaseCreate } from 'src/commands/release-create'
@@ -81,22 +80,6 @@ program
81
80
  await ghReleaseDeployAll({ version: options.version, env: options.env, skipTerraform: options.skipTerraform })
82
81
  })
83
82
 
84
- program
85
- .command('release-deploy-service')
86
- .description('Deploy specific service in release branch to any environment')
87
- .option('-v, --version <version>', 'Specify the version to deploy, e.g. 1.2.5')
88
- .option('-e, --env <env>', 'Specify the environment to deploy to, e.g. dev')
89
- .option('-s, --service <service>', 'Specify the service to deploy, e.g. client-be')
90
- .option('--skip-terraform', 'Skip terraform deployment step')
91
- .action(async (options) => {
92
- await ghReleaseDeployService({
93
- version: options.version,
94
- env: options.env,
95
- service: options.service,
96
- skipTerraform: options.skipTerraform,
97
- })
98
- })
99
-
100
83
  program
101
84
  .command('release-deploy-selected')
102
85
  .description('Deploy selected services from release branch to any environment')
@@ -217,7 +200,6 @@ if (process.argv.length <= 2) {
217
200
  'release-create',
218
201
  'release-create-batch',
219
202
  'release-deploy-all',
220
- 'release-deploy-service',
221
203
  'release-deploy-selected',
222
204
  'release-deliver',
223
205
  ]
@@ -8,7 +8,6 @@ import { ghMergeDevMcpTool } from 'src/commands/gh-merge-dev'
8
8
  import { ghReleaseDeliverMcpTool } from 'src/commands/gh-release-deliver'
9
9
  import { ghReleaseDeployAllMcpTool } from 'src/commands/gh-release-deploy-all'
10
10
  import { ghReleaseDeploySelectedMcpTool } from 'src/commands/gh-release-deploy-selected'
11
- import { ghReleaseDeployServiceMcpTool } from 'src/commands/gh-release-deploy-service'
12
11
  import { ghReleaseListMcpTool } from 'src/commands/gh-release-list'
13
12
  import { releaseCreateMcpTool } from 'src/commands/release-create'
14
13
  import { releaseCreateBatchMcpTool } from 'src/commands/release-create-batch'
@@ -29,7 +28,6 @@ const tools = [
29
28
  ghReleaseDeliverMcpTool,
30
29
  ghReleaseDeployAllMcpTool,
31
30
  ghReleaseDeploySelectedMcpTool,
32
- ghReleaseDeployServiceMcpTool,
33
31
  ghReleaseListMcpTool,
34
32
  worktreesAddMcpTool,
35
33
  worktreesListMcpTool,