patchwork-os 0.2.0-alpha.2 → 0.2.0-alpha.22

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 (281) hide show
  1. package/README.bridge.md +6 -0
  2. package/README.md +40 -15
  3. package/deploy/bootstrap-vps.sh +184 -0
  4. package/dist/approvalHttp.d.ts +11 -2
  5. package/dist/approvalHttp.js +98 -10
  6. package/dist/approvalHttp.js.map +1 -1
  7. package/dist/approvalQueue.d.ts +12 -1
  8. package/dist/approvalQueue.js +25 -3
  9. package/dist/approvalQueue.js.map +1 -1
  10. package/dist/automation.d.ts +20 -0
  11. package/dist/automation.js +35 -0
  12. package/dist/automation.js.map +1 -1
  13. package/dist/bridge.js +145 -23
  14. package/dist/bridge.js.map +1 -1
  15. package/dist/bridgeToken.js +57 -19
  16. package/dist/bridgeToken.js.map +1 -1
  17. package/dist/claudeDriver.d.ts +3 -1
  18. package/dist/claudeDriver.js +48 -0
  19. package/dist/claudeDriver.js.map +1 -1
  20. package/dist/claudeOrchestrator.d.ts +1 -1
  21. package/dist/claudeOrchestrator.js +14 -8
  22. package/dist/claudeOrchestrator.js.map +1 -1
  23. package/dist/commands/launchd.d.ts +2 -0
  24. package/dist/commands/launchd.js +94 -0
  25. package/dist/commands/launchd.js.map +1 -0
  26. package/dist/commands/recipe.d.ts +256 -0
  27. package/dist/commands/recipe.js +1313 -0
  28. package/dist/commands/recipe.js.map +1 -0
  29. package/dist/config.d.ts +15 -2
  30. package/dist/config.js +94 -8
  31. package/dist/config.js.map +1 -1
  32. package/dist/connectors/baseConnector.d.ts +117 -0
  33. package/dist/connectors/baseConnector.js +213 -0
  34. package/dist/connectors/baseConnector.js.map +1 -0
  35. package/dist/connectors/confluence.d.ts +111 -0
  36. package/dist/connectors/confluence.js +406 -0
  37. package/dist/connectors/confluence.js.map +1 -0
  38. package/dist/connectors/fixtureLibrary.d.ts +21 -0
  39. package/dist/connectors/fixtureLibrary.js +70 -0
  40. package/dist/connectors/fixtureLibrary.js.map +1 -0
  41. package/dist/connectors/fixtureRecorder.d.ts +1 -0
  42. package/dist/connectors/fixtureRecorder.js +35 -0
  43. package/dist/connectors/fixtureRecorder.js.map +1 -0
  44. package/dist/connectors/github.d.ts +58 -8
  45. package/dist/connectors/github.js +312 -84
  46. package/dist/connectors/github.js.map +1 -1
  47. package/dist/connectors/gmail.d.ts +4 -1
  48. package/dist/connectors/gmail.js +93 -16
  49. package/dist/connectors/gmail.js.map +1 -1
  50. package/dist/connectors/googleCalendar.d.ts +60 -0
  51. package/dist/connectors/googleCalendar.js +345 -0
  52. package/dist/connectors/googleCalendar.js.map +1 -0
  53. package/dist/connectors/jira.d.ts +98 -0
  54. package/dist/connectors/jira.js +379 -0
  55. package/dist/connectors/jira.js.map +1 -0
  56. package/dist/connectors/linear.d.ts +117 -0
  57. package/dist/connectors/linear.js +239 -0
  58. package/dist/connectors/linear.js.map +1 -0
  59. package/dist/connectors/mcpClient.d.ts +56 -0
  60. package/dist/connectors/mcpClient.js +189 -0
  61. package/dist/connectors/mcpClient.js.map +1 -0
  62. package/dist/connectors/mcpOAuth.d.ts +84 -0
  63. package/dist/connectors/mcpOAuth.js +389 -0
  64. package/dist/connectors/mcpOAuth.js.map +1 -0
  65. package/dist/connectors/mockConnector.d.ts +28 -0
  66. package/dist/connectors/mockConnector.js +81 -0
  67. package/dist/connectors/mockConnector.js.map +1 -0
  68. package/dist/connectors/notion.d.ts +143 -0
  69. package/dist/connectors/notion.js +424 -0
  70. package/dist/connectors/notion.js.map +1 -0
  71. package/dist/connectors/sentry.d.ts +43 -0
  72. package/dist/connectors/sentry.js +188 -0
  73. package/dist/connectors/sentry.js.map +1 -0
  74. package/dist/connectors/slack.d.ts +50 -0
  75. package/dist/connectors/slack.js +324 -0
  76. package/dist/connectors/slack.js.map +1 -0
  77. package/dist/connectors/tokenStorage.d.ts +35 -0
  78. package/dist/connectors/tokenStorage.js +394 -0
  79. package/dist/connectors/tokenStorage.js.map +1 -0
  80. package/dist/connectors/zendesk.d.ts +104 -0
  81. package/dist/connectors/zendesk.js +424 -0
  82. package/dist/connectors/zendesk.js.map +1 -0
  83. package/dist/drivers/claude/api.d.ts +11 -0
  84. package/dist/drivers/claude/api.js +54 -0
  85. package/dist/drivers/claude/api.js.map +1 -0
  86. package/dist/drivers/claude/envSanitizer.d.ts +7 -0
  87. package/dist/drivers/claude/envSanitizer.js +18 -0
  88. package/dist/drivers/claude/envSanitizer.js.map +1 -0
  89. package/dist/drivers/claude/streamParser.d.ts +38 -0
  90. package/dist/drivers/claude/streamParser.js +34 -0
  91. package/dist/drivers/claude/streamParser.js.map +1 -0
  92. package/dist/drivers/claude/subprocess.d.ts +19 -0
  93. package/dist/drivers/claude/subprocess.js +216 -0
  94. package/dist/drivers/claude/subprocess.js.map +1 -0
  95. package/dist/drivers/claude/subprocessSettings.d.ts +9 -0
  96. package/dist/drivers/claude/subprocessSettings.js +55 -0
  97. package/dist/drivers/claude/subprocessSettings.js.map +1 -0
  98. package/dist/drivers/gemini/index.d.ts +18 -0
  99. package/dist/drivers/gemini/index.js +210 -0
  100. package/dist/drivers/gemini/index.js.map +1 -0
  101. package/dist/drivers/grok/index.d.ts +11 -0
  102. package/dist/drivers/grok/index.js +22 -0
  103. package/dist/drivers/grok/index.js.map +1 -0
  104. package/dist/drivers/index.d.ts +23 -0
  105. package/dist/drivers/index.js +31 -0
  106. package/dist/drivers/index.js.map +1 -0
  107. package/dist/drivers/openai/index.d.ts +24 -0
  108. package/dist/drivers/openai/index.js +110 -0
  109. package/dist/drivers/openai/index.js.map +1 -0
  110. package/dist/drivers/types.d.ts +72 -0
  111. package/dist/drivers/types.js +30 -0
  112. package/dist/drivers/types.js.map +1 -0
  113. package/dist/featureFlags.d.ts +73 -0
  114. package/dist/featureFlags.js +203 -0
  115. package/dist/featureFlags.js.map +1 -0
  116. package/dist/fp/automationInterpreter.js +1 -0
  117. package/dist/fp/automationInterpreter.js.map +1 -1
  118. package/dist/fp/automationProgram.d.ts +1 -1
  119. package/dist/fp/automationProgram.js.map +1 -1
  120. package/dist/fp/policyParser.js +17 -0
  121. package/dist/fp/policyParser.js.map +1 -1
  122. package/dist/index.js +543 -37
  123. package/dist/index.js.map +1 -1
  124. package/dist/installGuard.d.ts +25 -0
  125. package/dist/installGuard.js +48 -0
  126. package/dist/installGuard.js.map +1 -0
  127. package/dist/oauth.d.ts +4 -1
  128. package/dist/oauth.js +50 -14
  129. package/dist/oauth.js.map +1 -1
  130. package/dist/patchworkConfig.d.ts +9 -0
  131. package/dist/patchworkConfig.js.map +1 -1
  132. package/dist/recipes/chainedRunner.d.ts +104 -0
  133. package/dist/recipes/chainedRunner.js +359 -0
  134. package/dist/recipes/chainedRunner.js.map +1 -0
  135. package/dist/recipes/dependencyGraph.d.ts +39 -0
  136. package/dist/recipes/dependencyGraph.js +199 -0
  137. package/dist/recipes/dependencyGraph.js.map +1 -0
  138. package/dist/recipes/legacyRecipeCompat.d.ts +1 -0
  139. package/dist/recipes/legacyRecipeCompat.js +97 -0
  140. package/dist/recipes/legacyRecipeCompat.js.map +1 -0
  141. package/dist/recipes/nestedRecipeStep.d.ts +58 -0
  142. package/dist/recipes/nestedRecipeStep.js +95 -0
  143. package/dist/recipes/nestedRecipeStep.js.map +1 -0
  144. package/dist/recipes/outputRegistry.d.ts +28 -0
  145. package/dist/recipes/outputRegistry.js +52 -0
  146. package/dist/recipes/outputRegistry.js.map +1 -0
  147. package/dist/recipes/scheduler.d.ts +23 -7
  148. package/dist/recipes/scheduler.js +135 -41
  149. package/dist/recipes/scheduler.js.map +1 -1
  150. package/dist/recipes/schemaGenerator.d.ts +28 -0
  151. package/dist/recipes/schemaGenerator.js +484 -0
  152. package/dist/recipes/schemaGenerator.js.map +1 -0
  153. package/dist/recipes/templateEngine.d.ts +62 -0
  154. package/dist/recipes/templateEngine.js +182 -0
  155. package/dist/recipes/templateEngine.js.map +1 -0
  156. package/dist/recipes/toolRegistry.d.ts +181 -0
  157. package/dist/recipes/toolRegistry.js +300 -0
  158. package/dist/recipes/toolRegistry.js.map +1 -0
  159. package/dist/recipes/tools/calendar.d.ts +6 -0
  160. package/dist/recipes/tools/calendar.js +61 -0
  161. package/dist/recipes/tools/calendar.js.map +1 -0
  162. package/dist/recipes/tools/confluence.d.ts +6 -0
  163. package/dist/recipes/tools/confluence.js +254 -0
  164. package/dist/recipes/tools/confluence.js.map +1 -0
  165. package/dist/recipes/tools/diagnostics.d.ts +6 -0
  166. package/dist/recipes/tools/diagnostics.js +36 -0
  167. package/dist/recipes/tools/diagnostics.js.map +1 -0
  168. package/dist/recipes/tools/file.d.ts +6 -0
  169. package/dist/recipes/tools/file.js +170 -0
  170. package/dist/recipes/tools/file.js.map +1 -0
  171. package/dist/recipes/tools/git.d.ts +6 -0
  172. package/dist/recipes/tools/git.js +63 -0
  173. package/dist/recipes/tools/git.js.map +1 -0
  174. package/dist/recipes/tools/github.d.ts +6 -0
  175. package/dist/recipes/tools/github.js +91 -0
  176. package/dist/recipes/tools/github.js.map +1 -0
  177. package/dist/recipes/tools/gmail.d.ts +6 -0
  178. package/dist/recipes/tools/gmail.js +210 -0
  179. package/dist/recipes/tools/gmail.js.map +1 -0
  180. package/dist/recipes/tools/index.d.ts +18 -0
  181. package/dist/recipes/tools/index.js +21 -0
  182. package/dist/recipes/tools/index.js.map +1 -0
  183. package/dist/recipes/tools/linear.d.ts +6 -0
  184. package/dist/recipes/tools/linear.js +83 -0
  185. package/dist/recipes/tools/linear.js.map +1 -0
  186. package/dist/recipes/tools/notion.d.ts +6 -0
  187. package/dist/recipes/tools/notion.js +278 -0
  188. package/dist/recipes/tools/notion.js.map +1 -0
  189. package/dist/recipes/tools/slack.d.ts +6 -0
  190. package/dist/recipes/tools/slack.js +72 -0
  191. package/dist/recipes/tools/slack.js.map +1 -0
  192. package/dist/recipes/tools/zendesk.d.ts +6 -0
  193. package/dist/recipes/tools/zendesk.js +245 -0
  194. package/dist/recipes/tools/zendesk.js.map +1 -0
  195. package/dist/recipes/yamlRunner.d.ts +79 -0
  196. package/dist/recipes/yamlRunner.js +612 -346
  197. package/dist/recipes/yamlRunner.js.map +1 -1
  198. package/dist/recipesHttp.d.ts +14 -1
  199. package/dist/recipesHttp.js +21 -4
  200. package/dist/recipesHttp.js.map +1 -1
  201. package/dist/riskTier.js +1 -0
  202. package/dist/riskTier.js.map +1 -1
  203. package/dist/runLog.d.ts +23 -0
  204. package/dist/runLog.js +56 -1
  205. package/dist/runLog.js.map +1 -1
  206. package/dist/server.d.ts +19 -1
  207. package/dist/server.js +682 -31
  208. package/dist/server.js.map +1 -1
  209. package/dist/streamableHttp.js +2 -0
  210. package/dist/streamableHttp.js.map +1 -1
  211. package/dist/tools/addLinearComment.d.ts +55 -0
  212. package/dist/tools/addLinearComment.js +72 -0
  213. package/dist/tools/addLinearComment.js.map +1 -0
  214. package/dist/tools/bridgeDoctor.js +2 -2
  215. package/dist/tools/bridgeDoctor.js.map +1 -1
  216. package/dist/tools/createLinearIssue.d.ts +84 -0
  217. package/dist/tools/createLinearIssue.js +146 -0
  218. package/dist/tools/createLinearIssue.js.map +1 -0
  219. package/dist/tools/ctxGetTaskContext.d.ts +4 -1
  220. package/dist/tools/ctxGetTaskContext.js +45 -2
  221. package/dist/tools/ctxGetTaskContext.js.map +1 -1
  222. package/dist/tools/fetchCalendarEvents.d.ts +94 -0
  223. package/dist/tools/fetchCalendarEvents.js +97 -0
  224. package/dist/tools/fetchCalendarEvents.js.map +1 -0
  225. package/dist/tools/fetchGithubIssue.d.ts +80 -0
  226. package/dist/tools/fetchGithubIssue.js +84 -0
  227. package/dist/tools/fetchGithubIssue.js.map +1 -0
  228. package/dist/tools/fetchGithubPR.d.ts +89 -0
  229. package/dist/tools/fetchGithubPR.js +96 -0
  230. package/dist/tools/fetchGithubPR.js.map +1 -0
  231. package/dist/tools/fetchLinearIssue.d.ts +112 -0
  232. package/dist/tools/fetchLinearIssue.js +129 -0
  233. package/dist/tools/fetchLinearIssue.js.map +1 -0
  234. package/dist/tools/fetchSentryIssue.d.ts +143 -0
  235. package/dist/tools/fetchSentryIssue.js +150 -0
  236. package/dist/tools/fetchSentryIssue.js.map +1 -0
  237. package/dist/tools/fetchSlackProfile.d.ts +43 -0
  238. package/dist/tools/fetchSlackProfile.js +46 -0
  239. package/dist/tools/fetchSlackProfile.js.map +1 -0
  240. package/dist/tools/getConnectorStatus.d.ts +58 -0
  241. package/dist/tools/getConnectorStatus.js +56 -0
  242. package/dist/tools/getConnectorStatus.js.map +1 -0
  243. package/dist/tools/github/actions.js +4 -2
  244. package/dist/tools/github/actions.js.map +1 -1
  245. package/dist/tools/github/composite.d.ts +339 -0
  246. package/dist/tools/github/composite.js +343 -0
  247. package/dist/tools/github/composite.js.map +1 -0
  248. package/dist/tools/github/index.d.ts +2 -1
  249. package/dist/tools/github/index.js +2 -1
  250. package/dist/tools/github/index.js.map +1 -1
  251. package/dist/tools/github/issues.js +8 -4
  252. package/dist/tools/github/issues.js.map +1 -1
  253. package/dist/tools/github/pr.d.ts +122 -0
  254. package/dist/tools/github/pr.js +195 -5
  255. package/dist/tools/github/pr.js.map +1 -1
  256. package/dist/tools/index.js +36 -1
  257. package/dist/tools/index.js.map +1 -1
  258. package/dist/tools/searchTools.js +1 -1
  259. package/dist/tools/searchTools.js.map +1 -1
  260. package/dist/tools/slackListChannels.d.ts +65 -0
  261. package/dist/tools/slackListChannels.js +70 -0
  262. package/dist/tools/slackListChannels.js.map +1 -0
  263. package/dist/tools/slackPostMessage.d.ts +57 -0
  264. package/dist/tools/slackPostMessage.js +77 -0
  265. package/dist/tools/slackPostMessage.js.map +1 -0
  266. package/dist/tools/updateLinearIssue.d.ts +89 -0
  267. package/dist/tools/updateLinearIssue.js +117 -0
  268. package/dist/tools/updateLinearIssue.js.map +1 -0
  269. package/dist/transport.d.ts +7 -1
  270. package/dist/transport.js +85 -11
  271. package/dist/transport.js.map +1 -1
  272. package/package.json +4 -2
  273. package/scripts/start-all.sh +56 -19
  274. package/templates/automation-policies/recipe-authoring.json +25 -0
  275. package/templates/automation-policy.example.json +6 -0
  276. package/templates/co.patchwork-os.bridge.plist +34 -0
  277. package/templates/recipes/ctx-loop-test.yaml +75 -0
  278. package/templates/recipes/lint-on-save.yaml +1 -2
  279. package/templates/recipes/morning-brief-slack.yaml +57 -0
  280. package/templates/recipes/morning-brief.yaml +21 -5
  281. package/templates/recipes/sentry-to-linear.yaml +77 -0
