memory-journal-mcp 4.4.2 → 5.0.0

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 (291) hide show
  1. package/.github/workflows/codeql.yml +1 -6
  2. package/.github/workflows/docker-publish.yml +15 -49
  3. package/.github/workflows/lint-and-test.yml +1 -1
  4. package/.github/workflows/secrets-scanning.yml +4 -3
  5. package/.github/workflows/security-update.yml +3 -3
  6. package/CHANGELOG.md +213 -0
  7. package/CONTRIBUTING.md +132 -97
  8. package/DOCKER_README.md +184 -235
  9. package/Dockerfile +27 -24
  10. package/README.md +218 -190
  11. package/SECURITY.md +27 -35
  12. package/dist/cli.js +16 -1
  13. package/dist/cli.js.map +1 -1
  14. package/dist/constants/ServerInstructions.d.ts +5 -1
  15. package/dist/constants/ServerInstructions.d.ts.map +1 -1
  16. package/dist/constants/ServerInstructions.js +133 -73
  17. package/dist/constants/ServerInstructions.js.map +1 -1
  18. package/dist/constants/icons.d.ts +2 -2
  19. package/dist/constants/icons.d.ts.map +1 -1
  20. package/dist/constants/icons.js +7 -6
  21. package/dist/constants/icons.js.map +1 -1
  22. package/dist/database/SqliteAdapter.d.ts +37 -24
  23. package/dist/database/SqliteAdapter.d.ts.map +1 -1
  24. package/dist/database/SqliteAdapter.js +319 -157
  25. package/dist/database/SqliteAdapter.js.map +1 -1
  26. package/dist/database/schema.d.ts +45 -0
  27. package/dist/database/schema.d.ts.map +1 -0
  28. package/dist/database/schema.js +92 -0
  29. package/dist/database/schema.js.map +1 -0
  30. package/dist/filtering/ToolFilter.d.ts +1 -1
  31. package/dist/filtering/ToolFilter.d.ts.map +1 -1
  32. package/dist/filtering/ToolFilter.js +13 -2
  33. package/dist/filtering/ToolFilter.js.map +1 -1
  34. package/dist/github/GitHubIntegration.d.ts.map +1 -1
  35. package/dist/github/GitHubIntegration.js +1 -3
  36. package/dist/github/GitHubIntegration.js.map +1 -1
  37. package/dist/handlers/prompts/github.d.ts +12 -0
  38. package/dist/handlers/prompts/github.d.ts.map +1 -0
  39. package/dist/handlers/prompts/github.js +178 -0
  40. package/dist/handlers/prompts/github.js.map +1 -0
  41. package/dist/handlers/prompts/index.d.ts +23 -2
  42. package/dist/handlers/prompts/index.d.ts.map +1 -1
  43. package/dist/handlers/prompts/index.js +7 -432
  44. package/dist/handlers/prompts/index.js.map +1 -1
  45. package/dist/handlers/prompts/workflow.d.ts +12 -0
  46. package/dist/handlers/prompts/workflow.d.ts.map +1 -0
  47. package/dist/handlers/prompts/workflow.js +277 -0
  48. package/dist/handlers/prompts/workflow.js.map +1 -0
  49. package/dist/handlers/resources/core.d.ts +11 -0
  50. package/dist/handlers/resources/core.d.ts.map +1 -0
  51. package/dist/handlers/resources/core.js +433 -0
  52. package/dist/handlers/resources/core.js.map +1 -0
  53. package/dist/handlers/resources/github.d.ts +11 -0
  54. package/dist/handlers/resources/github.d.ts.map +1 -0
  55. package/dist/handlers/resources/github.js +314 -0
  56. package/dist/handlers/resources/github.js.map +1 -0
  57. package/dist/handlers/resources/graph.d.ts +11 -0
  58. package/dist/handlers/resources/graph.d.ts.map +1 -0
  59. package/dist/handlers/resources/graph.js +204 -0
  60. package/dist/handlers/resources/graph.js.map +1 -0
  61. package/dist/handlers/resources/index.d.ts +5 -20
  62. package/dist/handlers/resources/index.d.ts.map +1 -1
  63. package/dist/handlers/resources/index.js +16 -1278
  64. package/dist/handlers/resources/index.js.map +1 -1
  65. package/dist/handlers/resources/shared.d.ts +60 -0
  66. package/dist/handlers/resources/shared.d.ts.map +1 -0
  67. package/dist/handlers/resources/shared.js +49 -0
  68. package/dist/handlers/resources/shared.js.map +1 -0
  69. package/dist/handlers/resources/team.d.ts +13 -0
  70. package/dist/handlers/resources/team.d.ts.map +1 -0
  71. package/dist/handlers/resources/team.js +119 -0
  72. package/dist/handlers/resources/team.js.map +1 -0
  73. package/dist/handlers/resources/templates.d.ts +13 -0
  74. package/dist/handlers/resources/templates.d.ts.map +1 -0
  75. package/dist/handlers/resources/templates.js +310 -0
  76. package/dist/handlers/resources/templates.js.map +1 -0
  77. package/dist/handlers/tools/admin.d.ts +8 -0
  78. package/dist/handlers/tools/admin.d.ts.map +1 -0
  79. package/dist/handlers/tools/admin.js +270 -0
  80. package/dist/handlers/tools/admin.js.map +1 -0
  81. package/dist/handlers/tools/analytics.d.ts +8 -0
  82. package/dist/handlers/tools/analytics.d.ts.map +1 -0
  83. package/dist/handlers/tools/analytics.js +256 -0
  84. package/dist/handlers/tools/analytics.js.map +1 -0
  85. package/dist/handlers/tools/backup.d.ts +8 -0
  86. package/dist/handlers/tools/backup.d.ts.map +1 -0
  87. package/dist/handlers/tools/backup.js +224 -0
  88. package/dist/handlers/tools/backup.js.map +1 -0
  89. package/dist/handlers/tools/core.d.ts +9 -0
  90. package/dist/handlers/tools/core.d.ts.map +1 -0
  91. package/dist/handlers/tools/core.js +326 -0
  92. package/dist/handlers/tools/core.js.map +1 -0
  93. package/dist/handlers/tools/export.d.ts +8 -0
  94. package/dist/handlers/tools/export.d.ts.map +1 -0
  95. package/dist/handlers/tools/export.js +89 -0
  96. package/dist/handlers/tools/export.js.map +1 -0
  97. package/dist/handlers/tools/github/helpers.d.ts +34 -0
  98. package/dist/handlers/tools/github/helpers.d.ts.map +1 -0
  99. package/dist/handlers/tools/github/helpers.js +52 -0
  100. package/dist/handlers/tools/github/helpers.js.map +1 -0
  101. package/dist/handlers/tools/github/insights-tools.d.ts +8 -0
  102. package/dist/handlers/tools/github/insights-tools.d.ts.map +1 -0
  103. package/dist/handlers/tools/github/insights-tools.js +104 -0
  104. package/dist/handlers/tools/github/insights-tools.js.map +1 -0
  105. package/dist/handlers/tools/github/issue-tools.d.ts +8 -0
  106. package/dist/handlers/tools/github/issue-tools.d.ts.map +1 -0
  107. package/dist/handlers/tools/github/issue-tools.js +359 -0
  108. package/dist/handlers/tools/github/issue-tools.js.map +1 -0
  109. package/dist/handlers/tools/github/kanban-tools.d.ts +8 -0
  110. package/dist/handlers/tools/github/kanban-tools.d.ts.map +1 -0
  111. package/dist/handlers/tools/github/kanban-tools.js +108 -0
  112. package/dist/handlers/tools/github/kanban-tools.js.map +1 -0
  113. package/dist/handlers/tools/github/milestone-tools.d.ts +9 -0
  114. package/dist/handlers/tools/github/milestone-tools.d.ts.map +1 -0
  115. package/dist/handlers/tools/github/milestone-tools.js +302 -0
  116. package/dist/handlers/tools/github/milestone-tools.js.map +1 -0
  117. package/dist/handlers/tools/github/mutation-tools.d.ts +12 -0
  118. package/dist/handlers/tools/github/mutation-tools.d.ts.map +1 -0
  119. package/dist/handlers/tools/github/mutation-tools.js +15 -0
  120. package/dist/handlers/tools/github/mutation-tools.js.map +1 -0
  121. package/dist/handlers/tools/github/read-tools.d.ts +8 -0
  122. package/dist/handlers/tools/github/read-tools.d.ts.map +1 -0
  123. package/dist/handlers/tools/github/read-tools.js +260 -0
  124. package/dist/handlers/tools/github/read-tools.js.map +1 -0
  125. package/dist/handlers/tools/github/schemas.d.ts +467 -0
  126. package/dist/handlers/tools/github/schemas.d.ts.map +1 -0
  127. package/dist/handlers/tools/github/schemas.js +335 -0
  128. package/dist/handlers/tools/github/schemas.js.map +1 -0
  129. package/dist/handlers/tools/github.d.ts +14 -0
  130. package/dist/handlers/tools/github.d.ts.map +1 -0
  131. package/dist/handlers/tools/github.js +28 -0
  132. package/dist/handlers/tools/github.js.map +1 -0
  133. package/dist/handlers/tools/index.d.ts +15 -20
  134. package/dist/handlers/tools/index.d.ts.map +1 -1
  135. package/dist/handlers/tools/index.js +117 -2909
  136. package/dist/handlers/tools/index.js.map +1 -1
  137. package/dist/handlers/tools/relationships.d.ts +8 -0
  138. package/dist/handlers/tools/relationships.d.ts.map +1 -0
  139. package/dist/handlers/tools/relationships.js +308 -0
  140. package/dist/handlers/tools/relationships.js.map +1 -0
  141. package/dist/handlers/tools/schemas.d.ts +108 -0
  142. package/dist/handlers/tools/schemas.d.ts.map +1 -0
  143. package/dist/handlers/tools/schemas.js +122 -0
  144. package/dist/handlers/tools/schemas.js.map +1 -0
  145. package/dist/handlers/tools/search.d.ts +8 -0
  146. package/dist/handlers/tools/search.d.ts.map +1 -0
  147. package/dist/handlers/tools/search.js +282 -0
  148. package/dist/handlers/tools/search.js.map +1 -0
  149. package/dist/handlers/tools/team.d.ts +11 -0
  150. package/dist/handlers/tools/team.d.ts.map +1 -0
  151. package/dist/handlers/tools/team.js +239 -0
  152. package/dist/handlers/tools/team.js.map +1 -0
  153. package/dist/server/McpServer.d.ts +4 -0
  154. package/dist/server/McpServer.d.ts.map +1 -1
  155. package/dist/server/McpServer.js +48 -297
  156. package/dist/server/McpServer.js.map +1 -1
  157. package/dist/server/Scheduler.d.ts +91 -0
  158. package/dist/server/Scheduler.d.ts.map +1 -0
  159. package/dist/server/Scheduler.js +201 -0
  160. package/dist/server/Scheduler.js.map +1 -0
  161. package/dist/transports/http.d.ts +66 -0
  162. package/dist/transports/http.d.ts.map +1 -0
  163. package/dist/transports/http.js +519 -0
  164. package/dist/transports/http.js.map +1 -0
  165. package/dist/types/entities.d.ts +101 -0
  166. package/dist/types/entities.d.ts.map +1 -0
  167. package/dist/types/entities.js +5 -0
  168. package/dist/types/entities.js.map +1 -0
  169. package/dist/types/filtering.d.ts +34 -0
  170. package/dist/types/filtering.d.ts.map +1 -0
  171. package/dist/types/filtering.js +5 -0
  172. package/dist/types/filtering.js.map +1 -0
  173. package/dist/types/github.d.ts +166 -0
  174. package/dist/types/github.d.ts.map +1 -0
  175. package/dist/types/github.js +5 -0
  176. package/dist/types/github.js.map +1 -0
  177. package/dist/types/index.d.ts +35 -292
  178. package/dist/types/index.d.ts.map +1 -1
  179. package/dist/types/index.js +2 -2
  180. package/dist/types/index.js.map +1 -1
  181. package/dist/utils/error-helpers.d.ts +37 -0
  182. package/dist/utils/error-helpers.d.ts.map +1 -0
  183. package/dist/utils/error-helpers.js +47 -0
  184. package/dist/utils/error-helpers.js.map +1 -0
  185. package/dist/utils/logger.d.ts.map +1 -1
  186. package/dist/utils/logger.js +6 -3
  187. package/dist/utils/logger.js.map +1 -1
  188. package/dist/utils/security-utils.d.ts +0 -21
  189. package/dist/utils/security-utils.d.ts.map +1 -1
  190. package/dist/utils/security-utils.js +0 -47
  191. package/dist/utils/security-utils.js.map +1 -1
  192. package/dist/vector/VectorSearchManager.d.ts.map +1 -1
  193. package/dist/vector/VectorSearchManager.js +9 -32
  194. package/dist/vector/VectorSearchManager.js.map +1 -1
  195. package/docker-compose.yml +11 -2
  196. package/hooks/README.md +107 -0
  197. package/hooks/cursor/hooks.json +10 -0
  198. package/hooks/cursor/memory-journal.mdc +22 -0
  199. package/hooks/cursor/session-end.sh +19 -0
  200. package/hooks/kilo-code/session-end-mode.json +11 -0
  201. package/hooks/kiro/session-end.md +13 -0
  202. package/mcp-config-example.json +1 -0
  203. package/package.json +11 -9
  204. package/playwright.config.ts +29 -0
  205. package/releases/v4.5.0.md +116 -0
  206. package/releases/v5.0.0.md +105 -0
  207. package/scripts/generate-server-instructions.ts +176 -0
  208. package/scripts/server-instructions-function-body.ts +77 -0
  209. package/server.json +3 -3
  210. package/src/cli.ts +45 -1
  211. package/src/constants/ServerInstructions.ts +133 -73
  212. package/src/constants/icons.ts +8 -7
  213. package/src/constants/server-instructions.md +268 -0
  214. package/src/database/SqliteAdapter.ts +358 -192
  215. package/src/database/schema.ts +125 -0
  216. package/src/filtering/ToolFilter.ts +13 -2
  217. package/src/github/GitHubIntegration.ts +1 -3
  218. package/src/handlers/prompts/github.ts +209 -0
  219. package/src/handlers/prompts/index.ts +10 -499
  220. package/src/handlers/prompts/workflow.ts +314 -0
  221. package/src/handlers/resources/core.ts +528 -0
  222. package/src/handlers/resources/github.ts +358 -0
  223. package/src/handlers/resources/graph.ts +254 -0
  224. package/src/handlers/resources/index.ts +23 -1570
  225. package/src/handlers/resources/shared.ts +103 -0
  226. package/src/handlers/resources/team.ts +133 -0
  227. package/src/handlers/resources/templates.ts +374 -0
  228. package/src/handlers/tools/admin.ts +285 -0
  229. package/src/handlers/tools/analytics.ts +301 -0
  230. package/src/handlers/tools/backup.ts +242 -0
  231. package/src/handlers/tools/core.ts +350 -0
  232. package/src/handlers/tools/export.ts +115 -0
  233. package/src/handlers/tools/github/helpers.ts +86 -0
  234. package/src/handlers/tools/github/insights-tools.ts +119 -0
  235. package/src/handlers/tools/github/issue-tools.ts +439 -0
  236. package/src/handlers/tools/github/kanban-tools.ts +134 -0
  237. package/src/handlers/tools/github/milestone-tools.ts +392 -0
  238. package/src/handlers/tools/github/mutation-tools.ts +17 -0
  239. package/src/handlers/tools/github/read-tools.ts +328 -0
  240. package/src/handlers/tools/github/schemas.ts +369 -0
  241. package/src/handlers/tools/github.ts +36 -0
  242. package/src/handlers/tools/index.ts +144 -3325
  243. package/src/handlers/tools/relationships.ts +358 -0
  244. package/src/handlers/tools/schemas.ts +132 -0
  245. package/src/handlers/tools/search.ts +343 -0
  246. package/src/handlers/tools/team.ts +273 -0
  247. package/src/server/McpServer.ts +63 -358
  248. package/src/server/Scheduler.ts +278 -0
  249. package/src/transports/http.ts +635 -0
  250. package/src/types/entities.ts +145 -0
  251. package/src/types/filtering.ts +54 -0
  252. package/src/types/github.ts +180 -0
  253. package/src/types/index.ts +67 -375
  254. package/src/utils/error-helpers.ts +52 -0
  255. package/src/utils/logger.ts +6 -3
  256. package/src/utils/security-utils.ts +0 -52
  257. package/src/vector/VectorSearchManager.ts +9 -33
  258. package/tests/constants/icons.test.ts +1 -2
  259. package/tests/constants/server-instructions.test.ts +30 -4
  260. package/tests/database/sqlite-adapter.test.ts +91 -7
  261. package/tests/e2e/auth.spec.ts +154 -0
  262. package/tests/e2e/health.spec.ts +63 -0
  263. package/tests/e2e/protocols.spec.ts +134 -0
  264. package/tests/e2e/resources.spec.ts +103 -0
  265. package/tests/e2e/scheduler.spec.ts +79 -0
  266. package/tests/e2e/security.spec.ts +91 -0
  267. package/tests/e2e/sessions.spec.ts +95 -0
  268. package/tests/e2e/stateless.spec.ts +121 -0
  269. package/tests/e2e/tools.spec.ts +111 -0
  270. package/tests/filtering/tool-filter.test.ts +46 -0
  271. package/tests/handlers/error-path-coverage.test.ts +324 -0
  272. package/tests/handlers/github-resource-handlers.test.ts +453 -0
  273. package/tests/handlers/github-tool-handlers.test.ts +899 -0
  274. package/tests/handlers/prompt-handler-coverage.test.ts +106 -0
  275. package/tests/handlers/prompt-handlers.test.ts +40 -0
  276. package/tests/handlers/resource-handler-coverage.test.ts +181 -0
  277. package/tests/handlers/resource-handlers.test.ts +33 -9
  278. package/tests/handlers/search-tool-handlers.test.ts +272 -0
  279. package/tests/handlers/targeted-gap-closure.test.ts +387 -0
  280. package/tests/handlers/team-resource-handlers.test.ts +156 -0
  281. package/tests/handlers/team-tool-handlers.test.ts +301 -0
  282. package/tests/handlers/tool-handler-coverage.test.ts +469 -0
  283. package/tests/handlers/tool-handlers.test.ts +2 -2
  284. package/tests/security/sql-injection.test.ts +3 -54
  285. package/tests/server/mcp-server.test.ts +503 -8
  286. package/tests/server/scheduler.test.ts +400 -0
  287. package/tests/transports/http-transport.test.ts +620 -0
  288. package/tests/vector/vector-search-manager.test.ts +60 -0
  289. package/vitest.config.ts +4 -1
  290. package/.memory-journal-team.db +0 -0
  291. package/.vscode/settings.json +0 -84
