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.
Files changed (37) hide show
  1. package/dist/cli.js +18 -18
  2. package/dist/cli.js.map +4 -4
  3. package/dist/mcp.js +18 -1
  4. package/dist/mcp.js.map +4 -4
  5. package/package.json +3 -2
  6. package/src/commands/gh-merge-dev/gh-merge-dev.ts +59 -22
  7. package/src/commands/gh-merge-dev/index.ts +1 -1
  8. package/src/commands/gh-release-create/gh-release-create.ts +58 -20
  9. package/src/commands/gh-release-create/index.ts +1 -1
  10. package/src/commands/gh-release-deliver/gh-release-deliver.ts +47 -11
  11. package/src/commands/gh-release-deliver/index.ts +1 -1
  12. package/src/commands/gh-release-deploy/gh-release-deploy.ts +47 -7
  13. package/src/commands/gh-release-deploy/index.ts +1 -1
  14. package/src/commands/gh-release-list/gh-release-list.ts +37 -5
  15. package/src/commands/gh-release-list/index.ts +1 -1
  16. package/src/commands/worktrees-add/index.ts +1 -1
  17. package/src/commands/worktrees-add/worktrees-add.ts +45 -19
  18. package/src/commands/worktrees-list/index.ts +1 -1
  19. package/src/commands/worktrees-list/worktrees-list.ts +69 -33
  20. package/src/commands/worktrees-remove/index.ts +1 -1
  21. package/src/commands/worktrees-remove/worktrees-remove.ts +44 -18
  22. package/src/commands/worktrees-sync/index.ts +1 -1
  23. package/src/commands/worktrees-sync/worktrees-sync.ts +42 -19
  24. package/src/entry/cli.ts +6 -6
  25. package/src/entry/mcp.ts +4 -4
  26. package/src/lib/error-handlers/index.ts +8 -2
  27. package/src/lib/logger/index.ts +23 -2
  28. package/src/mcp/prompts/index.ts +1 -1
  29. package/src/mcp/resources/index.ts +1 -1
  30. package/src/mcp/server.ts +2 -2
  31. package/src/mcp/tools/index.ts +39 -1
  32. package/src/shared/gh-cli-auth/gh-cli-auth.ts +6 -4
  33. package/src/shared/gh-release-prs/gh-release-prs.ts +4 -2
  34. package/src/shared/logger/index.ts +4 -0
  35. package/src/shared/tool-handler/index.ts +1 -0
  36. package/src/shared/tool-handler/tool-handler.ts +29 -0
  37. package/src/types.ts +11 -0
@@ -1,28 +1,25 @@
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 { getCurrentWorktrees, getProjectRoot } from 'src/shared/git-utils'
9
+ import { logger } from 'src/shared/logger'
10
+ import type { RequiredConfirmedOptionArg, ToolsExecutionResult } from 'src/types'
9
11
 
10
12
  // Constants
11
- interface WorktreeManagementArgs {
12
- yes: boolean
13
+ interface WorktreeManagementArgs extends RequiredConfirmedOptionArg {
13
14
  all: boolean
14
15
  }
15
16
 
16
- interface WorktreeManagementResult {
17
- removed: string[]
18
- }
19
-
20
17
  /**
21
18
  * Manage git worktrees for release branches
22
19
  * Creates worktrees for active release branches and removes unused ones
23
20
  */
24
- export const worktreesRemove = async (options: WorktreeManagementArgs): Promise<WorktreeManagementResult> => {
25
- const { yes, all } = options
21
+ export const worktreesRemove = async (options: WorktreeManagementArgs): Promise<ToolsExecutionResult> => {
22
+ const { confirmedCommand, all } = options
26
23
 
27
24
  try {
28
25
  const currentWorktrees = await getCurrentWorktrees('release')
@@ -46,14 +43,14 @@ export const worktreesRemove = async (options: WorktreeManagementArgs): Promise<
46
43
  }
47
44
 
48
45
  // Ask for confirmation
49
- const answer = yes
46
+ const answer = confirmedCommand
50
47
  ? true
51
48
  : await confirm({
52
49
  message: 'Are you sure you want to proceed with these worktree changes?',
53
50
  })
54
51
 
55
52
  if (!answer) {
56
- console.log('Operation cancelled. Exiting...')
53
+ logger.info('Operation cancelled. Exiting...')
57
54
  process.exit(0)
58
55
  }
59
56
 
@@ -61,11 +58,22 @@ export const worktreesRemove = async (options: WorktreeManagementArgs): Promise<
61
58
 
62
59
  logResults(removedWorktrees)
63
60
 
61
+ const structuredContent = {
62
+ removedWorktrees,
63
+ count: removedWorktrees.length,
64
+ }
65
+
64
66
  return {
65
- removed: removedWorktrees,
67
+ content: [
68
+ {
69
+ type: 'text',
70
+ text: JSON.stringify(structuredContent, null, 2),
71
+ },
72
+ ],
73
+ structuredContent,
66
74
  }
67
75
  } catch (error) {
68
- console.error('❌ Error managing worktrees:', error)
76
+ logger.error({ error }, '❌ Error managing worktrees')
69
77
  throw error
70
78
  }
71
79
  }
@@ -82,7 +90,7 @@ const removeWorktrees = async (branches: string[], worktreeDir: string): Promise
82
90
  await $`git worktree remove ${worktreePath}`
83
91
  removed.push(branch)
84
92
  } catch (error) {
85
- console.error(`❌ Failed to remove worktree for ${branch}:`, error)
93
+ logger.error({ error, branch }, `❌ Failed to remove worktree for ${branch}`)
86
94
  }
