@commandable/integration-data 0.0.6 → 0.1.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 (231) hide show
  1. package/dist/credentials-index.d.ts.map +1 -1
  2. package/dist/credentials-index.js +130 -0
  3. package/dist/credentials-index.js.map +1 -1
  4. package/dist/index.d.ts +2 -2
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +1 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/loader.d.ts +48 -0
  9. package/dist/loader.d.ts.map +1 -1
  10. package/dist/loader.js +46 -4
  11. package/dist/loader.js.map +1 -1
  12. package/integrations/__tests__/liveHarness.ts +16 -3
  13. package/integrations/airtable/.env.test +9 -0
  14. package/integrations/airtable/.env.test.example +11 -0
  15. package/integrations/airtable/README.md +27 -0
  16. package/integrations/airtable/__tests__/get_handlers.test.ts +43 -5
  17. package/integrations/airtable/credentials.json +2 -1
  18. package/integrations/confluence/.env.test +25 -0
  19. package/integrations/confluence/.env.test.example +36 -0
  20. package/integrations/confluence/README.md +28 -0
  21. package/integrations/confluence/__tests__/get_handlers.test.ts +121 -0
  22. package/integrations/confluence/__tests__/usage_parity.test.ts +14 -0
  23. package/integrations/confluence/__tests__/write_handlers.test.ts +131 -0
  24. package/integrations/confluence/credentials.json +39 -0
  25. package/integrations/confluence/credentials_hint.md +4 -0
  26. package/integrations/confluence/credentials_hint_api_token.md +9 -0
  27. package/integrations/confluence/credentials_hint_oauth_token.md +8 -0
  28. package/integrations/confluence/handlers/add_comment.js +19 -0
  29. package/integrations/confluence/handlers/add_label.js +16 -0
  30. package/integrations/confluence/handlers/create_page.js +22 -0
  31. package/integrations/confluence/handlers/delete_page.js +17 -0
  32. package/integrations/confluence/handlers/get_comments.js +33 -0
  33. package/integrations/confluence/handlers/get_page_children.js +30 -0
  34. package/integrations/confluence/handlers/get_space.js +22 -0
  35. package/integrations/confluence/handlers/list_spaces.js +39 -0
  36. package/integrations/confluence/handlers/read_page.js +49 -0
  37. package/integrations/confluence/handlers/search_pages.js +42 -0
  38. package/integrations/confluence/handlers/update_page.js +42 -0
  39. package/integrations/confluence/manifest.json +85 -0
  40. package/integrations/confluence/prompt.md +55 -0
  41. package/integrations/confluence/schemas/add_comment.json +22 -0
  42. package/integrations/confluence/schemas/add_label.json +19 -0
  43. package/integrations/confluence/schemas/create_page.json +33 -0
  44. package/integrations/confluence/schemas/delete_page.json +23 -0
  45. package/integrations/confluence/schemas/empty.json +6 -0
  46. package/integrations/confluence/schemas/get_comments.json +24 -0
  47. package/integrations/confluence/schemas/get_page_children.json +28 -0
  48. package/integrations/confluence/schemas/get_space.json +18 -0
  49. package/integrations/confluence/schemas/list_spaces.json +36 -0
  50. package/integrations/confluence/schemas/read_page.json +28 -0
  51. package/integrations/confluence/schemas/search_pages.json +26 -0
  52. package/integrations/confluence/schemas/update_page.json +31 -0
  53. package/integrations/github/.env.test +16 -0
  54. package/integrations/github/.env.test.example +17 -0
  55. package/integrations/github/README.md +75 -0
  56. package/integrations/github/__tests__/get_handlers.test.ts +5 -5
  57. package/integrations/github/__tests__/write_handlers.test.ts +176 -58
  58. package/integrations/github/credentials.json +4 -2
  59. package/integrations/github/handlers/create_file.js +46 -0
  60. package/integrations/github/handlers/delete_file.js +14 -1
  61. package/integrations/github/handlers/edit_file.js +52 -0
  62. package/integrations/github/handlers/edit_files.js +107 -0
  63. package/integrations/github/manifest.json +74 -47
  64. package/integrations/github/prompt.md +36 -0
  65. package/integrations/github/schemas/create_file.json +13 -0
  66. package/integrations/github/schemas/delete_file.json +2 -2
  67. package/integrations/github/schemas/edit_file.json +26 -0
  68. package/integrations/github/schemas/edit_files.json +39 -0
  69. package/integrations/google-calendar/.env.test.example +11 -0
  70. package/integrations/google-calendar/README.md +41 -0
  71. package/integrations/google-calendar/__tests__/write_and_admin_handlers.test.ts +7 -7
  72. package/integrations/google-calendar/credentials.json +4 -2
  73. package/integrations/google-calendar/credentials_hint.md +1 -1
  74. package/integrations/google-calendar/manifest.json +27 -17
  75. package/integrations/google-docs/README.md +30 -0
  76. package/integrations/google-docs/credentials_hint.md +1 -1
  77. package/integrations/google-drive/README.md +26 -0
  78. package/integrations/google-drive/credentials.json +4 -2
  79. package/integrations/google-gmail/.env.test.example +11 -0
  80. package/integrations/google-gmail/README.md +49 -0
  81. package/integrations/google-gmail/credentials.json +4 -2
  82. package/integrations/google-gmail/handlers/create_draft_email.js +1 -1
  83. package/integrations/google-gmail/handlers/read_email.js +1 -1
  84. package/integrations/google-gmail/handlers/send_email.js +1 -1
  85. package/integrations/google-gmail/manifest.json +36 -25
  86. package/integrations/google-sheet/README.md +27 -0
  87. package/integrations/google-sheet/credentials_hint.md +1 -1
  88. package/integrations/google-slides/README.md +28 -0
  89. package/integrations/google-slides/credentials_hint.md +1 -1
  90. package/integrations/hubspot/.env.test.example +20 -0
  91. package/integrations/hubspot/README.md +48 -0
  92. package/integrations/hubspot/__tests__/get_handlers.test.ts +151 -0
  93. package/integrations/hubspot/__tests__/usage_parity.test.ts +10 -0
  94. package/integrations/hubspot/__tests__/write_handlers.test.ts +244 -0
  95. package/integrations/hubspot/credentials.json +50 -0
  96. package/integrations/hubspot/credentials_hint.md +20 -0
  97. package/integrations/hubspot/credentials_hint_oauth_token.md +16 -0
  98. package/integrations/hubspot/handlers/archive_company.js +13 -0
  99. package/integrations/hubspot/handlers/archive_contact.js +13 -0
  100. package/integrations/hubspot/handlers/archive_deal.js +13 -0
  101. package/integrations/hubspot/handlers/archive_ticket.js +13 -0
  102. package/integrations/hubspot/handlers/create_association.js +18 -0
  103. package/integrations/hubspot/handlers/create_company.js +13 -0
  104. package/integrations/hubspot/handlers/create_contact.js +14 -0
  105. package/integrations/hubspot/handlers/create_deal.js +16 -0
  106. package/integrations/hubspot/handlers/create_note.js +44 -0
  107. package/integrations/hubspot/handlers/create_task.js +48 -0
  108. package/integrations/hubspot/handlers/create_ticket.js +15 -0
  109. package/integrations/hubspot/handlers/get_associations.js +14 -0
  110. package/integrations/hubspot/handlers/get_company.js +18 -0
  111. package/integrations/hubspot/handlers/get_contact.js +18 -0
  112. package/integrations/hubspot/handlers/get_deal.js +18 -0
  113. package/integrations/hubspot/handlers/get_ticket.js +20 -0
  114. package/integrations/hubspot/handlers/list_owners.js +12 -0
  115. package/integrations/hubspot/handlers/list_pipelines.js +5 -0
  116. package/integrations/hubspot/handlers/list_properties.js +11 -0
  117. package/integrations/hubspot/handlers/remove_association.js +22 -0
  118. package/integrations/hubspot/handlers/search_companies.js +43 -0
  119. package/integrations/hubspot/handlers/search_contacts.js +43 -0
  120. package/integrations/hubspot/handlers/search_deals.js +43 -0
  121. package/integrations/hubspot/handlers/search_notes.js +43 -0
  122. package/integrations/hubspot/handlers/search_tasks.js +43 -0
  123. package/integrations/hubspot/handlers/search_tickets.js +43 -0
  124. package/integrations/hubspot/handlers/update_company.js +13 -0
  125. package/integrations/hubspot/handlers/update_contact.js +14 -0
  126. package/integrations/hubspot/handlers/update_deal.js +16 -0
  127. package/integrations/hubspot/handlers/update_task.js +17 -0
  128. package/integrations/hubspot/handlers/update_ticket.js +15 -0
  129. package/integrations/hubspot/manifest.json +230 -0
  130. package/integrations/hubspot/prompt.md +69 -0
  131. package/integrations/hubspot/schemas/archive_company.json +13 -0
  132. package/integrations/hubspot/schemas/archive_contact.json +13 -0
  133. package/integrations/hubspot/schemas/archive_deal.json +9 -0
  134. package/integrations/hubspot/schemas/archive_ticket.json +9 -0
  135. package/integrations/hubspot/schemas/create_association.json +24 -0
  136. package/integrations/hubspot/schemas/create_company.json +14 -0
  137. package/integrations/hubspot/schemas/create_contact.json +15 -0
  138. package/integrations/hubspot/schemas/create_deal.json +20 -0
  139. package/integrations/hubspot/schemas/create_note.json +37 -0
  140. package/integrations/hubspot/schemas/create_task.json +51 -0
  141. package/integrations/hubspot/schemas/create_ticket.json +16 -0
  142. package/integrations/hubspot/schemas/empty.json +6 -0
  143. package/integrations/hubspot/schemas/get_associations.json +30 -0
  144. package/integrations/hubspot/schemas/get_company.json +27 -0
  145. package/integrations/hubspot/schemas/get_contact.json +27 -0
  146. package/integrations/hubspot/schemas/get_deal.json +20 -0
  147. package/integrations/hubspot/schemas/get_ticket.json +20 -0
  148. package/integrations/hubspot/schemas/list_owners.json +25 -0
  149. package/integrations/hubspot/schemas/list_pipelines.json +13 -0
  150. package/integrations/hubspot/schemas/list_properties.json +17 -0
  151. package/integrations/hubspot/schemas/remove_association.json +24 -0
  152. package/integrations/hubspot/schemas/search_companies.json +56 -0
  153. package/integrations/hubspot/schemas/search_contacts.json +56 -0
  154. package/integrations/hubspot/schemas/search_deals.json +43 -0
  155. package/integrations/hubspot/schemas/search_notes.json +43 -0
  156. package/integrations/hubspot/schemas/search_tasks.json +43 -0
  157. package/integrations/hubspot/schemas/search_tickets.json +43 -0
  158. package/integrations/hubspot/schemas/update_company.json +20 -0
  159. package/integrations/hubspot/schemas/update_contact.json +21 -0
  160. package/integrations/hubspot/schemas/update_deal.json +19 -0
  161. package/integrations/hubspot/schemas/update_task.json +31 -0
  162. package/integrations/hubspot/schemas/update_ticket.json +18 -0
  163. package/integrations/jira/.env.test +46 -0
  164. package/integrations/jira/.env.test.example +41 -0
  165. package/integrations/jira/README.md +46 -0
  166. package/integrations/jira/__tests__/get_handlers.test.ts +193 -0
  167. package/integrations/jira/__tests__/usage_parity.test.ts +14 -0
  168. package/integrations/jira/__tests__/write_handlers.test.ts +157 -0
  169. package/integrations/jira/credentials.json +39 -0
  170. package/integrations/jira/credentials_hint.md +4 -0
  171. package/integrations/jira/credentials_hint_api_token.md +6 -0
  172. package/integrations/jira/credentials_hint_oauth_token.md +6 -0
  173. package/integrations/jira/handlers/add_comment.js +9 -0
  174. package/integrations/jira/handlers/assign_issue.js +11 -0
  175. package/integrations/jira/handlers/create_issue.js +37 -0
  176. package/integrations/jira/handlers/create_sprint.js +19 -0
  177. package/integrations/jira/handlers/delete_issue.js +10 -0
  178. package/integrations/jira/handlers/get_backlog_issues.js +13 -0
  179. package/integrations/jira/handlers/get_board.js +6 -0
  180. package/integrations/jira/handlers/get_issue.js +63 -0
  181. package/integrations/jira/handlers/get_issue_comments.js +31 -0
  182. package/integrations/jira/handlers/get_myself.js +14 -0
  183. package/integrations/jira/handlers/get_project.js +28 -0
  184. package/integrations/jira/handlers/get_sprint.js +5 -0
  185. package/integrations/jira/handlers/get_sprint_issues.js +13 -0
  186. package/integrations/jira/handlers/get_transitions.js +23 -0
  187. package/integrations/jira/handlers/list_boards.js +34 -0
  188. package/integrations/jira/handlers/list_projects.js +29 -0
  189. package/integrations/jira/handlers/list_sprints.js +29 -0
  190. package/integrations/jira/handlers/move_issues_to_sprint.js +11 -0
  191. package/integrations/jira/handlers/search_issues.js +43 -0
  192. package/integrations/jira/handlers/search_users.js +21 -0
  193. package/integrations/jira/handlers/transition_issue.js +44 -0
  194. package/integrations/jira/handlers/update_issue.js +40 -0
  195. package/integrations/jira/handlers/update_sprint.js +20 -0
  196. package/integrations/jira/manifest.json +204 -0
  197. package/integrations/jira/prompt.md +80 -0
  198. package/integrations/jira/schemas/add_comment.json +16 -0
  199. package/integrations/jira/schemas/assign_issue.json +16 -0
  200. package/integrations/jira/schemas/create_issue.json +49 -0
  201. package/integrations/jira/schemas/create_sprint.json +29 -0
  202. package/integrations/jira/schemas/delete_issue.json +12 -0
  203. package/integrations/jira/schemas/empty.json +6 -0
  204. package/integrations/jira/schemas/get_backlog_issues.json +33 -0
  205. package/integrations/jira/schemas/get_board.json +13 -0
  206. package/integrations/jira/schemas/get_issue.json +23 -0
  207. package/integrations/jira/schemas/get_issue_comments.json +23 -0
  208. package/integrations/jira/schemas/get_project.json +17 -0
  209. package/integrations/jira/schemas/get_sprint.json +13 -0
  210. package/integrations/jira/schemas/get_sprint_issues.json +33 -0
  211. package/integrations/jira/schemas/get_transitions.json +12 -0
  212. package/integrations/jira/schemas/list_boards.json +27 -0
  213. package/integrations/jira/schemas/list_projects.json +22 -0
  214. package/integrations/jira/schemas/list_sprints.json +29 -0
  215. package/integrations/jira/schemas/move_issues_to_sprint.json +19 -0
  216. package/integrations/jira/schemas/search_issues.json +28 -0
  217. package/integrations/jira/schemas/search_users.json +18 -0
  218. package/integrations/jira/schemas/transition_issue.json +38 -0
  219. package/integrations/jira/schemas/update_issue.json +47 -0
  220. package/integrations/jira/schemas/update_sprint.json +33 -0
  221. package/integrations/new_integration_prompt.md +173 -2
  222. package/integrations/notion/.env.test +10 -0
  223. package/integrations/notion/.env.test.example +13 -0
  224. package/integrations/notion/README.md +42 -0
  225. package/integrations/notion/credentials.json +2 -1
  226. package/integrations/notion/manifest.json +64 -35
  227. package/integrations/trello/.env.test +6 -0
  228. package/integrations/trello/.env.test.example +9 -0
  229. package/integrations/trello/README.md +50 -0
  230. package/integrations/trello/credentials.json +2 -1
  231. package/package.json +7 -3