@@ -0,0 +1,389 @@
1
+ /**
2
+ * OAuth 2.1 PKCE helper for upstream MCP servers.
3
+ *
4
+ * Supports two vendor modes:
5
+ * - dyn-reg (Linear, Sentry): RFC 7591 dynamic client registration.
6
+ * Registration data cached alongside tokens so we don't re-register every run.
7
+ * - preregistered (GitHub): uses a hardcoded client_id + PKCE-only flow.
8
+ *
9
+ * Token files: ~/.patchwork/tokens/<vendor>-mcp.json (mode 0600)
10
+ *
11
+ * Flow:
12
+ * 1. startAuthorize({ vendor, config }) -> { url, state }
13
+ * Dashboard opens `url` in a popup; stores `state` to correlate callback.
14
+ * 2. server.ts callback route calls completeAuthorize({ vendor, config, code, state })
15
+ * -> persisted token file.
16
+ * 3. getAccessToken({ vendor }) reads token, refreshes if needed.
17
+ * 4. revoke({ vendor }) hits the revocation endpoint + deletes file.
18
+ */
19
+ import crypto from "node:crypto";
20
+ import { existsSync, readFileSync, unlinkSync } from "node:fs";
21
+ import { homedir } from "node:os";
22
+ import path from "node:path";
23
+ import { deleteSecretJsonSync, getSecretJsonSync, storeSecretJsonSync, } from "./tokenStorage.js";
24
+ // ── Known vendor configs ─────────────────────────────────────────────────────
25
+ function defaultBridgeBase() {
26
+ const port = process.env.PATCHWORK_BRIDGE_PORT ?? "3101";
27
+ return (process.env.PATCHWORK_BRIDGE_URL ?? `http://localhost:${port}`).replace(/\/$/, "");
28
+ }
29
+ export function vendorConfig(vendor) {
30
+ const bridgeBase = defaultBridgeBase();
31
+ switch (vendor) {
32
+ case "github":
33
+ return {
34
+ vendor,
35
+ issuer: "https://github.com/login/oauth",
36
+ authorizationEndpoint: "https://github.com/login/oauth/authorize",
37
+ tokenEndpoint: "https://github.com/login/oauth/access_token",
38
+ revocationEndpoint: undefined, // GitHub OAuth apps use a different revoke path; best-effort delete only
39
+ scopes: ["repo", "read:org", "read:user"],
40
+ redirectUri: `${bridgeBase}/connections/github/callback`,
41
+ useDynamicRegistration: false,
42
+ preregisteredClientId: process.env.PATCHWORK_GITHUB_CLIENT_ID ?? "",
43
+ preregisteredClientSecret: process.env.PATCHWORK_GITHUB_CLIENT_SECRET,
44
+ clientName: "Patchwork OS",
45
+ };
46
+ case "linear":
47
+ return {
48
+ vendor,
49
+ issuer: "https://mcp.linear.app",
50
+ authorizationEndpoint: "https://mcp.linear.app/authorize",
51
+ tokenEndpoint: "https://mcp.linear.app/token",
52
+ registrationEndpoint: "https://mcp.linear.app/register",
53
+ revocationEndpoint: "https://mcp.linear.app/token", // per discovery doc
54
+ scopes: [],
55
+ redirectUri: `${bridgeBase}/connections/linear/callback`,
56
+ useDynamicRegistration: true,
57
+ clientName: "Patchwork OS",
58
+ };
59
+ case "sentry":
60
+ return {
61
+ vendor,
62
+ issuer: "https://mcp.sentry.dev",
63
+ authorizationEndpoint: "https://mcp.sentry.dev/oauth/authorize",
64
+ tokenEndpoint: "https://mcp.sentry.dev/oauth/token",
65
+ registrationEndpoint: "https://mcp.sentry.dev/oauth/register",
66
+ revocationEndpoint: "https://mcp.sentry.dev/oauth/token",
67
+ scopes: ["org:read", "project:write", "event:write"],
68
+ redirectUri: `${bridgeBase}/connections/sentry/callback`,
69
+ useDynamicRegistration: true,
70
+ clientName: "Patchwork OS",
71
+ };
72
+ }
73
+ }
74
+ function tokenPath(vendor) {
75
+ return path.join(homedir(), ".patchwork", "tokens", `${vendor}-mcp.json`);
76
+ }
77
+ function tokenStorageProvider(vendor) {
78
+ return `${vendor}-mcp`;
79
+ }
80
+ export function loadTokenFile(vendor) {
81
+ const secure = getSecretJsonSync(tokenStorageProvider(vendor));
82
+ if (secure) {
83
+ return secure;
84
+ }
85
+ const p = tokenPath(vendor);
86
+ if (!existsSync(p))
87
+ return null;
88
+ try {
89
+ const legacy = JSON.parse(readFileSync(p, "utf-8"));
90
+ saveTokenFile(legacy);
91
+ return legacy;
92
+ }
93
+ catch {
94
+ return null;
95
+ }
96
+ }
97
+ function saveTokenFile(file) {
98
+ storeSecretJsonSync(tokenStorageProvider(file.vendor), file);
99
+ const p = tokenPath(file.vendor);
100
+ if (existsSync(p)) {
101
+ try {
102
+ unlinkSync(p);
103
+ }
104
+ catch { }
105
+ }
106
+ }
107
+ function deleteTokenFile(vendor) {
108
+ deleteSecretJsonSync(tokenStorageProvider(vendor));
109
+ const p = tokenPath(vendor);
110
+ if (existsSync(p))
111
+ unlinkSync(p);
112
+ }
113
+ export function updateTokenProfile(vendor, profile) {
114
+ const file = loadTokenFile(vendor);
115
+ if (!file) {
116
+ return;
117
+ }
118
+ saveTokenFile({
119
+ ...file,
120
+ profile: { ...(file.profile ?? {}), ...profile },
121
+ });
122
+ }
123
+ // ── PKCE helpers ─────────────────────────────────────────────────────────────
124
+ function base64url(buf) {
125
+ return buf
126
+ .toString("base64")
127
+ .replace(/=/g, "")
128
+ .replace(/\+/g, "-")
129
+ .replace(/\//g, "_");
130
+ }
131
+ function genVerifier() {
132
+ return base64url(crypto.randomBytes(32));
133
+ }
134
+ function challenge(verifier) {
135
+ return base64url(crypto.createHash("sha256").update(verifier).digest());
136
+ }
137
+ const pending = new Map();
138
+ function gcPending() {
139
+ const now = Date.now();
140
+ for (const [k, v] of pending.entries()) {
141
+ if (v.expiresAt < now)
142
+ pending.delete(k);
143
+ }
144
+ }
145
+ async function dynamicRegister(config) {
146
+ if (!config.registrationEndpoint) {
147
+ throw new Error(`${config.vendor}: no registration endpoint configured`);
148
+ }
149
+ const body = {
150
+ client_name: config.clientName ?? "Patchwork OS",
151
+ redirect_uris: [config.redirectUri],
152
+ grant_types: ["authorization_code", "refresh_token"],
153
+ response_types: ["code"],
154
+ token_endpoint_auth_method: "none",
155
+ scope: config.scopes.join(" "),
156
+ };
157
+ const res = await fetch(config.registrationEndpoint, {
158
+ method: "POST",
159
+ headers: { "Content-Type": "application/json", Accept: "application/json" },
160
+ body: JSON.stringify(body),
161
+ });
162
+ if (!res.ok) {
163
+ const snippet = (await res.text()).slice(0, 300);
164
+ throw new Error(`${config.vendor} dyn-reg failed ${res.status}: ${snippet}`);
165
+ }
166
+ const json = (await res.json());
167
+ if (!json.client_id)
168
+ throw new Error(`${config.vendor} dyn-reg missing client_id`);
169
+ return { clientId: json.client_id, clientSecret: json.client_secret };
170
+ }
171
+ // ── Authorize flow ───────────────────────────────────────────────────────────
172
+ /**
173
+ * Returns the authorize URL for the popup, and a `state` cookie value
174
+ * the callback must match. For dyn-reg vendors, registers a fresh client
175
+ * if we don't have one yet (re-uses existing one from token file on reconnect).
176
+ */
177
+ export async function startAuthorize(config) {
178
+ gcPending();
179
+ let clientId = config.preregisteredClientId ?? "";
180
+ let clientSecret = config.preregisteredClientSecret;
181
+ if (config.useDynamicRegistration) {
182
+ // Re-use cached registration if available
183
+ const existing = loadTokenFile(config.vendor);
184
+ if (existing?.client_id) {
185
+ clientId = existing.client_id;
186
+ clientSecret = existing.client_secret;
187
+ }
188
+ else {
189
+ const reg = await dynamicRegister(config);
190
+ clientId = reg.clientId;
191
+ clientSecret = reg.clientSecret;
192
+ }
193
+ }
194
+ if (!clientId) {
195
+ throw new Error(`${config.vendor}: client_id not configured (set PATCHWORK_${config.vendor.toUpperCase()}_CLIENT_ID)`);
196
+ }
197
+ if (!config.useDynamicRegistration &&
198
+ config.preregisteredClientSecret === undefined &&
199
+ config.vendor === "github") {
200
+ throw new Error("github: client_secret not configured (set PATCHWORK_GITHUB_CLIENT_SECRET)");
201
+ }
202
+ const verifier = genVerifier();
203
+ const state = base64url(crypto.randomBytes(24));
204
+ pending.set(state, {
205
+ vendor: config.vendor,
206
+ verifier,
207
+ clientId,
208
+ clientSecret,
209
+ expiresAt: Date.now() + 10 * 60 * 1000,
210
+ });
211
+ const params = new URLSearchParams({
212
+ response_type: "code",
213
+ client_id: clientId,
214
+ redirect_uri: config.redirectUri,
215
+ state,
216
+ code_challenge: challenge(verifier),
217
+ code_challenge_method: "S256",
218
+ });
219
+ if (config.scopes.length)
220
+ params.set("scope", config.scopes.join(" "));
221
+ const authorizeUrl = config.authorizationEndpoint;
222
+ if (!authorizeUrl)
223
+ throw new Error(`${config.vendor}: no authorization_endpoint`);
224
+ return { url: `${authorizeUrl}?${params.toString()}`, state };
225
+ }
226
+ async function exchangeCode(config, code, verifier, clientId, clientSecret) {
227
+ if (!config.tokenEndpoint)
228
+ throw new Error(`${config.vendor}: no token_endpoint`);
229
+ const body = new URLSearchParams({
230
+ grant_type: "authorization_code",
231
+ code,
232
+ redirect_uri: config.redirectUri,
233
+ client_id: clientId,
234
+ code_verifier: verifier,
235
+ });
236
+ if (clientSecret)
237
+ body.set("client_secret", clientSecret);
238
+ const res = await fetch(config.tokenEndpoint, {
239
+ method: "POST",
240
+ headers: {
241
+ "Content-Type": "application/x-www-form-urlencoded",
242
+ Accept: "application/json",
243
+ },
244
+ body: body.toString(),
245
+ });
246
+ if (!res.ok) {
247
+ const snippet = (await res.text()).slice(0, 300);
248
+ throw new Error(`${config.vendor} token exchange ${res.status}: ${snippet}`);
249
+ }
250
+ // GitHub returns form-encoded by default unless Accept: application/json is honored
251
+ const ct = res.headers.get("content-type") ?? "";
252
+ if (ct.includes("application/x-www-form-urlencoded")) {
253
+ const text = await res.text();
254
+ const p = new URLSearchParams(text);
255
+ if (p.get("error"))
256
+ throw new Error(`${config.vendor}: ${p.get("error_description") ?? p.get("error")}`);
257
+ return {
258
+ access_token: p.get("access_token") ?? "",
259
+ refresh_token: p.get("refresh_token") ?? undefined,
260
+ expires_in: p.get("expires_in") ? Number(p.get("expires_in")) : undefined,
261
+ scope: p.get("scope") ?? undefined,
262
+ };
263
+ }
264
+ return (await res.json());
265
+ }
266
+ /** Complete the authorize flow. Persists token file. */
267
+ export async function completeAuthorize(config, code, state, profile) {
268
+ gcPending();
269
+ const p = pending.get(state);
270
+ if (!p)
271
+ throw new Error(`${config.vendor}: invalid or expired state`);
272
+ pending.delete(state);
273
+ if (p.vendor !== config.vendor)
274
+ throw new Error(`${config.vendor}: vendor mismatch on state`);
275
+ const tok = await exchangeCode(config, code, p.verifier, p.clientId, p.clientSecret);
276
+ if (!tok.access_token)
277
+ throw new Error(`${config.vendor}: empty access_token`);
278
+ const expiresAt = tok.expires_in
279
+ ? Date.now() + tok.expires_in * 1000
280
+ : undefined;
281
+ saveTokenFile({
282
+ vendor: config.vendor,
283
+ client_id: p.clientId,
284
+ client_secret: p.clientSecret,
285
+ access_token: tok.access_token,
286
+ refresh_token: tok.refresh_token,
287
+ expires_at: expiresAt,
288
+ scope: tok.scope,
289
+ connected_at: new Date().toISOString(),
290
+ profile,
291
+ });
292
+ return { ok: true, profile };
293
+ }
294
+ // ── Token refresh ────────────────────────────────────────────────────────────
295
+ async function refreshIfNeeded(config, file) {
296
+ const buffer = 300_000; // 5-minute buffer — avoid mid-call expiry
297
+ if (!file.expires_at || Date.now() < file.expires_at - buffer)
298
+ return file;
299
+ if (!file.refresh_token) {
300
+ // No refresh token — token is expired and can't be renewed automatically
301
+ if (file.expires_at && Date.now() >= file.expires_at) {
302
+ throw new Error(`${file.vendor}: token expired. Re-authorize via GET /connections/${file.vendor}/authorize`);
303
+ }
304
+ return file;
305
+ }
306
+ if (!config.tokenEndpoint)
307
+ return file;
308
+ const body = new URLSearchParams({
309
+ grant_type: "refresh_token",
310
+ refresh_token: file.refresh_token,
311
+ client_id: file.client_id,
312
+ });
313
+ if (file.client_secret)
314
+ body.set("client_secret", file.client_secret);
315
+ const res = await fetch(config.tokenEndpoint, {
316
+ method: "POST",
317
+ headers: {
318
+ "Content-Type": "application/x-www-form-urlencoded",
319
+ Accept: "application/json",
320
+ },
321
+ body: body.toString(),
322
+ });
323
+ if (!res.ok) {
324
+ throw new Error(`${file.vendor}: token refresh failed (${res.status}). Re-authorize via GET /connections/${file.vendor}/authorize`);
325
+ }
326
+ const json = (await res.json());
327
+ const updated = {
328
+ ...file,
329
+ access_token: json.access_token,
330
+ refresh_token: json.refresh_token ?? file.refresh_token,
331
+ expires_at: json.expires_in
332
+ ? Date.now() + json.expires_in * 1000
333
+ : undefined,
334
+ };
335
+ saveTokenFile(updated);
336
+ return updated;
337
+ }
338
+ export function getConnectorStatus(vendor) {
339
+ const file = loadTokenFile(vendor);
340
+ if (!file)
341
+ return { vendor, connected: false, needsReauth: false };
342
+ const now = Date.now();
343
+ const expiresAt = file.expires_at;
344
+ const expiresInMs = expiresAt ? expiresAt - now : undefined;
345
+ const needsReauth = !file.refresh_token && expiresAt !== undefined && now >= expiresAt;
346
+ return {
347
+ vendor,
348
+ connected: true,
349
+ expiresAt,
350
+ expiresInMs,
351
+ needsReauth,
352
+ profile: file.profile,
353
+ };
354
+ }
355
+ export function getAllConnectorStatuses() {
356
+ const vendors = ["github", "linear", "sentry"];
357
+ return vendors.map(getConnectorStatus);
358
+ }
359
+ export async function getAccessToken(vendor) {
360
+ const file = loadTokenFile(vendor);
361
+ if (!file)
362
+ throw new Error(`${vendor}: not connected`);
363
+ const config = vendorConfig(vendor);
364
+ const fresh = await refreshIfNeeded(config, file);
365
+ return fresh.access_token;
366
+ }
367
+ // ── Revocation ───────────────────────────────────────────────────────────────
368
+ export async function revoke(vendor) {
369
+ const file = loadTokenFile(vendor);
370
+ const config = vendorConfig(vendor);
371
+ if (file && config.revocationEndpoint) {
372
+ const body = new URLSearchParams({
373
+ token: file.access_token,
374
+ client_id: file.client_id,
375
+ });
376
+ if (file.client_secret)
377
+ body.set("client_secret", file.client_secret);
378
+ await fetch(config.revocationEndpoint, {
379
+ method: "POST",
380
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
381
+ body: body.toString(),
382
+ }).catch(() => { });
383
+ }
384
+ deleteTokenFile(vendor);
385
+ }
386
+ export function isConnected(vendor) {
387
+ return loadTokenFile(vendor) !== null;
388
+ }
389
+ //# sourceMappingURL=mcpOAuth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcpOAuth.js","sourceRoot":"","sources":["../../src/connectors/mcpOAuth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { type AuthContext, BaseConnector, type ConnectorError, type ConnectorStatus, type OAuthConfig } from "./baseConnector.js";
2
+ import { type FixtureEntry, type FixtureLibrary } from "./fixtureLibrary.js";
3
+ export interface MockCall {
4
+ operation: string;
5
+ input?: unknown;
6
+ matched: boolean;
7
+ }
8
+ export declare class MockConnector extends BaseConnector {
9
+ readonly providerName: string;
10
+ private readonly fixturePath?;
11
+ private readonly library;
12
+ private readonly calls;
13
+ constructor(providerName: string, options?: {
14
+ fixturePath?: string;
15
+ });
16
+ protected getOAuthConfig(): OAuthConfig | null;
17
+ authenticate(): Promise<AuthContext>;
18
+ healthCheck(): Promise<{
19
+ ok: boolean;
20
+ error?: ConnectorError;
21
+ }>;
22
+ normalizeError(error: unknown): ConnectorError;
23
+ getStatus(): ConnectorStatus;
24
+ invoke<TOutput = unknown>(operation: string, input?: unknown): Promise<TOutput>;
25
+ addFixture(entry: FixtureEntry): void;
26
+ getCalls(): MockCall[];
27
+ getLibrary(): FixtureLibrary;
28
+ }
@@ -0,0 +1,81 @@
1
+ import { BaseConnector, } from "./baseConnector.js";
2
+ import { createFixtureLibrary, findFixture, loadFixtureLibrary, recordFixture, } from "./fixtureLibrary.js";
3
+ export class MockConnector extends BaseConnector {
4
+ providerName;
5
+ fixturePath;
6
+ library;
7
+ calls = [];
8
+ constructor(providerName, options = {}) {
9
+ super();
10
+ this.providerName = providerName;
11
+ this.fixturePath = options.fixturePath;
12
+ this.library = options.fixturePath
13
+ ? (loadFixtureLibrary(options.fixturePath) ??
14
+ createFixtureLibrary(providerName))
15
+ : createFixtureLibrary(providerName);
16
+ }
17
+ getOAuthConfig() {
18
+ return null;
19
+ }
20
+ async authenticate() {
21
+ return {
22
+ token: `mock-${this.providerName}`,
23
+ scopes: ["mock"],
24
+ };
25
+ }
26
+ async healthCheck() {
27
+ return { ok: true };
28
+ }
29
+ normalizeError(error) {
30
+ if (error && typeof error === "object" && "message" in error) {
31
+ const err = error;
32
+ return {
33
+ code: err.code ?? "provider_error",
34
+ message: err.message,
35
+ retryable: err.retryable ?? false,
36
+ };
37
+ }
38
+ return {
39
+ code: "provider_error",
40
+ message: String(error),
41
+ retryable: false,
42
+ };
43
+ }
44
+ getStatus() {
45
+ return {
46
+ id: this.providerName,
47
+ status: "connected",
48
+ };
49
+ }
50
+ async invoke(operation, input) {
51
+ const fixture = findFixture(this.library, operation, input);
52
+ this.calls.push({ operation, input, matched: fixture !== null });
53
+ if (!fixture) {
54
+ throw new Error(`No mock fixture for ${this.providerName}.${operation} with input ${JSON.stringify(input ?? null)}`);
55
+ }
56
+ if (fixture.error) {
57
+ throw Object.assign(new Error(fixture.error.message), {
58
+ code: fixture.error.code,
59
+ retryable: fixture.error.retryable,
60
+ });
61
+ }
62
+ return fixture.output;
63
+ }
64
+ addFixture(entry) {
65
+ this.library.fixtures.push(entry);
66
+ if (this.fixturePath) {
67
+ recordFixture(this.fixturePath, this.providerName, entry);
68
+ }
69
+ }
70
+ getCalls() {
71
+ return [...this.calls];
72
+ }
73
+ getLibrary() {
74
+ return {
75
+ version: this.library.version,
76
+ provider: this.library.provider,
77
+ fixtures: [...this.library.fixtures],
78
+ };
79
+ }
80
+ }
81
+ //# sourceMappingURL=mockConnector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mockConnector.js","sourceRoot":"","sources":["../../src/connectors/mockConnector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Notion connector — read/write Notion databases and pages via the Notion API.
3
+ *
4
+ * Auth: API token (internal integration) or OAuth 2.0 (public integration).
5
+ * - Env var: NOTION_TOKEN overrides stored token for CI/headless use.
6
+ * - Stored: getSecretJsonSync("notion") → NotionTokens
7
+ *
8
+ * Tools: queryDatabase, getPage, search, createPage, appendBlock
9
+ *
10
+ * Extends BaseConnector for unified auth, retry, rate-limit, error handling.
11
+ */
12
+ import { type AuthContext, BaseConnector, type ConnectorError, type ConnectorStatus } from "./baseConnector.js";
13
+ export interface NotionTokens {
14
+ accessToken: string;
15
+ workspaceName?: string;
16
+ workspaceId?: string;
17
+ botId?: string;
18
+ connected_at: string;
19
+ }
20
+ export interface NotionUser {
21
+ object: "user";
22
+ id: string;
23
+ name?: string;
24
+ avatar_url?: string;
25
+ type: "person" | "bot";
26
+ }
27
+ export interface NotionRichText {
28
+ type: "text";
29
+ text: {
30
+ content: string;
31
+ link?: {
32
+ url: string;
33
+ } | null;
34
+ };
35
+ plain_text: string;
36
+ href?: string | null;
37
+ }
38
+ export interface NotionPage {
39
+ object: "page";
40
+ id: string;
41
+ created_time: string;
42
+ last_edited_time: string;
43
+ archived: boolean;
44
+ url: string;
45
+ properties: Record<string, unknown>;
46
+ parent: {
47
+ type: string;
48
+ database_id?: string;
49
+ page_id?: string;
50
+ };
51
+ }
52
+ export interface NotionDatabase {
53
+ object: "database";
54
+ id: string;
55
+ title: NotionRichText[];
56
+ description?: NotionRichText[];
57
+ created_time: string;
58
+ last_edited_time: string;
59
+ url: string;
60
+ properties: Record<string, unknown>;
61
+ }
62
+ export interface NotionBlock {
63
+ object: "block";
64
+ id: string;
65
+ type: string;
66
+ created_time: string;
67
+ last_edited_time: string;
68
+ has_children: boolean;
69
+ [key: string]: unknown;
70
+ }
71
+ export interface NotionQueryResult {
72
+ object: "list";
73
+ results: NotionPage[];
74
+ next_cursor: string | null;
75
+ has_more: boolean;
76
+ }
77
+ export interface NotionSearchResult {
78
+ object: "list";
79
+ results: Array<NotionPage | NotionDatabase>;
80
+ next_cursor: string | null;
81
+ has_more: boolean;
82
+ }
83
+ export interface CreatePageParams {
84
+ parentId: string;
85
+ parentType: "database" | "page";
86
+ title: string;
87
+ properties?: Record<string, unknown>;
88
+ content?: string;
89
+ }
90
+ export interface AppendBlockParams {
91
+ pageId: string;
92
+ content: string;
93
+ blockType?: "paragraph" | "bulleted_list_item" | "numbered_list_item" | "heading_1" | "heading_2" | "heading_3" | "quote" | "code";
94
+ }
95
+ export declare function loadTokens(): NotionTokens | null;
96
+ export declare function saveTokens(tokens: NotionTokens): void;
97
+ export declare function clearTokens(): void;
98
+ export declare class NotionConnector extends BaseConnector {
99
+ readonly providerName = "notion";
100
+ protected cachedTokens: NotionTokens | null;
101
+ protected getOAuthConfig(): null;
102
+ authenticate(): Promise<AuthContext>;
103
+ healthCheck(): Promise<{
104
+ ok: boolean;
105
+ error?: ConnectorError;
106
+ }>;
107
+ normalizeError(error: unknown): ConnectorError;
108
+ getStatus(): ConnectorStatus;
109
+ private buildHeaders;
110
+ queryDatabase(databaseId: string, filter?: Record<string, unknown>, sorts?: Array<{
111
+ property: string;
112
+ direction: "ascending" | "descending";
113
+ }>, pageSize?: number): Promise<NotionQueryResult>;
114
+ getPage(pageId: string): Promise<NotionPage>;
115
+ search(query: string, filterType?: "page" | "database", pageSize?: number): Promise<NotionSearchResult>;
116
+ createPage(params: CreatePageParams): Promise<NotionPage>;
117
+ appendBlock(params: AppendBlockParams): Promise<{
118
+ results: NotionBlock[];
119
+ }>;
120
+ }
121
+ export declare function getNotionConnector(): NotionConnector;
122
+ export declare function resetNotionConnector(): void;
123
+ export { loadTokens as isConnected };
124
+ export interface ConnectorHandlerResult {
125
+ status: number;
126
+ body: string;
127
+ contentType?: string;
128
+ }
129
+ /**
130
+ * POST /connections/notion/connect { token: "secret_..." }
131
+ * Stores the integration token and verifies it by calling /users/me.
132
+ */
133
+ export declare function handleNotionConnect(body: string): Promise<ConnectorHandlerResult>;
134
+ /**
135
+ * POST /connections/notion/test
136
+ * Verifies stored token is still valid.
137
+ */
138
+ export declare function handleNotionTest(): Promise<ConnectorHandlerResult>;
139
+ /**
140
+ * DELETE /connections/notion
141
+ * Removes stored token.
142
+ */
143
+ export declare function handleNotionDisconnect(): ConnectorHandlerResult;