87
95
  }
88
96
 
@@ -94,10 +102,28 @@ const removeWorktrees = async (branches: string[], worktreeDir: string): Promise
94
102
  */
95
103
  const logResults = (removed: string[]): void => {
96
104
  if (removed.length > 0) {
97
- console.log('❌ Removed worktrees:')
98
- console.log(removed.join('\n'))
99
- console.log()
105
+ logger.info('❌ Removed worktrees:')
106
+ logger.info(removed.join('\n'))
107
+ logger.info('')
100
108
  } else {
101
- console.log('ℹ️ No unused worktrees to remove')
109
+ logger.info('ℹ️ No unused worktrees to remove')
102
110
  }
103
111
  }
112
+
113
+ // MCP Tool Registration
114
+ const worktreesRemoveSchema = z.object({
115
+ all: z.boolean().describe('Remove all worktrees without prompting'),
116
+ })
117
+
118
+ const worktreesRemoveOutputSchema = z.object({
119
+ removedWorktrees: z.array(z.string()).describe('List of removed worktree branches'),
120
+ count: z.number().describe('Number of worktrees removed'),
121
+ })
122
+
123
+ export const worktreesRemoveMcpTool = {
124
+ name: 'worktrees-remove',
125
+ description: 'Remove selected worktrees',
126
+ inputSchema: worktreesRemoveSchema,
127
+ outputSchema: worktreesRemoveOutputSchema,
128
+ handler: worktreesRemove,
129
+ }
@@ -1 +1 @@
1
- export { worktreesSync } from './worktrees-sync'
1
+ export { worktreesSync, worktreesSyncMcpTool } from './worktrees-sync'
@@ -1,29 +1,25 @@
1
- /* eslint-disable no-console */
2
1
  import confirm from '@inquirer/confirm'
3
2
  import process from 'node:process'
3
+ import { z } from 'zod'
4
4
  import { $ } from 'zx'
5
5
 
6
6
  import { WORKTREES_DIR_SUFFIX } from 'src/shared/constants'
7
7
  import { getReleasePRs } from 'src/shared/gh-release-prs'
8
8
  import { getCurrentWorktrees, getProjectRoot } from 'src/shared/git-utils'
9
+ import { logger } from 'src/shared/logger'
10
+ import type { RequiredConfirmedOptionArg, ToolsExecutionResult } from 'src/types'
9
11
 
10
12
  // Constants
11
13
  const RELEASE_BRANCH_PREFIX = 'release/v'
12
14
 
13
- interface WorktreeManagementResult {
14
- removed: string[]
15
- }
16
-
17
- interface WorktreeSyncArgs {
18
- yes: boolean
19
- }
15
+ interface WorktreeSyncArgs extends RequiredConfirmedOptionArg {}
20
16
 
21
17
  /**
22
18
  * Manage git worktrees for release branches
23
19
  * Creates worktrees for active release branches and removes unused ones
24
20
  */