@@ -0,0 +1,107 @@
1
+ async (input) => {
2
+ const { owner, repo, branch, message, files } = input
3
+
4
+ // Helper: decode base64 GitHub content to UTF-8
5
+ function decodeContent(b64Raw) {
6
+ const b64 = b64Raw.replace(/\n/g, '')
7
+ return decodeURIComponent(
8
+ atob(b64).split('').map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)).join('')
9
+ )
10
+ }
11
+
12
+ // Helper: apply search/replace edits to text
13
+ function applyEdits(text, edits, filePath) {
14
+ let result = text
15
+ for (let i = 0; i < edits.length; i++) {
16
+ const { old_text, new_text } = edits[i]
17
+ const idx = result.indexOf(old_text)
18
+ if (idx === -1) {
19
+ throw new Error(
20
+ `Edit ${i + 1}/${edits.length} failed on ${filePath}: old_text not found. `
21
+ + 'Ensure the search text matches exactly, including whitespace and indentation. '
22
+ + 'Use get_file_contents to verify the current content.'
23
+ )
24
+ }
25
+ result = result.substring(0, idx) + new_text + result.substring(idx + old_text.length)
26
+ }
27
+ return result
28
+ }
29
+
30
+ // 1. Get the current commit SHA for the branch
31
+ const refRes = await integration.fetch(`/repos/${owner}/${repo}/git/refs/heads/${branch}`)
32
+ const refData = await refRes.json()
33
+ const currentCommitSha = refData.object.sha
34
+
35
+ // 2. Get the current commit to find its tree
36
+ const commitRes = await integration.fetch(`/repos/${owner}/${repo}/git/commits/${currentCommitSha}`)
37
+ const commitData = await commitRes.json()
38
+ const currentTreeSha = commitData.tree.sha
39
+
40
+ // 3. Resolve final content for each file
41
+ const tree = []
42
+ for (const file of files) {
43
+ if (file.action === 'delete') {
44
+ tree.push({ path: file.path, mode: '100644', type: 'blob', sha: null })
45
+ continue
46
+ }
47
+
48
+ let finalContent
49
+ if (file.action === 'edit') {
50
+ if (!file.edits || file.edits.length === 0) {
51
+ throw new Error(`File ${file.path} has action 'edit' but no edits provided.`)
52
+ }
53
+ const params = new URLSearchParams()
54
+ params.set('ref', branch)
55
+ const fileRes = await integration.fetch(`/repos/${owner}/${repo}/contents/${file.path}?${params.toString()}`)
56
+ const fileData = await fileRes.json()
57
+ if (!fileData || !fileData.content) {
58
+ throw new Error(`File not found: ${file.path}. Use get_repo_tree to discover file paths.`)
59
+ }
60
+ const currentContent = decodeContent(fileData.content)
61
+ finalContent = applyEdits(currentContent, file.edits, file.path)
62
+ } else {
63
+ // action === 'create'
64
+ if (file.content === undefined || file.content === null) {
65
+ throw new Error(`File ${file.path} has action 'create' but no content provided.`)
66
+ }
67
+ finalContent = file.content
68
+ }
69
+
70
+ // Create blob
71
+ const blobRes = await integration.fetch(`/repos/${owner}/${repo}/git/blobs`, {
72
+ method: 'POST',
73
+ body: { content: finalContent, encoding: 'utf-8' },
74
+ })
75
+ const blobData = await blobRes.json()
76
+ tree.push({ path: file.path, mode: '100644', type: 'blob', sha: blobData.sha })
77
+ }
78
+
79
+ // 4. Create a new tree
80
+ const treeRes = await integration.fetch(`/repos/${owner}/${repo}/git/trees`, {
81
+ method: 'POST',
82
+ body: { base_tree: currentTreeSha, tree: tree },
83
+ })
84
+ const treeData = await treeRes.json()
85
+
86
+ // 5. Create the commit
87
+ const newCommitRes = await integration.fetch(`/repos/${owner}/${repo}/git/commits`, {
88
+ method: 'POST',
89
+ body: { message: message, tree: treeData.sha, parents: [currentCommitSha] },
90
+ })
91
+ const newCommitData = await newCommitRes.json()
92
+
93
+ // 6. Update the branch reference
94
+ await integration.fetch(`/repos/${owner}/${repo}/git/refs/heads/${branch}`, {
95
+ method: 'PATCH',
96
+ body: { sha: newCommitData.sha },
97
+ })
98
+
99
+ return {
100
+ commit: {
101
+ sha: newCommitData.sha,
102
+ message: newCommitData.message,
103
+ url: newCommitData.html_url,
104
+ },
105
+ files: files.map(f => ({ path: f.path, action: f.action })),
106
+ }
107
+ }
@@ -1,64 +1,91 @@
1
1
  {
2
2
  "name": "github",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
+ "toolsets": {
5
+ "code": {
6
+ "label": "Code & Files",
7
+ "description": "Read, search, and manage repository code and branches"
8
+ },
9
+ "issues": {
10
+ "label": "Issues",
11
+ "description": "Create, search, and manage GitHub issues"
12
+ },
13
+ "pull_requests": {
14
+ "label": "Pull Requests",
15
+ "description": "Create, review, and merge pull requests"
16
+ },
17
+ "ci": {
18
+ "label": "CI / Actions",
19
+ "description": "Monitor GitHub Actions workflows and debug failures"
20
+ },
21
+ "releases": {
22
+ "label": "Releases & Tags",
23
+ "description": "Manage releases and view tags"
24
+ },
25
+ "repo_admin": {
26
+ "label": "Repository Management",
27
+ "description": "Create, delete, fork, and discover repositories"
28
+ }
29
+ },
4
30
  "tools": [
5
- { "name": "get_me", "description": "Get the authenticated user's profile. Use this to find out who you are authenticated as before performing operations.", "inputSchema": "schemas/empty.json", "handler": "handlers/get_me.js", "scope": "read" },
6
- { "name": "list_repos", "description": "List repositories for the authenticated user.", "inputSchema": "schemas/empty.json", "handler": "handlers/list_repos_user.js", "scope": "read" },
7
- { "name": "get_repo", "description": "Get details for a repository (description, default branch, visibility, topics, stats).", "inputSchema": "schemas/get_repo.json", "handler": "handlers/get_repo.js", "scope": "read" },
8
- { "name": "search_repos", "description": "Search GitHub repositories. Supports stars, forks, language, topic, and user filters (e.g. 'topic:react stars:>1000 language:javascript'). Use this to discover repos.", "inputSchema": "schemas/search_repos.json", "handler": "handlers/search_repos.js", "scope": "read" },
31
+ { "name": "get_me", "description": "Get the authenticated user's profile. Use this to find out who you are authenticated as before performing operations.", "inputSchema": "schemas/empty.json", "handler": "handlers/get_me.js", "scope": "read", "toolset": "repo_admin" },
32
+ { "name": "list_repos", "description": "List repositories for the authenticated user.", "inputSchema": "schemas/empty.json", "handler": "handlers/list_repos_user.js", "scope": "read", "toolset": "repo_admin" },
33
+ { "name": "get_repo", "description": "Get details for a repository (description, default branch, visibility, topics, stats).", "inputSchema": "schemas/get_repo.json", "handler": "handlers/get_repo.js", "scope": "read", "toolset": "code" },
34
+ { "name": "search_repos", "description": "Search GitHub repositories. Supports stars, forks, language, topic, and user filters (e.g. 'topic:react stars:>1000 language:javascript'). Use this to discover repos.", "inputSchema": "schemas/search_repos.json", "handler": "handlers/search_repos.js", "scope": "read", "toolset": "repo_admin" },
9
35
 
10
- { "name": "get_file_contents", "description": "Get the content of a file from a repository. Returns decoded UTF-8 text. Use ref to read from a specific branch, tag, or commit. Call get_repo_tree first to discover file paths.", "inputSchema": "schemas/get_file_contents.json", "handler": "handlers/get_file_contents.js", "scope": "read" },
11
- { "name": "get_repo_tree", "description": "Get the full file/directory tree of a repository. Returns all paths and types. Use path_filter to scope to a subdirectory (e.g. 'src/'). Use this before get_file_contents to discover what files exist.", "inputSchema": "schemas/get_repo_tree.json", "handler": "handlers/get_repo_tree.js", "scope": "read" },
12
- { "name": "search_code", "description": "Search for code across GitHub repositories using GitHub's code search syntax. Examples: 'useState language:typescript repo:facebook/react', 'console.error path:src/'. Returns file paths and matched fragments.", "inputSchema": "schemas/search_code.json", "handler": "handlers/search_code.js", "scope": "read" },
36
+ { "name": "get_file_contents", "description": "Get the content of a file from a repository. Returns decoded UTF-8 text. Use ref to read from a specific branch, tag, or commit. Call get_repo_tree first to discover file paths.", "inputSchema": "schemas/get_file_contents.json", "handler": "handlers/get_file_contents.js", "scope": "read", "toolset": "code" },
37
+ { "name": "get_repo_tree", "description": "Get the full file/directory tree of a repository. Returns all paths and types. Use path_filter to scope to a subdirectory (e.g. 'src/'). Use this before get_file_contents to discover what files exist.", "inputSchema": "schemas/get_repo_tree.json", "handler": "handlers/get_repo_tree.js", "scope": "read", "toolset": "code" },
38
+ { "name": "search_code", "description": "Search for code across GitHub repositories using GitHub's code search syntax. Examples: 'useState language:typescript repo:facebook/react', 'console.error path:src/'. Returns file paths and matched fragments.", "inputSchema": "schemas/search_code.json", "handler": "handlers/search_code.js", "scope": "read", "toolset": "code" },
13
39
 
14
- { "name": "list_branches", "description": "List branches in a repository. Supports pagination and filtering by protection status.", "inputSchema": "schemas/list_branches.json", "handler": "handlers/list_branches.js", "scope": "read" },
15
- { "name": "list_commits", "description": "List commits for a repository. Filter by branch/tag (sha), file path, or author. Paginate with page/per_page.", "inputSchema": "schemas/list_commits.json", "handler": "handlers/list_commits.js", "scope": "read" },
16
- { "name": "get_commit", "description": "Get the full details of a specific commit including its message, author, file changes, and diff stats.", "inputSchema": "schemas/get_commit.json", "handler": "handlers/get_commit.js", "scope": "read" },
17
- { "name": "list_tags", "description": "List tags for a repository. Use this to see available versions before creating a release.", "inputSchema": "schemas/list_tags.json", "handler": "handlers/list_tags.js", "scope": "read" },
40
+ { "name": "list_branches", "description": "List branches in a repository. Supports pagination and filtering by protection status.", "inputSchema": "schemas/list_branches.json", "handler": "handlers/list_branches.js", "scope": "read", "toolset": "code" },
41
+ { "name": "list_commits", "description": "List commits for a repository. Filter by branch/tag (sha), file path, or author. Paginate with page/per_page.", "inputSchema": "schemas/list_commits.json", "handler": "handlers/list_commits.js", "scope": "read", "toolset": "code" },
42
+ { "name": "get_commit", "description": "Get the full details of a specific commit including its message, author, file changes, and diff stats.", "inputSchema": "schemas/get_commit.json", "handler": "handlers/get_commit.js", "scope": "read", "toolset": "code" },
43
+ { "name": "list_tags", "description": "List tags for a repository. Use this to see available versions before creating a release.", "inputSchema": "schemas/list_tags.json", "handler": "handlers/list_tags.js", "scope": "read", "toolset": "code" },
18
44
 
19
- { "name": "list_issues", "description": "List issues for a repository. Filter by state (open/closed/all), labels (comma-separated), and assignee. Paginate with page/per_page. Note: this also returns pull requests; use search_issues to exclude them.", "inputSchema": "schemas/list_issues.json", "handler": "handlers/list_issues.js", "scope": "read" },
20
- { "name": "get_issue", "description": "Get full details of a specific issue including its body, labels, assignees, and milestone.", "inputSchema": "schemas/get_issue.json", "handler": "handlers/get_issue.js", "scope": "read" },
21
- { "name": "list_issue_comments", "description": "List all comments on an issue. Use this to read the full discussion thread before replying.", "inputSchema": "schemas/list_issue_comments.json", "handler": "handlers/list_issue_comments.js", "scope": "read" },
22
- { "name": "search_issues", "description": "Search issues using GitHub search syntax (e.g. 'is:open is:issue label:bug repo:owner/repo', 'is:issue no:assignee milestone:v2.0'). More powerful than list_issues for finding specific issues.", "inputSchema": "schemas/search_issues.json", "handler": "handlers/search_issues.js", "scope": "read" },
23
- { "name": "list_labels", "description": "List all labels available in a repository. Call this before add_labels_to_issue to see which labels exist.", "inputSchema": "schemas/list_labels.json", "handler": "handlers/list_labels.js", "scope": "read" },
45
+ { "name": "list_issues", "description": "List issues for a repository. Filter by state (open/closed/all), labels (comma-separated), and assignee. Paginate with page/per_page. Note: this also returns pull requests; use search_issues to exclude them.", "inputSchema": "schemas/list_issues.json", "handler": "handlers/list_issues.js", "scope": "read", "toolset": "issues" },
46
+ { "name": "get_issue", "description": "Get full details of a specific issue including its body, labels, assignees, and milestone.", "inputSchema": "schemas/get_issue.json", "handler": "handlers/get_issue.js", "scope": "read", "toolset": "issues" },
47
+ { "name": "list_issue_comments", "description": "List all comments on an issue. Use this to read the full discussion thread before replying.", "inputSchema": "schemas/list_issue_comments.json", "handler": "handlers/list_issue_comments.js", "scope": "read", "toolset": "issues" },
48
+ { "name": "search_issues", "description": "Search issues using GitHub search syntax (e.g. 'is:open is:issue label:bug repo:owner/repo', 'is:issue no:assignee milestone:v2.0'). More powerful than list_issues for finding specific issues.", "inputSchema": "schemas/search_issues.json", "handler": "handlers/search_issues.js", "scope": "read", "toolset": "issues" },
49
+ { "name": "list_labels", "description": "List all labels available in a repository. Call this before add_labels_to_issue to see which labels exist.", "inputSchema": "schemas/list_labels.json", "handler": "handlers/list_labels.js", "scope": "read", "toolset": "issues" },
24
50
 
25
- { "name": "list_pull_requests", "description": "List pull requests for a repository. Filter by state, head branch, base branch. Sort and paginate results.", "inputSchema": "schemas/list_pull_requests.json", "handler": "handlers/list_pull_requests.js", "scope": "read" },
26
- { "name": "get_pull_request", "description": "Get full details of a specific pull request including title, body, state, merge status, head/base refs, reviewers, and labels.", "inputSchema": "schemas/get_pull_request.json", "handler": "handlers/get_pull_request.js", "scope": "read" },
27
- { "name": "get_pull_request_diff", "description": "Get the raw unified diff for a pull request. Returns the complete diff of all changes. For per-file details, use list_pull_request_files instead.", "inputSchema": "schemas/get_pull_request_diff.json", "handler": "handlers/get_pull_request_diff.js", "scope": "read" },
28
- { "name": "list_pull_request_files", "description": "List the files changed in a pull request with their status (added/modified/deleted) and patch diff per file. Essential for code review.", "inputSchema": "schemas/list_pull_request_files.json", "handler": "handlers/list_pull_request_files.js", "scope": "read" },
29
- { "name": "list_pull_request_comments", "description": "List inline review comments on a pull request (comments attached to specific lines of code).", "inputSchema": "schemas/list_pull_request_comments.json", "handler": "handlers/list_pull_request_comments.js", "scope": "read" },
30
- { "name": "search_pull_requests", "description": "Search pull requests using GitHub search syntax. Use 'is:pr' to scope to PRs (e.g. 'is:pr is:open author:octocat', 'is:pr review:required label:bug'). Returns matching PRs across repos.", "inputSchema": "schemas/search_pull_requests.json", "handler": "handlers/search_pull_requests.js", "scope": "read" },
51
+ { "name": "list_pull_requests", "description": "List pull requests for a repository. Filter by state, head branch, base branch. Sort and paginate results.", "inputSchema": "schemas/list_pull_requests.json", "handler": "handlers/list_pull_requests.js", "scope": "read", "toolset": "pull_requests" },
52
+ { "name": "get_pull_request", "description": "Get full details of a specific pull request including title, body, state, merge status, head/base refs, reviewers, and labels.", "inputSchema": "schemas/get_pull_request.json", "handler": "handlers/get_pull_request.js", "scope": "read", "toolset": "pull_requests" },
53
+ { "name": "get_pull_request_diff", "description": "Get the raw unified diff for a pull request. Returns the complete diff of all changes. For per-file details, use list_pull_request_files instead.", "inputSchema": "schemas/get_pull_request_diff.json", "handler": "handlers/get_pull_request_diff.js", "scope": "read", "toolset": "pull_requests" },
54
+ { "name": "list_pull_request_files", "description": "List the files changed in a pull request with their status (added/modified/deleted) and patch diff per file. Essential for code review.", "inputSchema": "schemas/list_pull_request_files.json", "handler": "handlers/list_pull_request_files.js", "scope": "read", "toolset": "pull_requests" },
55
+ { "name": "list_pull_request_comments", "description": "List inline review comments on a pull request (comments attached to specific lines of code).", "inputSchema": "schemas/list_pull_request_comments.json", "handler": "handlers/list_pull_request_comments.js", "scope": "read", "toolset": "pull_requests" },
56
+ { "name": "search_pull_requests", "description": "Search pull requests using GitHub search syntax. Use 'is:pr' to scope to PRs (e.g. 'is:pr is:open author:octocat', 'is:pr review:required label:bug'). Returns matching PRs across repos.", "inputSchema": "schemas/search_pull_requests.json", "handler": "handlers/search_pull_requests.js", "scope": "read", "toolset": "pull_requests" },
31
57
 
32
- { "name": "list_releases", "description": "List all releases for a repository, newest first.", "inputSchema": "schemas/list_releases.json", "handler": "handlers/list_releases.js", "scope": "read" },
33
- { "name": "get_latest_release", "description": "Get the latest published release for a repository. Use this to quickly check the current version.", "inputSchema": "schemas/owner_repo.json", "handler": "handlers/get_latest_release.js", "scope": "read" },
58
+ { "name": "list_releases", "description": "List all releases for a repository, newest first.", "inputSchema": "schemas/list_releases.json", "handler": "handlers/list_releases.js", "scope": "read", "toolset": "releases" },
59
+ { "name": "get_latest_release", "description": "Get the latest published release for a repository. Use this to quickly check the current version.", "inputSchema": "schemas/owner_repo.json", "handler": "handlers/get_latest_release.js", "scope": "read", "toolset": "releases" },
34
60
 
35
- { "name": "list_workflow_runs", "description": "List GitHub Actions workflow runs for a repository. Filter by branch, status (e.g. 'failure', 'success'), or triggering event. Use this to check CI status.", "inputSchema": "schemas/list_workflow_runs.json", "handler": "handlers/list_workflow_runs.js", "scope": "read" },
36
- { "name": "get_workflow_run", "description": "Get details of a specific GitHub Actions workflow run including its status, conclusion, timing, and associated commit.", "inputSchema": "schemas/get_workflow_run.json", "handler": "handlers/get_workflow_run.js", "scope": "read" },
37
- { "name": "get_job_logs", "description": "Get the log output for a specific GitHub Actions workflow job. Use this to diagnose CI failures. Get job_id from the GitHub Actions UI or the jobs list of a workflow run.", "inputSchema": "schemas/get_job_logs.json", "handler": "handlers/get_job_logs.js", "scope": "read" },
61
+ { "name": "list_workflow_runs", "description": "List GitHub Actions workflow runs for a repository. Filter by branch, status (e.g. 'failure', 'success'), or triggering event. Use this to check CI status.", "inputSchema": "schemas/list_workflow_runs.json", "handler": "handlers/list_workflow_runs.js", "scope": "read", "toolset": "ci" },
62
+ { "name": "get_workflow_run", "description": "Get details of a specific GitHub Actions workflow run including its status, conclusion, timing, and associated commit.", "inputSchema": "schemas/get_workflow_run.json", "handler": "handlers/get_workflow_run.js", "scope": "read", "toolset": "ci" },
63
+ { "name": "get_job_logs", "description": "Get the log output for a specific GitHub Actions workflow job. Use this to diagnose CI failures. Get job_id from the GitHub Actions UI or the jobs list of a workflow run.", "inputSchema": "schemas/get_job_logs.json", "handler": "handlers/get_job_logs.js", "scope": "read", "toolset": "ci" },
38
64
 
39
- { "name": "create_repo", "description": "Create a new GitHub repository under the authenticated user's account.", "inputSchema": "schemas/create_repo.json", "handler": "handlers/create_repo.js", "scope": "write", "credentialVariants": ["classic_pat"] },
40
- { "name": "delete_repo", "description": "Permanently delete a repository. This is irreversible. Requires the delete_repo scope on classic PATs.", "inputSchema": "schemas/delete_repo.json", "handler": "handlers/delete_repo.js", "scope": "write", "credentialVariants": ["classic_pat"] },
41
- { "name": "fork_repo", "description": "Fork a repository into your account or an organization. The fork is created asynchronously; the response returns immediately with the new repo details.", "inputSchema": "schemas/fork_repo.json", "handler": "handlers/fork_repo.js", "scope": "write" },
65
+ { "name": "create_repo", "description": "Create a new GitHub repository under the authenticated user's account.", "inputSchema": "schemas/create_repo.json", "handler": "handlers/create_repo.js", "scope": "write", "credentialVariants": ["classic_pat"], "toolset": "repo_admin" },
66
+ { "name": "delete_repo", "description": "Permanently delete a repository. This is irreversible. Requires the delete_repo scope on classic PATs.", "inputSchema": "schemas/delete_repo.json", "handler": "handlers/delete_repo.js", "scope": "write", "credentialVariants": ["classic_pat"], "toolset": "repo_admin" },
67
+ { "name": "fork_repo", "description": "Fork a repository into your account or an organization. The fork is created asynchronously; the response returns immediately with the new repo details.", "inputSchema": "schemas/fork_repo.json", "handler": "handlers/fork_repo.js", "scope": "write", "toolset": "repo_admin" },
42
68
 
43
- { "name": "create_branch", "description": "Create a new branch in a repository, branching from the repo's default branch by default.", "inputSchema": "schemas/create_branch.json", "handler": "handlers/create_branch.js", "scope": "write" },
44
- { "name": "delete_branch", "description": "Delete a branch. Typically used after a pull request is merged. Use list_branches to find the branch name first.", "inputSchema": "schemas/delete_branch.json", "handler": "handlers/delete_branch.js", "scope": "write" },
69
+ { "name": "create_branch", "description": "Create a new branch in a repository, branching from the repo's default branch by default.", "inputSchema": "schemas/create_branch.json", "handler": "handlers/create_branch.js", "scope": "write", "toolset": "code" },
70
+ { "name": "delete_branch", "description": "Delete a branch. Typically used after a pull request is merged. Use list_branches to find the branch name first.", "inputSchema": "schemas/delete_branch.json", "handler": "handlers/delete_branch.js", "scope": "write", "toolset": "code" },
45
71
 
46
- { "name": "create_or_update_file", "description": "Create or update a single file in a repository. Content must be plain text (base64 encoding is handled internally). Provide sha when updating an existing file (get it from get_file_contents).", "inputSchema": "schemas/create_or_update_file.json", "handler": "handlers/create_or_update_file.js", "scope": "write" },
47
- { "name": "delete_file", "description": "Delete a file from a repository. Requires the file's blob SHA (get it from get_file_contents). Creates a commit with the deletion.", "inputSchema": "schemas/delete_file.json", "handler": "handlers/delete_file.js", "scope": "write" },
48
- { "name": "create_commit", "description": "Create a commit with multiple file changes in a single operation. Supports adding, modifying, and deleting files atomically. Content must be plain text (base64 handled internally). Omit content to delete a file.", "inputSchema": "schemas/create_commit.json", "handler": "handlers/create_commit.js", "scope": "write" },
72
+ { "name": "edit_file", "description": "Edit a file using search/replace. Fetches the file, applies edits, and commits the result. Each old_text must match the file content exactly, including whitespace and indentation. Use get_file_contents to verify content before editing. For multi-file atomic changes, use edit_files instead.", "inputSchema": "schemas/edit_file.json", "handler": "handlers/edit_file.js", "scope": "write", "toolset": "code" },
73
+ { "name": "edit_files", "description": "Create, edit, and delete multiple files in a single atomic commit. Use action 'create' with content for new files, 'edit' with old_text/new_text search/replace pairs for existing files, 'delete' to remove files. All changes are committed together. For single-file edits, use edit_file instead.", "inputSchema": "schemas/edit_files.json", "handler": "handlers/edit_files.js", "scope": "write", "toolset": "code" },
74
+ { "name": "create_file", "description": "Create a new file or overwrite an existing file's content in a single commit. Handles SHA resolution internally -- no need to fetch the file first. For partial edits to existing files, use edit_file instead.", "inputSchema": "schemas/create_file.json", "handler": "handlers/create_file.js", "scope": "write", "toolset": "code" },
75
+ { "name": "delete_file", "description": "Delete a file from a repository. The file's SHA is fetched automatically. Creates a commit with the deletion.", "inputSchema": "schemas/delete_file.json", "handler": "handlers/delete_file.js", "scope": "write", "toolset": "code" },
49
76
 
50
- { "name": "create_pull_request", "description": "Open a new pull request from a head branch into a base branch.", "inputSchema": "schemas/create_pull_request.json", "handler": "handlers/create_pull_request.js", "scope": "write" },
51
- { "name": "update_pull_request", "description": "Edit a pull request's title, body, state (open/closed), base branch, or draft status.", "inputSchema": "schemas/update_pull_request.json", "handler": "handlers/update_pull_request.js", "scope": "write" },
52
- { "name": "merge_pull_request", "description": "Merge a pull request. Supports merge, squash, and rebase merge methods.", "inputSchema": "schemas/merge_pull_request.json", "handler": "handlers/merge_pull_request.js", "scope": "write" },
53
- { "name": "request_pull_request_reviewers", "description": "Request specific users or teams to review a pull request.", "inputSchema": "schemas/request_pull_request_reviewers.json", "handler": "handlers/request_pull_request_reviewers.js", "scope": "write" },
54
- { "name": "create_pull_request_review", "description": "Submit a pull request review. Use event=APPROVE to approve, REQUEST_CHANGES to request changes, or COMMENT to leave a comment-only review.", "inputSchema": "schemas/create_pull_request_review.json", "handler": "handlers/create_pull_request_review.js", "scope": "write" },
77
+ { "name": "create_pull_request", "description": "Open a new pull request from a head branch into a base branch.", "inputSchema": "schemas/create_pull_request.json", "handler": "handlers/create_pull_request.js", "scope": "write", "toolset": "pull_requests" },
78
+ { "name": "update_pull_request", "description": "Edit a pull request's title, body, state (open/closed), base branch, or draft status.", "inputSchema": "schemas/update_pull_request.json", "handler": "handlers/update_pull_request.js", "scope": "write", "toolset": "pull_requests" },
79
+ { "name": "merge_pull_request", "description": "Merge a pull request. Supports merge, squash, and rebase merge methods.", "inputSchema": "schemas/merge_pull_request.json", "handler": "handlers/merge_pull_request.js", "scope": "write", "toolset": "pull_requests" },
80
+ { "name": "request_pull_request_reviewers", "description": "Request specific users or teams to review a pull request.", "inputSchema": "schemas/request_pull_request_reviewers.json", "handler": "handlers/request_pull_request_reviewers.js", "scope": "write", "toolset": "pull_requests" },
81
+ { "name": "create_pull_request_review", "description": "Submit a pull request review. Use event=APPROVE to approve, REQUEST_CHANGES to request changes, or COMMENT to leave a comment-only review.", "inputSchema": "schemas/create_pull_request_review.json", "handler": "handlers/create_pull_request_review.js", "scope": "write", "toolset": "pull_requests" },
55
82
 
56
- { "name": "create_issue", "description": "Create a new issue in a repository. Optionally assign users and add labels.", "inputSchema": "schemas/create_issue.json", "handler": "handlers/create_issue.js", "scope": "write" },
57
- { "name": "update_issue", "description": "Update fields on an existing issue (title, body, state, assignees, labels, milestone).", "inputSchema": "schemas/update_issue.json", "handler": "handlers/update_issue.js", "scope": "write" },
58
- { "name": "close_issue", "description": "Close an issue.", "inputSchema": "schemas/close_issue.json", "handler": "handlers/close_issue.js", "scope": "write" },
59
- { "name": "comment_on_issue", "description": "Add a comment to an issue or pull request (GitHub PRs share the issue comment thread). Use list_issue_comments to read existing comments first.", "inputSchema": "schemas/comment_on_issue.json", "handler": "handlers/comment_on_issue.js", "scope": "write" },
60
- { "name": "add_labels_to_issue", "description": "Add labels to an issue or pull request. Use list_labels to discover available labels before calling this.", "inputSchema": "schemas/add_labels_to_issue.json", "handler": "handlers/add_labels_to_issue.js", "scope": "write" },
83
+ { "name": "create_issue", "description": "Create a new issue in a repository. Optionally assign users and add labels.", "inputSchema": "schemas/create_issue.json", "handler": "handlers/create_issue.js", "scope": "write", "toolset": "issues" },
84
+ { "name": "update_issue", "description": "Update fields on an existing issue (title, body, state, assignees, labels, milestone).", "inputSchema": "schemas/update_issue.json", "handler": "handlers/update_issue.js", "scope": "write", "toolset": "issues" },
85
+ { "name": "close_issue", "description": "Close an issue.", "inputSchema": "schemas/close_issue.json", "handler": "handlers/close_issue.js", "scope": "write", "toolset": "issues" },
86
+ { "name": "comment_on_issue", "description": "Add a comment to an issue or pull request (GitHub PRs share the issue comment thread). Use list_issue_comments to read existing comments first.", "inputSchema": "schemas/comment_on_issue.json", "handler": "handlers/comment_on_issue.js", "scope": "write", "toolset": "issues" },
87
+ { "name": "add_labels_to_issue", "description": "Add labels to an issue or pull request. Use list_labels to discover available labels before calling this.", "inputSchema": "schemas/add_labels_to_issue.json", "handler": "handlers/add_labels_to_issue.js", "scope": "write", "toolset": "issues" },
61
88
 
62
- { "name": "create_release", "description": "Create a new release from a tag. Can auto-generate release notes from commits. Set draft=true to save without publishing, prerelease=true for alpha/beta/rc versions.", "inputSchema": "schemas/create_release.json", "handler": "handlers/create_release.js", "scope": "write" }
89
+ { "name": "create_release", "description": "Create a new release from a tag. Can auto-generate release notes from commits. Set draft=true to save without publishing, prerelease=true for alpha/beta/rc versions.", "inputSchema": "schemas/create_release.json", "handler": "handlers/create_release.js", "scope": "write", "toolset": "releases" }
63
90
  ]
64
91
  }
