infra-kit 0.1.99 → 0.1.100
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/.eslintcache +1 -1
- package/.omc/state/agent-replay-d367c3be-9c2a-48e7-bcea-b45861af568c.jsonl +2 -0
- package/.omc/state/agent-replay-f2846d8f-974c-486c-b16f-4bdaa28ca45f.jsonl +1 -0
- package/.omc/state/last-tool-error.json +7 -0
- package/.omc/state/subagent-tracking.json +7 -0
- package/.turbo/turbo-eslint-check.log +1 -4
- package/.turbo/turbo-eslint-fix.log +1 -0
- package/.turbo/turbo-prettier-check.log +1 -4
- package/.turbo/turbo-prettier-fix.log +1 -10
- package/.turbo/turbo-test.log +5 -11
- package/.turbo/turbo-ts-check.log +1 -4
- package/dist/cli.js +45 -36
- package/dist/cli.js.map +4 -4
- package/dist/mcp.js +42 -34
- package/dist/mcp.js.map +4 -4
- package/package.json +11 -11
- package/src/commands/doctor/doctor.ts +62 -12
- package/src/commands/env-clear/env-clear.ts +5 -10
- package/src/commands/env-list/env-list.ts +5 -10
- package/src/commands/env-load/env-load.ts +5 -10
- package/src/commands/env-status/env-status.ts +5 -10
- package/src/commands/gh-merge-dev/gh-merge-dev.ts +17 -18
- package/src/commands/gh-release-deliver/gh-release-deliver.ts +290 -89
- package/src/commands/gh-release-deploy-all/gh-release-deploy-all.ts +15 -14
- package/src/commands/gh-release-deploy-selected/gh-release-deploy-selected.ts +30 -23
- package/src/commands/gh-release-list/gh-release-list.ts +5 -10
- package/src/commands/release-create/release-create.ts +22 -18
- package/src/commands/release-desc-edit/index.ts +1 -0
- package/src/commands/release-desc-edit/release-desc-edit.ts +207 -0
- package/src/commands/version/version.ts +5 -10
- package/src/commands/worktrees-add/worktrees-add.ts +18 -14
- package/src/commands/worktrees-list/worktrees-list.ts +6 -11
- package/src/commands/worktrees-open/worktrees-open.ts +10 -6
- package/src/commands/worktrees-remove/worktrees-remove.ts +18 -14
- package/src/commands/worktrees-sync/worktrees-sync.ts +17 -12
- package/src/entry/cli.ts +16 -0
- package/src/integrations/gh/gh-release-prs/gh-release-prs.ts +21 -0
- package/src/integrations/gh/gh-release-prs/index.ts +1 -1
- package/src/integrations/gh/index.ts +1 -1
- package/src/integrations/jira/api.ts +8 -17
- package/src/integrations/jira/index.ts +2 -0
- package/src/lib/errors/__tests__/operation-error.test.ts +62 -0
- package/src/lib/errors/format-zx-error.ts +54 -0
- package/src/lib/errors/operation-error.ts +80 -0
- package/src/mcp/tools/index.ts +2 -0
- package/src/types.ts +56 -2
- package/tsconfig.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "infra-kit",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.100",
|
|
5
5
|
"description": "infra-kit",
|
|
6
6
|
"main": "dist/cli.js",
|
|
7
7
|
"module": "dist/cli.js",
|
|
@@ -17,27 +17,27 @@
|
|
|
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
|
|
21
|
-
"prettier-check": "pnpm exec prettier **/* --check --no-error-on-unmatched-pattern --log-level
|
|
20
|
+
"prettier-fix": "pnpm exec prettier **/* --write --no-error-on-unmatched-pattern --log-level silent --ignore-path ../../../.prettierignore",
|
|
21
|
+
"prettier-check": "pnpm exec prettier **/* --check --no-error-on-unmatched-pattern --log-level silent --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",
|
|
25
|
-
"test": "pnpm exec vitest run --reporter=
|
|
26
|
-
"test-watch": "pnpm exec vitest --watch",
|
|
27
|
-
"test-ui": "pnpm exec vitest --ui",
|
|
28
|
-
"test-report": "pnpm exec vitest run --coverage",
|
|
25
|
+
"test": "pnpm exec vitest run --reporter=minimal",
|
|
26
|
+
"test-watch": "pnpm exec vitest --watch --silent passed-only",
|
|
27
|
+
"test-ui": "pnpm exec vitest --ui --silent passed-only",
|
|
28
|
+
"test-report": "pnpm exec vitest run --coverage --silent passed-only",
|
|
29
29
|
"qa": "pnpm run prettier-check && pnpm run eslint-check && pnpm run ts-check && pnpm run test && echo ✅ Success",
|
|
30
30
|
"fix": "pnpm run prettier-fix && pnpm run eslint-fix && pnpm run qa"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@inquirer/checkbox": "
|
|
34
|
-
"@inquirer/confirm": "
|
|
35
|
-
"@inquirer/select": "
|
|
33
|
+
"@inquirer/checkbox": "catalog:",
|
|
34
|
+
"@inquirer/confirm": "catalog:",
|
|
35
|
+
"@inquirer/select": "catalog:",
|
|
36
36
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
37
37
|
"commander": "^14.0.3",
|
|
38
38
|
"pino": "^10.3.1",
|
|
39
39
|
"pino-pretty": "^13.1.3",
|
|
40
|
-
"yaml": "
|
|
40
|
+
"yaml": "catalog:",
|
|
41
41
|
"zod": "^3.25.76",
|
|
42
42
|
"zx": "^8.8.5"
|
|
43
43
|
},
|
|
@@ -8,7 +8,7 @@ import { MARKER_END, MARKER_START, buildShellBlock } from 'src/commands/init/ini
|
|
|
8
8
|
import { getProjectRoot } from 'src/lib/git-utils/git-utils'
|
|
9
9
|
import { getInfraKitConfig, getInfraKitConfigPaths, resetInfraKitConfigCache } from 'src/lib/infra-kit-config'
|
|
10
10
|
import { logger } from 'src/lib/logger'
|
|
11
|
-
import
|
|
11
|
+
import { defineMcpTool, textContent } from 'src/types'
|
|
12
12
|
|
|
13
13
|
interface CheckResult {
|
|
14
14
|
name: string
|
|
@@ -148,10 +148,58 @@ const checkUserOverridePath = async (): Promise<CheckResult> => {
|
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
+
const RTK_REQUIRED_INDEXES = [1, 2, 3, 5, 7] as const
|
|
152
|
+
|
|
153
|
+
const checkRtkConfigured = async (): Promise<CheckResult> => {
|
|
154
|
+
const name = 'rtk configured'
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
const result = await $`rtk init --show`
|
|
158
|
+
const statusLines = result.stdout
|
|
159
|
+
.split('\n')
|
|
160
|
+
.map((l) => {
|
|
161
|
+
return l.trim()
|
|
162
|
+
})
|
|
163
|
+
.filter((l) => {
|
|
164
|
+
return l.startsWith('[ok]') || l.startsWith('[--]')
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
const failed: number[] = []
|
|
168
|
+
|
|
169
|
+
for (const idx of RTK_REQUIRED_INDEXES) {
|
|
170
|
+
const line = statusLines[idx - 1]
|
|
171
|
+
|
|
172
|
+
if (!line || !line.startsWith('[ok]')) {
|
|
173
|
+
failed.push(idx)
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (failed.length > 0) {
|
|
178
|
+
return {
|
|
179
|
+
name,
|
|
180
|
+
status: 'fail',
|
|
181
|
+
message: `rtk setup incomplete (items ${failed.join(', ')} not [ok]). Run: rtk init -g --auto-patch`,
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
name,
|
|
187
|
+
status: 'pass',
|
|
188
|
+
message: 'rtk hook, RTK.md, global CLAUDE.md, settings.json, and Cursor hook are configured',
|
|
189
|
+
}
|
|
190
|
+
} catch (err) {
|
|
191
|
+
return {
|
|
192
|
+
name,
|
|
193
|
+
status: 'fail',
|
|
194
|
+
message: `Failed to run 'rtk init --show': ${(err as Error).message}`,
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
151
199
|
/**
|
|
152
|
-
* Check installation and authentication status of gh, doppler, and
|
|
200
|
+
* Check installation and authentication status of gh, doppler, aws, and rtk CLIs
|
|
153
201
|
*/
|
|
154
|
-
export const doctor = async ()
|
|
202
|
+
export const doctor = async () => {
|
|
155
203
|
const checks: CheckResult[] = await Promise.all([
|
|
156
204
|
checkCommand(
|
|
157
205
|
'gh installed',
|
|
@@ -190,6 +238,13 @@ export const doctor = async (): Promise<ToolsExecutionResult> => {
|
|
|
190
238
|
// 'AWS CLI is authenticated',
|
|
191
239
|
// 'AWS CLI is not authenticated. Run: aws configure (or aws sso login)',
|
|
192
240
|
// ),
|
|
241
|
+
checkCommand(
|
|
242
|
+
'rtk installed',
|
|
243
|
+
['rtk', '--version'],
|
|
244
|
+
'RTK is installed',
|
|
245
|
+
'RTK is not installed. Install from: https://github.com/rtk-ai/rtk',
|
|
246
|
+
),
|
|
247
|
+
checkRtkConfigured(),
|
|
193
248
|
Promise.resolve(checkZshrcInitialized()),
|
|
194
249
|
checkPnpmWorkspaceVirtualStore(),
|
|
195
250
|
checkInfraKitConfigValid(),
|
|
@@ -214,20 +269,15 @@ export const doctor = async (): Promise<ToolsExecutionResult> => {
|
|
|
214
269
|
}
|
|
215
270
|
|
|
216
271
|
return {
|
|
217
|
-
content:
|
|
218
|
-
{
|
|
219
|
-
type: 'text',
|
|
220
|
-
text: JSON.stringify(structuredContent, null, 2),
|
|
221
|
-
},
|
|
222
|
-
],
|
|
272
|
+
content: textContent(JSON.stringify(structuredContent, null, 2)),
|
|
223
273
|
structuredContent,
|
|
224
274
|
}
|
|
225
275
|
}
|
|
226
276
|
|
|
227
277
|
// MCP Tool Registration
|
|
228
|
-
export const doctorMcpTool = {
|
|
278
|
+
export const doctorMcpTool = defineMcpTool({
|
|
229
279
|
name: 'doctor',
|
|
230
|
-
description: 'Check installation and authentication status of gh, doppler, and
|
|
280
|
+
description: 'Check installation and authentication status of gh, doppler, aws, and rtk CLIs',
|
|
231
281
|
inputSchema: {},
|
|
232
282
|
outputSchema: {
|
|
233
283
|
checks: z
|
|
@@ -242,4 +292,4 @@ export const doctorMcpTool = {
|
|
|
242
292
|
allPassed: z.boolean().describe('Whether all checks passed'),
|
|
243
293
|
},
|
|
244
294
|
handler: doctor,
|
|
245
|
-
}
|
|
295
|
+
})
|
|
@@ -13,14 +13,14 @@ import {
|
|
|
13
13
|
getSessionCacheDir,
|
|
14
14
|
parseVarNamesFromEnvFile,
|
|
15
15
|
} from 'src/lib/constants'
|
|
16
|
-
import
|
|
16
|
+
import { defineMcpTool, textContent } from 'src/types'
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Clear loaded env vars. Prints a file path to stdout that must be sourced to apply.
|
|
20
20
|
* The env-clear shell alias does this automatically. Throws when no env is loaded
|
|
21
21
|
* so CLI callers exit non-zero and MCP callers receive a structured tool error.
|
|
22
22
|
*/
|
|
23
|
-
export const envClear = async ()
|
|
23
|
+
export const envClear = async () => {
|
|
24
24
|
const cacheDir = getSessionCacheDir()
|
|
25
25
|
const envLoadPath = path.join(cacheDir, ENV_LOAD_FILE)
|
|
26
26
|
|
|
@@ -58,18 +58,13 @@ export const envClear = async (): Promise<ToolsExecutionResult> => {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
return {
|
|
61
|
-
content:
|
|
62
|
-
{
|
|
63
|
-
type: 'text',
|
|
64
|
-
text: JSON.stringify(structuredContent, null, 2),
|
|
65
|
-
},
|
|
66
|
-
],
|
|
61
|
+
content: textContent(JSON.stringify(structuredContent, null, 2)),
|
|
67
62
|
structuredContent,
|
|
68
63
|
}
|
|
69
64
|
}
|
|
70
65
|
|
|
71
66
|
// MCP Tool Registration
|
|
72
|
-
export const envClearMcpTool = {
|
|
67
|
+
export const envClearMcpTool = defineMcpTool({
|
|
73
68
|
name: 'env-clear',
|
|
74
69
|
description:
|
|
75
70
|
'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. When `infra-kit init` has installed the zsh shell integration, the user\'s terminal auto-sources the unset script on its next prompt (precmd hook) — so calling this via MCP will clear the vars in the shell that launched Claude Code automatically. Other callers must source "<filePath>" themselves or surface it to the user. Errors if no env is currently loaded.',
|
|
@@ -80,4 +75,4 @@ export const envClearMcpTool = {
|
|
|
80
75
|
unsetStatements: z.array(z.string()).describe('Unset statements generated'),
|
|
81
76
|
},
|
|
82
77
|
handler: envClear,
|
|
83
|
-
}
|
|
78
|
+
})
|
|
@@ -3,7 +3,7 @@ import { z } from 'zod/v4'
|
|
|
3
3
|
import { getDopplerProject } from 'src/integrations/doppler/doppler-project'
|
|
4
4
|
import { getInfraKitConfig } from 'src/lib/infra-kit-config'
|
|
5
5
|
import { logger } from 'src/lib/logger'
|
|
6
|
-
import
|
|
6
|
+
import { defineMcpTool, textContent } from 'src/types'
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* List available Doppler configs for the detected project.
|
|
@@ -12,7 +12,7 @@ import type { ToolsExecutionResult } from 'src/types'
|
|
|
12
12
|
* do not run validateDopplerCliAndAuth here — users listing envs often do so
|
|
13
13
|
* before `doppler login`, and a spurious auth error would be misleading.
|
|
14
14
|
*/
|
|
15
|
-
export const envList = async ()
|
|
15
|
+
export const envList = async () => {
|
|
16
16
|
const project = await getDopplerProject()
|
|
17
17
|
const { environments } = await getInfraKitConfig()
|
|
18
18
|
|
|
@@ -29,18 +29,13 @@ export const envList = async (): Promise<ToolsExecutionResult> => {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
return {
|
|
32
|
-
content:
|
|
33
|
-
{
|
|
34
|
-
type: 'text',
|
|
35
|
-
text: JSON.stringify(structuredContent, null, 2),
|
|
36
|
-
},
|
|
37
|
-
],
|
|
32
|
+
content: textContent(JSON.stringify(structuredContent, null, 2)),
|
|
38
33
|
structuredContent,
|
|
39
34
|
}
|
|
40
35
|
}
|
|
41
36
|
|
|
42
37
|
// MCP Tool Registration
|
|
43
|
-
export const envListMcpTool = {
|
|
38
|
+
export const envListMcpTool = defineMcpTool({
|
|
44
39
|
name: 'env-list',
|
|
45
40
|
description:
|
|
46
41
|
'List the environments the project is configured to support. Returns the `environments` list declared in infra-kit.yml at the project root (not a live fetch from Doppler) plus the Doppler project name resolved from the same file. Read-only.',
|
|
@@ -50,4 +45,4 @@ export const envListMcpTool = {
|
|
|
50
45
|
configs: z.array(z.string()).describe('Available environment configs'),
|
|
51
46
|
},
|
|
52
47
|
handler: envList,
|
|
53
|
-
}
|
|
48
|
+
})
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
getSessionCacheDir,
|
|
20
20
|
} from 'src/lib/constants'
|
|
21
21
|
import { getInfraKitConfig } from 'src/lib/infra-kit-config'
|
|
22
|
-
import
|
|
22
|
+
import { defineMcpTool, textContent } from 'src/types'
|
|
23
23
|
|
|
24
24
|
interface EnvLoadArgs {
|
|
25
25
|
config?: string
|
|
@@ -28,7 +28,7 @@ interface EnvLoadArgs {
|
|
|
28
28
|
/**
|
|
29
29
|
* Load environment variables from Doppler for the given config
|
|
30
30
|
*/
|
|
31
|
-
export const envLoad = async (args: EnvLoadArgs)
|
|
31
|
+
export const envLoad = async (args: EnvLoadArgs) => {
|
|
32
32
|
await validateDopplerCliAndAuth()
|
|
33
33
|
|
|
34
34
|
const { config } = args
|
|
@@ -98,12 +98,7 @@ export const envLoad = async (args: EnvLoadArgs): Promise<ToolsExecutionResult>
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
return {
|
|
101
|
-
content:
|
|
102
|
-
{
|
|
103
|
-
type: 'text',
|
|
104
|
-
text: JSON.stringify(structuredContent, null, 2),
|
|
105
|
-
},
|
|
106
|
-
],
|
|
101
|
+
content: textContent(JSON.stringify(structuredContent, null, 2)),
|
|
107
102
|
structuredContent,
|
|
108
103
|
}
|
|
109
104
|
}
|
|
@@ -189,7 +184,7 @@ export const assertValidEnvContent = (content: string): void => {
|
|
|
189
184
|
}
|
|
190
185
|
|
|
191
186
|
// MCP Tool Registration
|
|
192
|
-
export const envLoadMcpTool = {
|
|
187
|
+
export const envLoadMcpTool = defineMcpTool({
|
|
193
188
|
name: 'env-load',
|
|
194
189
|
description:
|
|
195
190
|
'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).',
|
|
@@ -205,4 +200,4 @@ export const envLoadMcpTool = {
|
|
|
205
200
|
config: z.string().describe('Doppler config name'),
|
|
206
201
|
},
|
|
207
202
|
handler: envLoad,
|
|
208
|
-
}
|
|
203
|
+
})
|
|
@@ -13,12 +13,12 @@ import {
|
|
|
13
13
|
parseVarNamesFromEnvFile,
|
|
14
14
|
} from 'src/lib/constants'
|
|
15
15
|
import { logger } from 'src/lib/logger'
|
|
16
|
-
import
|
|
16
|
+
import { defineMcpTool, textContent } from 'src/types'
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Show Doppler authentication status and detected project info
|
|
20
20
|
*/
|
|
21
|
-
export const envStatus = async ()
|
|
21
|
+
export const envStatus = async () => {
|
|
22
22
|
await validateDopplerCliAndAuth()
|
|
23
23
|
|
|
24
24
|
logger.info('Environment session status:')
|
|
@@ -73,18 +73,13 @@ export const envStatus = async (): Promise<ToolsExecutionResult> => {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
return {
|
|
76
|
-
content:
|
|
77
|
-
{
|
|
78
|
-
type: 'text',
|
|
79
|
-
text: JSON.stringify(structuredContent, null, 2),
|
|
80
|
-
},
|
|
81
|
-
],
|
|
76
|
+
content: textContent(JSON.stringify(structuredContent, null, 2)),
|
|
82
77
|
structuredContent,
|
|
83
78
|
}
|
|
84
79
|
}
|
|
85
80
|
|
|
86
81
|
// MCP Tool Registration
|
|
87
|
-
export const envStatusMcpTool = {
|
|
82
|
+
export const envStatusMcpTool = defineMcpTool({
|
|
88
83
|
name: 'env-status',
|
|
89
84
|
description:
|
|
90
85
|
'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.',
|
|
@@ -98,4 +93,4 @@ export const envStatusMcpTool = {
|
|
|
98
93
|
sessionLoadedAt: z.string().nullable().describe('ISO 8601 timestamp of when the env was loaded'),
|
|
99
94
|
},
|
|
100
95
|
handler: envStatus,
|
|
101
|
-
}
|
|
96
|
+
})
|
|
@@ -7,18 +7,20 @@ import { $ } from 'zx'
|
|
|
7
7
|
|
|
8
8
|
import { getReleasePRsWithInfo } from 'src/integrations/gh'
|
|
9
9
|
import { commandEcho } from 'src/lib/command-echo'
|
|
10
|
+
import { OperationError } from 'src/lib/errors/operation-error'
|
|
10
11
|
import { logger } from 'src/lib/logger'
|
|
11
12
|
import { detectReleaseType, formatBranchChoices, getJiraDescriptions } from 'src/lib/release-utils'
|
|
12
|
-
import
|
|
13
|
+
import { defineMcpTool, textContent } from 'src/types'
|
|
14
|
+
import type { RequiredConfirmedOptionArg } from 'src/types'
|
|
13
15
|
|
|
14
16
|
interface GhMergeDevArgs extends RequiredConfirmedOptionArg {
|
|
15
|
-
all
|
|
17
|
+
all?: boolean
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
/**
|
|
19
21
|
* Merge dev into every release branch
|
|
20
22
|
*/
|
|
21
|
-
export const ghMergeDev = async (args: GhMergeDevArgs)
|
|
23
|
+
export const ghMergeDev = async (args: GhMergeDevArgs) => {
|
|
22
24
|
const { all, confirmedCommand } = args
|
|
23
25
|
|
|
24
26
|
commandEcho.start('merge-dev')
|
|
@@ -39,12 +41,9 @@ export const ghMergeDev = async (args: GhMergeDevArgs): Promise<ToolsExecutionRe
|
|
|
39
41
|
commandEcho.print()
|
|
40
42
|
|
|
41
43
|
return {
|
|
42
|
-
content:
|
|
43
|
-
{
|
|
44
|
-
|
|
45
|
-
text: JSON.stringify({ successfulMerges: 0, failedMerges: 0, failedBranches: [], totalBranches: 0 }, null, 2),
|
|
46
|
-
},
|
|
47
|
-
],
|
|
44
|
+
content: textContent(
|
|
45
|
+
JSON.stringify({ successfulMerges: 0, failedMerges: 0, failedBranches: [], totalBranches: 0 }, null, 2),
|
|
46
|
+
),
|
|
48
47
|
structuredContent: { successfulMerges: 0, failedMerges: 0, failedBranches: [], totalBranches: 0 },
|
|
49
48
|
}
|
|
50
49
|
}
|
|
@@ -149,12 +148,7 @@ export const ghMergeDev = async (args: GhMergeDevArgs): Promise<ToolsExecutionRe
|
|
|
149
148
|
}
|
|
150
149
|
|
|
151
150
|
return {
|
|
152
|
-
content:
|
|
153
|
-
{
|
|
154
|
-
type: 'text',
|
|
155
|
-
text: JSON.stringify(structuredContent, null, 2),
|
|
156
|
-
},
|
|
157
|
-
],
|
|
151
|
+
content: textContent(JSON.stringify(structuredContent, null, 2)),
|
|
158
152
|
structuredContent,
|
|
159
153
|
}
|
|
160
154
|
}
|
|
@@ -175,7 +169,12 @@ const mergeDev = async (branch: string): Promise<boolean> => {
|
|
|
175
169
|
|
|
176
170
|
return true
|
|
177
171
|
} catch (error: unknown) {
|
|
178
|
-
|
|
172
|
+
const err = new OperationError(error, {
|
|
173
|
+
operation: `merge dev into ${branch}`,
|
|
174
|
+
remediation: "resolve conflicts manually or rerun after 'git fetch origin'",
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
logger.error({ error, branch, msg: err.message })
|
|
179
178
|
|
|
180
179
|
await $`git reset --merge HEAD~1`
|
|
181
180
|
|
|
@@ -184,7 +183,7 @@ const mergeDev = async (branch: string): Promise<boolean> => {
|
|
|
184
183
|
}
|
|
185
184
|
|
|
186
185
|
// MCP Tool Registration
|
|
187
|
-
export const ghMergeDevMcpTool = {
|
|
186
|
+
export const ghMergeDevMcpTool = defineMcpTool({
|
|
188
187
|
name: 'gh-merge-dev',
|
|
189
188
|
description:
|
|
190
189
|
'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.',
|
|
@@ -203,4 +202,4 @@ export const ghMergeDevMcpTool = {
|
|
|
203
202
|
totalBranches: z.number().describe('Total number of branches processed'),
|
|
204
203
|
},
|
|
205
204
|
handler: ghMergeDev,
|
|
206
|
-
}
|
|
205
|
+
})
|