25
- export const worktreesSync = async (options: WorktreeSyncArgs): Promise<WorktreeManagementResult> => {
26
- const { yes } = options
21
+ export const worktreesSync = async (options: WorktreeSyncArgs): Promise<ToolsExecutionResult> => {
22
+ const { confirmedCommand } = options
27
23
 
28
24
  try {
29
25
  const currentWorktrees = await getCurrentWorktrees('release')
@@ -34,14 +30,14 @@ export const worktreesSync = async (options: WorktreeSyncArgs): Promise<Worktree
34
30
  const releasePRsList = await getReleasePRs()
35
31
 
36
32
  // Ask for confirmation
37
- const answer = yes
33
+ const answer = confirmedCommand
38
34
  ? true
39
35
  : await confirm({
40
36
  message: 'Are you sure you want to proceed with these worktree changes?',
41
37
  })
42
38
 
43
39
  if (!answer) {
44
- console.log('Operation cancelled. Exiting...')
40
+ logger.info('Operation cancelled. Exiting...')
45
41
  process.exit(0)
46
42
  }
47
43
 
@@ -54,11 +50,22 @@ export const worktreesSync = async (options: WorktreeSyncArgs): Promise<Worktree
54
50
 
55
51
  logResults(removedWorktrees)
56
52
 
53
+ const structuredContent = {
54
+ removedWorktrees,
55
+ count: removedWorktrees.length,
56
+ }
57
+
57
58
  return {
58
- removed: removedWorktrees,
59
+ content: [
60
+ {
61
+ type: 'text',
62
+ text: JSON.stringify(structuredContent, null, 2),
63
+ },
64
+ ],
65
+ structuredContent,
59
66
  }
60
67
  } catch (error) {
61
- console.error('❌ Error managing worktrees:', error)
68
+ logger.error({ error }, '❌ Error managing worktrees')
62
69
  throw error
63
70
  }
64
71
  }
@@ -93,7 +100,7 @@ const removeWorktrees = async (branches: string[], worktreeDir: string): Promise
93
100
  await $`git worktree remove ${worktreePath}`
94
101
  removed.push(branch)
95
102
  } catch (error) {
96
- console.error(`❌ Failed to remove worktree for ${branch}:`, error)
103
+ logger.error({ error, branch }, `❌ Failed to remove worktree for ${branch}`)
97
104
  }
98
105
  }
99
106
 
@@ -105,10 +112,26 @@ const removeWorktrees = async (branches: string[], worktreeDir: string): Promise
105
112
  */
106
113
  const logResults = (removed: string[]): void => {
107
114
  if (removed.length > 0) {
108
- console.log('❌ Removed worktrees:')
109
- console.log(removed.join('\n'))
110
- console.log()
115
+ logger.info('❌ Removed worktrees:')
116
+ logger.info(removed.join('\n'))
117
+ logger.info('')
111
118
  } else {
112
- console.log('ℹ️ No unused worktrees to remove')
119
+ logger.info('ℹ️ No unused worktrees to remove')
113
120
  }
114
121
  }
122
+
123
+ // MCP Tool Registration
124
+ const worktreesSyncSchema = z.object({})
125
+
126
+ const worktreesSyncOutputSchema = z.object({
127
+ removedWorktrees: z.array(z.string()).describe('List of removed worktree branches'),
128
+ count: z.number().describe('Number of worktrees removed during sync'),
129
+ })
130
+
131
+ export const worktreesSyncMcpTool = {
132
+ name: 'worktrees-sync',
133
+ description: 'Synchronize worktrees with active release branches',
134
+ inputSchema: worktreesSyncSchema,
135
+ outputSchema: worktreesSyncOutputSchema,
136
+ handler: worktreesSync,
137
+ }
package/src/entry/cli.ts CHANGED
@@ -19,7 +19,7 @@ program
19
19
  .option('-a, --all', 'Select all active release branches')
20
20
  .option('-y, --yes', 'Skip confirmation prompt')
21
21
  .action(async (options) => {
22
- await ghMergeDev({ all: options.all, yes: options.yes })
22
+ await ghMergeDev({ all: options.all, confirmedCommand: options.yes })
23
23
  })
24
24
 
25
25
  program
@@ -36,7 +36,7 @@ program
36
36
  .option('-y, --yes', 'Skip confirmation prompt')
37
37
  .option('-c, --checkout', 'Checkout the created branch after creation (only works when creating a single branch)')
38
38
  .action(async (options) => {
39
- await ghReleaseCreate({ versions: options.versions, yes: options.yes, checkout: options.checkout })
39
+ await ghReleaseCreate({ versions: options.versions, confirmedCommand: options.yes, checkout: options.checkout })
40
40
  })
41
41
 
42
42
  program
@@ -54,7 +54,7 @@ program
54
54
  .option('-v, --version <version>', 'Specify the version to release, e.g. 1.2.5')
55
55
  .option('-y, --yes', 'Skip confirmation prompt')