@@ -0,0 +1,36 @@
1
+ # GitHub coding workflow
2
+
3
+ ## Branch-based workflow
4
+
5
+ Always work on a feature branch, never commit directly to main:
6
+
7
+ 1. `create_branch` from the default branch
8
+ 2. Make changes with `edit_file`, `edit_files`, `create_file`, or `delete_file` -- each call auto-commits to the branch
9
+ 3. `create_pull_request` when done
10
+ 4. `merge_pull_request` with `merge_method: "squash"` to collapse all commits into one clean commit on main
11
+
12
+ Multiple small commits on a feature branch are fine -- they get squash-merged into a single commit.
13
+
14
+ ## Choosing the right write tool
15
+
16
+ - **`edit_file`** -- Surgical edits to a single existing file. Use for most code changes. Each call is a commit.
17
+ - **`edit_files`** -- Atomic multi-file changes (create + edit + delete in one commit). Use when files must change together to stay consistent (e.g. renaming across files, adding a module + updating imports).
18
+ - **`create_file`** -- Create a new file or completely replace an existing file's content. Use for new files or full rewrites.
19
+ - **`delete_file`** -- Remove a file.
20
+
21
+ ## Search/replace rules for edit_file and edit_files
22
+
23
+ The `old_text` field must be an **exact match** of the text currently in the file:
24
+
25
+ - Whitespace matters: spaces, tabs, and indentation must match exactly
26
+ - Line breaks matter: include the exact newline characters
27
+ - Include enough surrounding context to uniquely identify the location
28
+ - Each edit replaces the **first occurrence** only. To replace multiple occurrences, use separate edits.
29
+
30
+ **Before editing**, call `get_file_contents` to see the file's current content. This avoids failed edits from stale or incorrect assumptions about file content.
31
+
32
+ ## Reading before writing
33
+
34
+ - Use `get_repo_tree` to discover the project structure and file paths
35
+ - Use `get_file_contents` to read a file before editing it
36
+ - Use `search_code` to find where something is defined or used across the repo
@@ -0,0 +1,13 @@
1
+ {
2
+ "type": "object",
3
+ "properties": {
4
+ "owner": { "type": "string", "description": "Repository owner" },
5
+ "repo": { "type": "string", "description": "Repository name" },
6
+ "branch": { "type": "string", "description": "Branch to commit to" },
7
+ "path": { "type": "string", "description": "File path to create (e.g. 'src/utils/helpers.ts')" },
8
+ "content": { "type": "string", "description": "Plain text file content" },
9
+ "message": { "type": "string", "description": "Commit message" }
10
+ },
11
+ "required": ["owner", "repo", "branch", "path", "content", "message"],
12
+ "additionalProperties": false
13
+ }
@@ -5,9 +5,9 @@
5
5
  "repo": { "type": "string", "description": "Repository name" },