@@ -0,0 +1,392 @@
1
+ /**
2
+ * GitHub Milestone Tools - 5 tools
3
+ *
4
+ * Tools: get_github_milestones, get_github_milestone,
5
+ * create_github_milestone, update_github_milestone, delete_github_milestone
6
+ */
7
+
8
+ import { z } from 'zod'
9
+ import type { ToolDefinition, ToolContext } from '../../../types/index.js'
10
+ import type { GitHubIntegration } from '../../../github/GitHubIntegration.js'
11
+ import { formatHandlerError } from '../../../utils/error-helpers.js'
12
+ import {
13
+ GitHubMilestonesListOutputSchema,
14
+ GitHubMilestoneResultOutputSchema,
15
+ CreateMilestoneOutputSchema,
16
+ UpdateMilestoneOutputSchema,
17
+ DeleteMilestoneOutputSchema,
18
+ } from './schemas.js'
19
+
20
+ // ============================================================================
21
+ // Helper: owner/repo resolution
22
+ // ============================================================================
23
+
24
+ async function resolveOwnerRepo(
25
+ context: ToolContext,
26
+ input: { owner?: string; repo?: string },
27
+ entityLabel: string
28
+ ): Promise<
29
+ | {
30
+ owner: string
31
+ repo: string
32
+ detectedOwner: string | null
33
+ detectedRepo: string | null
34
+ github: GitHubIntegration
35
+ }
36
+ | { error: true; response: Record<string, unknown> }
37
+ > {
38
+ if (!context.github) {
39
+ return { error: true, response: { error: 'GitHub integration not available' } }
40
+ }
41
+
42
+ const repoInfo = await context.github.getRepoInfo()
43
+ const detectedOwner = repoInfo.owner
44
+ const detectedRepo = repoInfo.repo
45
+ const owner = input.owner ?? detectedOwner ?? undefined
46
+ const repo = input.repo ?? detectedRepo ?? undefined
47
+
48
+ if (!owner || !repo) {
49
+ return {
50
+ error: true,
51
+ response: {
52
+ error: 'STOP: Could not auto-detect repository. DO NOT GUESS. You MUST ask the user to provide the GitHub owner and repository name.',
53
+ requiresUserInput: true,
54
+ detectedOwner,
55
+ detectedRepo,
56
+ instruction: `Ask the user: "${entityLabel}"`,
57
+ },
58
+ }
59
+ }
60
+
61
+ return { owner, repo, detectedOwner, detectedRepo, github: context.github }
62
+ }
63
+
64
+ // ============================================================================
65
+ // Tool Definitions
66
+ // ============================================================================
67
+
68
+ export function getGitHubMilestoneTools(context: ToolContext): ToolDefinition[] {
69
+ return [
70
+ {
71
+ name: 'get_github_milestones',
72
+ title: 'List GitHub Milestones',
73
+ description:
74
+ 'List GitHub milestones for the repository with completion percentages and due dates.',
75
+ group: 'github',
76
+ inputSchema: z.object({
77
+ state: z
78
+ .string()
79
+ .optional()
80
+ .default('open')
81
+ .describe('Filter by state (default: open)'),
82
+ limit: z
83
+ .number()
84
+ .optional()
85
+ .default(20)
86
+ .describe('Max milestones to return (default: 20)'),
87
+ owner: z.string().optional().describe('LEAVE EMPTY to auto-detect from git'),
88
+ repo: z.string().optional().describe('LEAVE EMPTY to auto-detect from git'),
89
+ }),
90
+ outputSchema: GitHubMilestonesListOutputSchema,
91
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
92
+ handler: async (params: unknown) => {
93
+ try {
94
+ const input = z
95
+ .object({
96
+ state: z.enum(['open', 'closed', 'all']).optional().default('open'),
97
+ limit: z.number().optional().default(20),
98
+ owner: z.string().optional(),
99
+ repo: z.string().optional(),
100
+ })
101
+ .parse(params)
102
+
103
+ const resolved = await resolveOwnerRepo(
104
+ context,
105
+ input,
106
+ 'What GitHub repository should I list milestones for? Please provide the owner and repo name (e.g., owner/repo).'
107
+ )
108
+ if ('error' in resolved) return resolved.response
109
+
110
+ const milestones = await resolved.github.getMilestones(
111
+ resolved.owner,
112
+ resolved.repo,
113
+ input.state,
114
+ input.limit
115
+ )
116
+ const milestonesWithPercentage = milestones.map((ms) => {
117
+ const total = ms.openIssues + ms.closedIssues
118
+ const completionPercentage =
119
+ total > 0 ? Math.round((ms.closedIssues / total) * 100) : 0
120
+ return { ...ms, completionPercentage }
121
+ })
122
+
123
+ return {
124
+ milestones: milestonesWithPercentage,
125
+ count: milestonesWithPercentage.length,
126
+ owner: resolved.owner,
127
+ repo: resolved.repo,
128
+ detectedOwner: resolved.detectedOwner,
129
+ detectedRepo: resolved.detectedRepo,
130
+ }
131
+ } catch (err) {
132
+ return formatHandlerError(err)
133
+ }
134
+ },
135
+ },
136
+ {
137
+ name: 'get_github_milestone',
138
+ title: 'Get GitHub Milestone Details',
139
+ description:
140
+ 'Get detailed information about a specific GitHub milestone including progress and linked issue counts.',
141
+ group: 'github',
142
+ inputSchema: z.object({
143
+ milestone_number: z.number().describe('Milestone number'),
144
+ owner: z.string().optional().describe('LEAVE EMPTY to auto-detect from git'),
145
+ repo: z.string().optional().describe('LEAVE EMPTY to auto-detect from git'),
146
+ }),
147
+ outputSchema: GitHubMilestoneResultOutputSchema,
148
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
149
+ handler: async (params: unknown) => {
150
+ try {
151
+ const input = z
152
+ .object({
153
+ milestone_number: z.number(),
154
+ owner: z.string().optional(),
155
+ repo: z.string().optional(),
156
+ })
157
+ .parse(params)
158
+
159
+ const resolved = await resolveOwnerRepo(
160
+ context,
161
+ input,
162
+ 'What GitHub repository is this milestone from? Please provide the owner and repo name (e.g., owner/repo).'
163
+ )
164
+ if ('error' in resolved) return resolved.response
165
+
166
+ const milestone = await resolved.github.getMilestone(
167
+ resolved.owner,
168
+ resolved.repo,
169
+ input.milestone_number
170
+ )
171
+ if (!milestone) {
172
+ return {
173
+ error: `Milestone #${String(input.milestone_number)} not found`,
174
+ owner: resolved.owner,
175
+ repo: resolved.repo,
176
+ detectedOwner: resolved.detectedOwner,
177
+ detectedRepo: resolved.detectedRepo,
178
+ }
179
+ }
180
+
181
+ const total = milestone.openIssues + milestone.closedIssues
182
+ const completionPercentage =
183
+ total > 0 ? Math.round((milestone.closedIssues / total) * 100) : 0
184
+
185
+ return {
186
+ milestone: { ...milestone, completionPercentage },
187
+ owner: resolved.owner,
188
+ repo: resolved.repo,
189
+ detectedOwner: resolved.detectedOwner,
190
+ detectedRepo: resolved.detectedRepo,
191
+ }
192
+ } catch (err) {
193
+ return formatHandlerError(err)
194
+ }
195
+ },
196
+ },
197
+ {
198
+ name: 'create_github_milestone',
199
+ title: 'Create GitHub Milestone',
200
+ description:
201
+ 'Create a new GitHub milestone for tracking progress toward a project goal.',
202
+ group: 'github',
203
+ inputSchema: z.object({
204
+ title: z.string().min(1).describe('Milestone title'),
205
+ description: z.string().optional().describe('Milestone description'),
206
+ due_on: z.string().optional().describe('Due date in YYYY-MM-DD format (optional)'),
207
+ owner: z.string().optional().describe('LEAVE EMPTY to auto-detect'),
208
+ repo: z.string().optional().describe('LEAVE EMPTY to auto-detect'),
209
+ }),
210
+ outputSchema: CreateMilestoneOutputSchema,
211
+ annotations: { readOnlyHint: false, idempotentHint: false, openWorldHint: true },
212
+ handler: async (params: unknown) => {
213
+ try {
214
+ const input = z
215
+ .object({
216
+ title: z.string().min(1),
217
+ description: z.string().optional(),
218
+ due_on: z.string().optional(),
219
+ owner: z.string().optional(),
220
+ repo: z.string().optional(),
221
+ })
222
+ .parse(params)
223
+
224
+ const resolved = await resolveOwnerRepo(
225
+ context,
226
+ input,
227
+ 'What GitHub repository should I create the milestone in?'
228
+ )
229
+ if ('error' in resolved) return resolved.response
230
+
231
+ const dueOn = input.due_on ? `${input.due_on}T08:00:00Z` : undefined
232
+ const milestone = await resolved.github.createMilestone(
233
+ resolved.owner,
234
+ resolved.repo,
235
+ input.title,
236
+ input.description,
237
+ dueOn
238
+ )
239
+
240
+ if (!milestone) {
241
+ return {
242
+ success: false,
243
+ error: 'Failed to create milestone. Check GITHUB_TOKEN permissions.',
244
+ }
245
+ }
246
+
247
+ return {
248
+ success: true,
249
+ milestone: { ...milestone, completionPercentage: 0 },
250
+ message: `Created milestone #${String(milestone.number)}: ${milestone.title}`,
251
+ }
252
+ } catch (err) {
253
+ return formatHandlerError(err)
254
+ }
255
+ },
256
+ },
257
+ {
258
+ name: 'update_github_milestone',
259
+ title: 'Update GitHub Milestone',
260
+ description:
261
+ 'Update a GitHub milestone (title, description, due date, or state). Use state "closed" to close a completed milestone.',
262
+ group: 'github',
263
+ inputSchema: z.object({
264
+ milestone_number: z.number().describe('Milestone number to update'),
265
+ title: z.string().optional().describe('New title'),
266
+ description: z.string().optional().describe('New description'),
267
+ due_on: z.string().optional().describe('New due date in YYYY-MM-DD format'),
268
+ state: z.string().optional().describe('Set to "closed" to close the milestone'),
269
+ owner: z.string().optional().describe('LEAVE EMPTY to auto-detect'),
270
+ repo: z.string().optional().describe('LEAVE EMPTY to auto-detect'),
271
+ }),
272
+ outputSchema: UpdateMilestoneOutputSchema,
273
+ annotations: { readOnlyHint: false, idempotentHint: false, openWorldHint: true },
274
+ handler: async (params: unknown) => {
275
+ try {
276
+ const input = z
277
+ .object({
278
+ milestone_number: z.number(),
279
+ title: z.string().optional(),
280
+ description: z.string().optional(),
281
+ due_on: z.string().optional(),
282
+ state: z.enum(['open', 'closed']).optional(),
283
+ owner: z.string().optional(),
284
+ repo: z.string().optional(),
285
+ })
286
+ .parse(params)
287
+
288
+ const resolved = await resolveOwnerRepo(
289
+ context,
290
+ input,
291
+ 'What GitHub repository is this milestone in?'
292
+ )
293
+ if ('error' in resolved) return resolved.response
294
+
295
+ const dueOn = input.due_on ? `${input.due_on}T08:00:00Z` : undefined
296
+ const milestone = await resolved.github.updateMilestone(
297
+ resolved.owner,
298
+ resolved.repo,
299
+ input.milestone_number,
300
+ {
301
+ title: input.title,
302
+ description: input.description,
303
+ dueOn,
304
+ state: input.state,
305
+ }
306
+ )
307
+
308
+ if (!milestone) {
309
+ return {
310
+ success: false,
311
+ error: `Failed to update milestone #${String(input.milestone_number)}. Check that it exists and GITHUB_TOKEN has permissions.`,
312
+ }
313
+ }
314
+
315
+ const total = milestone.openIssues + milestone.closedIssues
316
+ const completionPercentage =
317
+ total > 0 ? Math.round((milestone.closedIssues / total) * 100) : 0
318
+
319
+ return {
320
+ success: true,
321
+ milestone: { ...milestone, completionPercentage },
322
+ message: `Updated milestone #${String(milestone.number)}: ${milestone.title}`,
323
+ }
324
+ } catch (err) {
325
+ return formatHandlerError(err)
326
+ }
327
+ },
328
+ },
329
+ {
330
+ name: 'delete_github_milestone',
331
+ title: 'Delete GitHub Milestone',
332
+ description:
333
+ 'Permanently delete a GitHub milestone. Issues assigned to the milestone will be un-assigned but not deleted.',
334
+ group: 'github',
335
+ inputSchema: z.object({
336
+ milestone_number: z.number().describe('Milestone number to delete'),
337
+ confirm: z.literal(true).describe('Must be set to true to confirm deletion'),
338
+ owner: z.string().optional().describe('LEAVE EMPTY to auto-detect'),
339
+ repo: z.string().optional().describe('LEAVE EMPTY to auto-detect'),
340
+ }),
341
+ outputSchema: DeleteMilestoneOutputSchema,
342
+ annotations: {
343
+ readOnlyHint: false,
344
+ idempotentHint: false,
345
+ destructiveHint: true,
346
+ openWorldHint: true,
347
+ },
348
+ handler: async (params: unknown) => {
349
+ try {
350
+ const input = z
351
+ .object({
352
+ milestone_number: z.number(),
353
+ confirm: z.literal(true),
354
+ owner: z.string().optional(),
355
+ repo: z.string().optional(),
356
+ })
357
+ .parse(params)
358
+
359
+ const resolved = await resolveOwnerRepo(
360
+ context,
361
+ input,
362
+ 'What GitHub repository is this milestone in?'
363
+ )
364
+ if ('error' in resolved) return resolved.response
365
+
366
+ const result = await resolved.github.deleteMilestone(
367
+ resolved.owner,
368
+ resolved.repo,
369
+ input.milestone_number
370
+ )
371
+
372
+ if (!result.success) {
373
+ return {
374
+ success: false,
375
+ milestoneNumber: input.milestone_number,
376
+ message: `Failed to delete milestone #${String(input.milestone_number)}`,
377
+ error: result.error ?? undefined,
378
+ }
379
+ }
380
+
381
+ return {
382
+ success: true,
383
+ milestoneNumber: input.milestone_number,
384
+ message: `Deleted milestone #${String(input.milestone_number)}`,
385
+ }
386
+ } catch (err) {
387
+ return formatHandlerError(err)
388
+ }
389
+ },
390
+ },
391
+ ]
392
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * GitHub Mutation Tools - Barrel file
3
+ *
4
+ * Composes kanban tools and issue tools into a single export
5
+ * for backward compatibility with existing imports.
6
+ */
7
+
8
+ import type { ToolDefinition, ToolContext } from '../../../types/index.js'
9
+ import { getKanbanTools } from './kanban-tools.js'
10
+ import { getGitHubIssueTools } from './issue-tools.js'
11
+
12
+ /**
13
+ * Get all GitHub mutation tools (kanban + issue management)
14
+ */
15
+ export function getGitHubMutationTools(context: ToolContext): ToolDefinition[] {
16
+ return [...getKanbanTools(context), ...getGitHubIssueTools(context)]
17
+ }