56
56
  .action(async (options) => {
57
- await ghReleaseDeliver({ version: options.version, yes: options.yes })
57
+ await ghReleaseDeliver({ version: options.version, confirmedCommand: options.yes })
58
58
  })
59
59
 
60
60
  program
@@ -62,7 +62,7 @@ program
62
62
  .description('Sync git worktrees for release branches')
63
63
  .option('-y, --yes', 'Skip confirmation prompt')
64
64
  .action(async (options) => {
65
- await worktreesSync({ yes: options.yes })
65
+ await worktreesSync({ confirmedCommand: options.yes })
66
66
  })
67
67
 
68
68
  program
@@ -71,7 +71,7 @@ program
71
71
  .option('-y, --yes', 'Skip confirmation prompt')
72
72
  .option('-a, --all', 'Select all active release branches')
73
73
  .action(async (options) => {
74
- await worktreesAdd({ yes: options.yes, all: options.all })
74
+ await worktreesAdd({ confirmedCommand: options.yes, all: options.all })
75
75
  })
76
76
 
77
77
  program
@@ -87,7 +87,7 @@ program
87
87
  .option('-y, --yes', 'Skip confirmation prompt')
88
88
  .option('-a, --all', 'Select all active release branches')
89
89
  .action(async (options) => {
90
- await worktreesRemove({ yes: options.yes, all: options.all })
90
+ await worktreesRemove({ confirmedCommand: options.yes, all: options.all })
91
91
  })
92
92
 
93
93
  await validateGitHubCliAndAuth()
package/src/entry/mcp.ts CHANGED
@@ -2,11 +2,11 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio'
2
2
  import process from 'node:process'
3
3
 
4
4
  import { setupErrorHandlers } from 'src/lib/error-handlers'
5
- import { initLogger } from 'src/lib/logger'
5
+ import { initLoggerMcp } from 'src/lib/logger'
6
6
 
7
7
  import { createMcpServer } from '../mcp/server'
8
8
 
9
- const logger = initLogger()
9
+ const logger = initLoggerMcp()
10
10
 