6
6
  "path": { "type": "string", "description": "Path of the file to delete (e.g. 'src/old-file.js')" },
7
7
  "message": { "type": "string", "description": "Commit message" },
8
- "sha": { "type": "string", "description": "The blob SHA of the file to delete. Obtain this from get_file_contents (the 'sha' field on the response)." },
8
+ "sha": { "type": "string", "description": "Optional blob SHA. If omitted, the SHA is fetched automatically." },
9
9
  "branch": { "type": "string", "description": "Branch to delete the file from (defaults to the repo's default branch)" }
10
10
  },
11
- "required": ["owner", "repo", "path", "message", "sha"],
11
+ "required": ["owner", "repo", "path", "message"],
12
12
  "additionalProperties": false
13
13
  }
@@ -0,0 +1,26 @@
1
+ {
2
+ "type": "object",
3
+ "properties": {
4
+ "owner": { "type": "string", "description": "Repository owner" },
5
+ "repo": { "type": "string", "description": "Repository name" },
6
+ "branch": { "type": "string", "description": "Branch to commit to" },
7
+ "path": { "type": "string", "description": "Path of the file to edit (e.g. 'src/index.ts')" },
8
+ "edits": {
9
+ "type": "array",
10
+ "description": "Search/replace operations applied in order. Each old_text must match the file content exactly, including whitespace and indentation.",
11
+ "items": {
12
+ "type": "object",
13
+ "properties": {
14
+ "old_text": { "type": "string", "description": "Exact text to find in the file" },
15
+ "new_text": { "type": "string", "description": "Text to replace it with" }
16
+ },
17
+ "required": ["old_text", "new_text"],
18
+ "additionalProperties": false
19
+ },
20
+ "minItems": 1
21
+ },
22
+ "message": { "type": "string", "description": "Commit message" }
23
+ },
24
+ "required": ["owner", "repo", "branch", "path", "edits", "message"],
25
+ "additionalProperties": false
26
+ }
@@ -0,0 +1,39 @@
1
+ {
2
+ "type": "object",
3
+ "properties": {
4
+ "owner": { "type": "string", "description": "Repository owner" },
5
+ "repo": { "type": "string", "description": "Repository name" },
6
+ "branch": { "type": "string", "description": "Branch to commit to" },
7
+ "message": { "type": "string", "description": "Commit message" },
8
+ "files": {
9
+ "type": "array",
10
+ "description": "Files to create, edit, or delete in this commit",
11
+ "items": {
12
+ "type": "object",
13
+ "properties": {
14
+ "path": { "type": "string", "description": "File path in the repository" },
15
+ "action": { "type": "string", "enum": ["create", "edit", "delete"], "description": "'create': new file or overwrite with content. 'edit': apply search/replace edits to existing file. 'delete': remove the file." },
16
+ "content": { "type": "string", "description": "Full file content (required for 'create' action)" },
17
+ "edits": {
18
+ "type": "array",
19
+ "description": "Search/replace pairs (required for 'edit' action). Each old_text must match exactly, including whitespace.",
20
+ "items": {
21
+ "type": "object",
22
+ "properties": {
23
+ "old_text": { "type": "string", "description": "Exact text to find" },
24
+ "new_text": { "type": "string", "description": "Text to replace it with" }
25
+ },
26
+ "required": ["old_text", "new_text"],
27
+ "additionalProperties": false
28
+ }
29
+ }
30
+ },
31
+ "required": ["path", "action"],
32
+ "additionalProperties": false
33
+ },
34
+ "minItems": 1
35
+ }
36
+ },
37
+ "required": ["owner", "repo", "branch", "message", "files"],
38
+ "additionalProperties": false
39
+ }
@@ -0,0 +1,11 @@
1
+ # Google Calendar live integration tests
2
+ # Shared Google credentials live in /.env.test.google — set those up first.
3
+ #
4
+ # Calendar ID to run tests against (defaults to 'primary' if omitted)
5
+ GOOGLE_CALENDAR_TEST_CALENDAR_ID=
6
+ # Set to any non-empty value to enable admin write tests (creates/deletes calendars)
7
+ GOOGLE_CALENDAR_TEST_ADMIN_WRITE=
8
+ # A plain-text quick-add string for the quick_add_event test (e.g. "Lunch tomorrow at noon")
9
+ GOOGLE_CALENDAR_TEST_QUICK_ADD=
10
+ # Calendar ID to use as the move destination in move_event tests
11
+ GOOGLE_CALENDAR_TEST_MOVE_DEST=
@@ -0,0 +1,41 @@
1
+ # Google Calendar
2
+
3
+ **17 tools** across 2 toolsets
4
+
5
+ ![Google Calendar tests](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/theomccabe/771bd329f303087690c522afa1baa6f3/raw/test-google-calendar.json)
6
+
7
+ ## Credential variants
8
+
9
+ | Variant | Label |
10
+ |---|---|
11
+ | `service_account` | Service Account (recommended) _(default)_ |
12
+ | `oauth_token` | OAuth Access Token (short-lived) |
13
+
14
+ ## Toolsets
15
+
16
+ | Toolset | Description |
17
+ |---|---|
18
+ | `events` | Browse, schedule, and manage calendar events |
19
+ | `sharing` | Control who can access calendars |
20
+
21
+ ## Tools
22
+
23
+ | Tool | Scope | Toolset | Description |
24
+ |---|---|---|---|
25
+ | `list_calendars` | read | `events` | List all calendars in the authenticated user's calendar list, including the primary calen… |
26
+ | `get_calendar` | read | `events` | Get details for a specific calendar by ID, including its summary, description, timezone, … |
27
+ | `list_events` | read | `events` | List events in a calendar with optional time range, text search, and pagination. Use cale… |
28
+ | `get_event` | read | `events` | Get a specific event by its ID from a calendar. Returns full event details including summ… |
29
+ | `list_colors` | read | `events` | Get the set of color definitions available for calendars and events. Returns colorId valu… |
30
+ | `freebusy_query` | read | `events` | Query free/busy availability for one or more calendars within a time range. Useful for fi… |
31
+ | `list_settings` | read | `events` | List the authenticated user's Google Calendar settings, such as timezone, date format, an… |
32
+ | `create_event` | write | `events` | Create a new event in a calendar. Required fields: calendarId, summary, start, end. Use {… |
33
+ | `patch_event` | write | `events` | Partially update an event by providing only the fields to change. All other fields are pr… |
34
+ | `delete_event` | write | `events` | Delete an event from a calendar. This permanently removes the event. For recurring events… |
35
+ | `move_event` | write | `events` | Move an event from one calendar to another. Provide the source calendarId, eventId, and t… |
36
+ | `quick_add` | write | `events` | Create an event using a natural language text string. Parses the text to extract event de… |
37
+ | `list_acl` | admin | `sharing` | List the Access Control List (ACL) rules for a calendar. Returns rules defining who has a… |
38
+ | `get_acl` | admin | `sharing` | Get a specific ACL rule by its rule ID for a calendar. Use list_acl to find rule IDs. |
39
+ | `insert_acl` | admin | `sharing` | Add a new ACL rule to grant a user or group access to a calendar. Roles: 'reader' (view),… |
40
+ | `update_acl` | admin | `sharing` | Update an existing ACL rule to change a user's or group's permission level on a calendar.… |
41
+ | `delete_acl` | admin | `sharing` | Remove an ACL rule from a calendar, revoking the associated user's or group's access. Use… |
@@ -6,7 +6,7 @@ import { loadIntegrationTools } from '../../../../server/src/integrations/dataLo
6
6
  // Required env vars:
7
7
  // - Either GOOGLE_TOKEN, OR (GOOGLE_SERVICE_ACCOUNT_JSON + GOOGLE_IMPERSONATE_SUBJECT)
8
8
  // Optional:
9
- // - GCAL_TEST_CALENDAR_ID (defaults to 'primary')
9
+ // - GOOGLE_CALENDAR_TEST_CALENDAR_ID (defaults to 'primary')
10
10
 
11
11
  interface Ctx {
12
12
  calendarId: string
@@ -27,9 +27,9 @@ suite('google-calendar write & admin handlers (live)', () => {
27
27
  let buildAdmin: (name: string) => ((input: any) => Promise<any>)
28
28
 
29
29
  beforeAll(async () => {
30
- const { GCAL_TEST_CALENDAR_ID } = env
30
+ const { GOOGLE_CALENDAR_TEST_CALENDAR_ID } = env
31
31
 
32
- ctx.calendarId = GCAL_TEST_CALENDAR_ID || 'primary'
32
+ ctx.calendarId = GOOGLE_CALENDAR_TEST_CALENDAR_ID || 'primary'
33
33
 
34
34
  const credentialStore = {
35
35
  getCredentials: async () => ({
@@ -114,7 +114,7 @@ suite('google-calendar write & admin handlers (live)', () => {
114
114
  }, 30000)
115
115
 
116
116
  it('insert_acl -> get_acl -> update_acl -> delete_acl (admin)', async () => {
117
- if (!process.env.GCAL_TEST_ADMIN_WRITE)
117
+ if (!process.env.GOOGLE_CALENDAR_TEST_ADMIN_WRITE)
118
118
  return expect(true).toBe(true)
119
119
  const insert_acl = buildAdmin('insert_acl')
120
120
  const created = await insert_acl({ calendarId: ctx.calendarId, rule: { scope: { type: 'default' }, role: 'reader' } })
@@ -132,7 +132,7 @@ suite('google-calendar write & admin handlers (live)', () => {
132
132
  }, 90000)
133
133
 
134
134
  it('quick_add creates a simple event', async () => {
135
- if (!process.env.GCAL_TEST_QUICK_ADD)
135
+ if (!process.env.GOOGLE_CALENDAR_TEST_QUICK_ADD)
136
136
  return expect(true).toBe(true)
137
137
  const quick_add = buildWrite('quick_add')
138
138
  const res = await quick_add({ calendarId: ctx.calendarId, text: `Lunch tomorrow ${Date.now()}` })
@@ -140,7 +140,7 @@ suite('google-calendar write & admin handlers (live)', () => {
140
140
  }, 60000)
141
141
 
142
142
  it('move_event moves an event when provided a source event', async () => {
143
- if (!process.env.GCAL_TEST_MOVE_DEST)
143
+ if (!process.env.GOOGLE_CALENDAR_TEST_MOVE_DEST)
144
144
  return expect(true).toBe(true)
145
145
  const create_event = buildWrite('create_event')
146
146
  const now = new Date()
@@ -149,7 +149,7 @@ suite('google-calendar write & admin handlers (live)', () => {
149
149
  const eventId = created?.id
150
150
  expect(eventId).toBeTruthy()
151
151
  const move_event = buildWrite('move_event')
152
- const moved = await move_event({ calendarId: ctx.calendarId, eventId, destinationId: process.env.GCAL_TEST_MOVE_DEST })
152
+ const moved = await move_event({ calendarId: ctx.calendarId, eventId, destinationId: process.env.GOOGLE_CALENDAR_TEST_MOVE_DEST })
153
153
  expect(moved?.id).toBeTruthy()
154
154
  }, 90000)
155
155
  })
@@ -30,7 +30,8 @@
30
30
  "Authorization": "Bearer {{token}}"
31
31
  }
32
32
  },
33
- "preprocess": "google_service_account"
33
+ "preprocess": "google_service_account",
34
+ "healthCheck": { "path": "/users/me/calendarList?maxResults=1" }
34
35
  },
35
36
  "oauth_token": {
36
37
  "label": "OAuth Access Token (short-lived)",
@@ -50,7 +51,8 @@
50
51
  "headers": {
51
52
  "Authorization": "Bearer {{token}}"
52
53
  }
53
- }
54
+ },
55
+ "healthCheck": { "path": "/users/me/calendarList?maxResults=1" }
54
56
  }
55
57
  },
56
58
  "default": "service_account"
@@ -2,7 +2,7 @@ Recommended: use a Google service account.
2
2
 
3
3
  - Create a service account in Google Cloud
4
4
  - Download a JSON key
5
- - Paste the JSON into `serviceAccountJson` (or use `env:GOOGLE_SERVICE_ACCOUNT_JSON`)
5
+ - Paste the JSON into `serviceAccountJson`
6
6
 
7
7
  Note: Calendar often needs Google Workspace domain-wide delegation if you want to impersonate a user (`subject`).
8
8
  For simple setups, use a short-lived OAuth access token in `token`.