11
11
  const startServer = async () => {
12
12
  let server
@@ -14,7 +14,7 @@ const startServer = async () => {
14
14
  server = await createMcpServer()
15
15
  } catch (error) {
16
16
  logger.error({ err: error, msg: 'Failed to create MCP server' })
17
- console.error(`Fatal error during server creation.`)
17
+ logger.error(`Fatal error during server creation.`)
18
18
 
19
19
  process.exit(1)
20
20
  }
@@ -27,7 +27,7 @@ const startServer = async () => {
27
27
  logger.info({ msg: 'Server connected to transport. Ready.' })
28
28
  } catch (error) {
29
29
  logger.error({ err: error, msg: 'Failed to initialize server' })
30
- console.error(`Fatal error during server transport init.`)
30
+ logger.error(`Fatal error during server transport init.`)
31
31
 
32
32
  process.exit(1)
33
33
  }
@@ -3,6 +3,12 @@ import type { Logger } from 'pino'
3
3
 
4
4
  import { LOG_FILE_PATH } from 'src/shared/constants'
5
5
 
6
+ /**
7
+ * Setup error handlers for the application
8
+ * @param logger - The logger instance
9
+ *
10
+ * ONLY FOR SERVER!
11
+ */
6
12
  export const setupErrorHandlers = (logger: Logger) => {
7
13
  process.on('SIGINT', () => {
8
14
  logger.info({ msg: 'Received SIGINT. Shutting down...' })
@@ -16,14 +22,14 @@ export const setupErrorHandlers = (logger: Logger) => {
16
22
 
17
23
  process.on('uncaughtException', (error) => {
18
24
  logger.fatal({ err: error, msg: 'Uncaught Exception' })
19
- console.error(`Uncaught Exception! Check ${LOG_FILE_PATH}. Shutting down...`)
25
+ logger.error(`Uncaught Exception! Check ${LOG_FILE_PATH}. Shutting down...`)
20
26
  logger.flush()
21
27
  process.exit(1)
22
28
  })
23
29
 
24
30
  process.on('unhandledRejection', (reason, promise) => {
25
31
  logger.fatal({ reason, promise, msg: 'Unhandled Rejection' })
26
- console.error(`Unhandled Rejection! Check ${LOG_FILE_PATH}. Shutting down...`)
32
+ logger.error(`Unhandled Rejection! Check ${LOG_FILE_PATH}. Shutting down...`)
27
33
  logger.flush()
28
34
  process.exit(1)
29
35
  })
@@ -1,14 +1,35 @@
1
1
  import process from 'node:process'
2
2
  import pino from 'pino'
3
+ import pretty from 'pino-pretty'
3
4
 
4
5
  import { LOG_FILE_PATH } from 'src/shared/constants'
5
6
 
6
- export const initLogger = () => {
7
+ export const initLoggerMcp = () => {
7
8
  const logLevel = process.argv.includes('--debug') ? 'debug' : 'info'
8
9
 
9
- const logger = pino({ level: logLevel }, pino.destination(LOG_FILE_PATH))
10
+ const logger = pino({ level: logLevel })
10
11
 
11
12
  logger.info(`Logger initialized with level: ${logLevel}. Logging to: ${LOG_FILE_PATH}`)
12
13
 
13
14
  return logger
14
15
  }
16
+
17
+ export const initLoggerCLI = () => {
18
+ const logLevel = process.argv.includes('--debug') ? 'debug' : 'info'
19
+
20
+ const ignoreFields = ['time', 'pid', 'hostname']
21
+
22
+ if (logLevel === 'debug') {
23
+ ignoreFields.push('level')
24
+ }
25
+
26
+ const logger = pino(
27
+ { level: logLevel },
28
+ pretty({
29
+ ignore: ignoreFields.join(','),
30
+ colorize: true,
31
+ }),
32
+ )
33
+
34
+ return logger
35
+ }
@@ -1,3 +1,3 @@
1
1
  import type { Server } from '@modelcontextprotocol/sdk/server/index'
2
2
 
3
- export const initializePrompts = async (server: Server) => {}
3
+ export const initializePrompts = async (_server: Server) => {}
@@ -1,3 +1,3 @@
1
1
  import type { Server } from '@modelcontextprotocol/sdk/server/index'
2
2
 
3
- export const initializeResources = async (server: Server) => {}
3
+ export const initializeResources = async (_server: Server) => {}
package/src/mcp/server.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  import { Server } from '@modelcontextprotocol/sdk/server/index.js'
2
2
 
3
- import { initLogger } from 'src/lib/logger'
3
+ import { initLoggerMcp } from 'src/lib/logger'
4
4
 
5
5
  import { initializePrompts } from './prompts'
6
6
  import { initializeResources } from './resources'
7
7
  import { initializeTools } from './tools'
8
8
 
9
- const logger = initLogger()
9
+ const logger = initLoggerMcp()
10
10
 
11
11
  export async function createMcpServer() {
12
12
  const server = new Server(
@@ -1,3 +1,41 @@
1
1
  import type { Server } from '@modelcontextprotocol/sdk/server/index'
2
2
 
3
- export const initializeTools = async (server: Server) => {}
3
+ import { ghMergeDevMcpTool } from 'src/commands/gh-merge-dev'
4
+ import { ghReleaseCreateMcpTool } from 'src/commands/gh-release-create'
5
+ import { ghReleaseDeliverMcpTool } from 'src/commands/gh-release-deliver'
6
+ import { ghReleaseDeployMcpTool } from 'src/commands/gh-release-deploy'
7
+ import { ghReleaseListMcpTool } from 'src/commands/gh-release-list'
8
+ import { worktreesAddMcpTool } from 'src/commands/worktrees-add'
9
+ import { worktreesListMcpTool } from 'src/commands/worktrees-list'
10
+ import { worktreesRemoveMcpTool } from 'src/commands/worktrees-remove'
11
+ import { worktreesSyncMcpTool } from 'src/commands/worktrees-sync'
12
+ import { createToolHandler } from 'src/shared/tool-handler'
13
+
14
+ const tools = [
15
+ ghMergeDevMcpTool,
16
+ ghReleaseCreateMcpTool,
17
+ ghReleaseDeliverMcpTool,
18
+ ghReleaseDeployMcpTool,
19
+ ghReleaseListMcpTool,
20
+ worktreesAddMcpTool,
21
+ worktreesListMcpTool,
22
+ worktreesRemoveMcpTool,
23
+ worktreesSyncMcpTool,
24
+ ]
25
+
26
+ export const initializeTools = async (server: Server) => {
27
+ for (const tool of tools) {
28
+ // eslint-disable-next-line ts/ban-ts-comment
29
+ // @ts-expect-error
30
+ server.registerTool(
31
+ tool.name,
32
+ {
33
+ description: tool.description,
34
+ inputSchema: tool.inputSchema,
35
+ outputSchema: tool.outputSchema,
36
+ handler: tool.handler,
37
+ },
38
+ createToolHandler({ toolName: tool.name, handler: tool.handler }),
39
+ )
40
+ }
41
+ }
@@ -1,6 +1,8 @@
1
1
  import process from 'node:process'
2
2
  import { $ } from 'zx'
3
3
 
4
+ import { logger } from 'src/shared/logger'
5
+
4
6
  /**
5
7
  * Validate GitHub CLI installation and authentication status and throw an error if not valid
6
8
  */
@@ -8,16 +10,16 @@ export const validateGitHubCliAndAuth = async () => {
8
10
  try {
9
11
  await $`gh --version`
10
12
  } catch (error: unknown) {
11
- console.error('Error: GitHub CLI (gh) is not installed.', (error as Error)?.message)
12
- console.error('Please install it from: https://cli.github.com/')
13
+ logger.error({ error }, 'Error: GitHub CLI (gh) is not installed.')
14
+ logger.error('Please install it from: https://cli.github.com/')
13
15
  process.exit(1)
14
16
  }
15
17
 
16
18
  try {
17
19
  await $`gh auth status`
18
20
  } catch (error: unknown) {
19
- console.error('Error: GitHub CLI (gh) is not authenticated.', (error as Error)?.message)
20
- console.error('Please authenticate it from: https://cli.github.com/manual/gh_auth_login or type "gh auth login"')
21
+ logger.error({ error }, 'Error: GitHub CLI (gh) is not authenticated.')
22
+ logger.error('Please authenticate it from: https://cli.github.com/manual/gh_auth_login or type "gh auth login"')
21
23
  process.exit(1)
22
24
  }
23
25
  }
@@ -1,6 +1,8 @@
1
1
  import process from 'node:process'
2
2
  import { $ } from 'zx'
3
3
 
4
+ import { logger } from 'src/shared/logger'
5
+
4
6
  interface ReleasePR {
5
7
  headRefName: string
6
8
  number: number
@@ -25,13 +27,13 @@ export const getReleasePRs = async (): Promise<string[]> => {
25
27
  const releasePRsArray: ReleasePR[] = JSON.parse(releasePRs.stdout)
26
28
 
27
29
  if (releasePRsArray.length === 0) {
28
- console.error('❌ No release PRs found. Check the project folder for the script. Exiting...')
30
+ logger.error('❌ No release PRs found. Check the project folder for the script. Exiting...')
29
31
  process.exit(1)
30
32
  }
31
33
 
32
34
  return releasePRsArray.map((pr) => pr.headRefName)
33
35
  } catch (error) {
34
- console.error('❌ Error fetching release PRs:', error instanceof Error ? error.message : String(error))
36
+ logger.error({ error }, '❌ Error fetching release PRs')
35
37
  process.exit(1)
36
38
  }
37
39
  }
@@ -0,0 +1,4 @@
1
+ import { initLoggerCLI } from 'src/lib/logger'
2
+
3
+ // INFO: This is a logger for NPM CLI package
4
+ export const logger = initLoggerCLI()
@@ -0,0 +1 @@
1
+ export { createToolHandler } from './tool-handler'
@@ -0,0 +1,29 @@
1
+ import type { ToolsExecutionResult } from 'src/types'
2
+
3
+ import { logger } from '../logger'
4
+
5
+ interface ToolHandlerArgs {
6
+ toolName: string
7
+ handler: (params: any) => Promise<ToolsExecutionResult>
8
+ }
9
+
10
+ export const createToolHandler = (args: ToolHandlerArgs) => async (params: unknown) => {
11
+ const { toolName, handler } = args
12
+
13
+ logger.info({ msg: `Tool execution started: ${toolName}`, params })
14
+ try {
15
+ const payload = await handler({ ...(params as object), confirmedCommand: true })
16
+
17
+ logger.info({ msg: `Tool execution successful: ${toolName}` })
18
+
19
+ return payload
20
+ } catch (error) {
21
+ logger.error({
22
+ err: error,
23
+ params,
24
+ msg: `Tool execution failed: ${toolName}`,
25
+ })
26
+
27
+ throw error
28
+ }
29
+ }
package/src/types.ts ADDED
@@ -0,0 +1,11 @@
1
+ export interface ToolsExecutionResult {
2
+ content: {
3
+ type: 'text'
4
+ text: string
5
+ }[]
6
+ structuredContent?: unknown
7
+ }
8
+
9
+ export interface RequiredConfirmedOptionArg {
10
+ confirmedCommand: boolean
11
+ }