patchwork-os 0.2.0-alpha.21 → 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 (169) hide show
  1. package/README.md +26 -12
  2. package/deploy/bootstrap-vps.sh +184 -0
  3. package/dist/approvalHttp.js +6 -1
  4. package/dist/approvalHttp.js.map +1 -1
  5. package/dist/automation.d.ts +20 -0
  6. package/dist/automation.js +35 -0
  7. package/dist/automation.js.map +1 -1
  8. package/dist/bridge.js +22 -4
  9. package/dist/bridge.js.map +1 -1
  10. package/dist/bridgeToken.js +57 -19
  11. package/dist/bridgeToken.js.map +1 -1
  12. package/dist/commands/recipe.d.ts +256 -0
  13. package/dist/commands/recipe.js +1313 -0
  14. package/dist/commands/recipe.js.map +1 -0
  15. package/dist/config.d.ts +8 -0
  16. package/dist/config.js +9 -0
  17. package/dist/config.js.map +1 -1
  18. package/dist/connectors/baseConnector.d.ts +117 -0
  19. package/dist/connectors/baseConnector.js +213 -0
  20. package/dist/connectors/baseConnector.js.map +1 -0
  21. package/dist/connectors/confluence.d.ts +111 -0
  22. package/dist/connectors/confluence.js +406 -0
  23. package/dist/connectors/confluence.js.map +1 -0
  24. package/dist/connectors/fixtureLibrary.d.ts +21 -0
  25. package/dist/connectors/fixtureLibrary.js +70 -0
  26. package/dist/connectors/fixtureLibrary.js.map +1 -0
  27. package/dist/connectors/fixtureRecorder.d.ts +1 -0
  28. package/dist/connectors/fixtureRecorder.js +35 -0
  29. package/dist/connectors/fixtureRecorder.js.map +1 -0
  30. package/dist/connectors/github.js +2 -11
  31. package/dist/connectors/github.js.map +1 -1
  32. package/dist/connectors/gmail.js +23 -7
  33. package/dist/connectors/gmail.js.map +1 -1
  34. package/dist/connectors/googleCalendar.js +23 -7
  35. package/dist/connectors/googleCalendar.js.map +1 -1
  36. package/dist/connectors/jira.d.ts +98 -0
  37. package/dist/connectors/jira.js +379 -0
  38. package/dist/connectors/jira.js.map +1 -0
  39. package/dist/connectors/linear.js +2 -11
  40. package/dist/connectors/linear.js.map +1 -1
  41. package/dist/connectors/mcpOAuth.d.ts +1 -0
  42. package/dist/connectors/mcpOAuth.js +30 -4
  43. package/dist/connectors/mcpOAuth.js.map +1 -1
  44. package/dist/connectors/mockConnector.d.ts +28 -0
  45. package/dist/connectors/mockConnector.js +81 -0
  46. package/dist/connectors/mockConnector.js.map +1 -0
  47. package/dist/connectors/notion.d.ts +143 -0
  48. package/dist/connectors/notion.js +424 -0
  49. package/dist/connectors/notion.js.map +1 -0
  50. package/dist/connectors/sentry.js +2 -11
  51. package/dist/connectors/sentry.js.map +1 -1
  52. package/dist/connectors/slack.js +50 -15
  53. package/dist/connectors/slack.js.map +1 -1
  54. package/dist/connectors/tokenStorage.d.ts +35 -0
  55. package/dist/connectors/tokenStorage.js +394 -0
  56. package/dist/connectors/tokenStorage.js.map +1 -0
  57. package/dist/connectors/zendesk.d.ts +104 -0
  58. package/dist/connectors/zendesk.js +424 -0
  59. package/dist/connectors/zendesk.js.map +1 -0
  60. package/dist/featureFlags.d.ts +73 -0
  61. package/dist/featureFlags.js +203 -0
  62. package/dist/featureFlags.js.map +1 -0
  63. package/dist/fp/automationInterpreter.js +1 -0
  64. package/dist/fp/automationInterpreter.js.map +1 -1
  65. package/dist/fp/automationProgram.d.ts +1 -1
  66. package/dist/fp/automationProgram.js.map +1 -1
  67. package/dist/fp/policyParser.js +17 -0
  68. package/dist/fp/policyParser.js.map +1 -1
  69. package/dist/index.js +508 -36
  70. package/dist/index.js.map +1 -1
  71. package/dist/oauth.d.ts +4 -1
  72. package/dist/oauth.js +50 -14
  73. package/dist/oauth.js.map +1 -1
  74. package/dist/recipes/chainedRunner.d.ts +104 -0
  75. package/dist/recipes/chainedRunner.js +359 -0
  76. package/dist/recipes/chainedRunner.js.map +1 -0
  77. package/dist/recipes/dependencyGraph.d.ts +39 -0
  78. package/dist/recipes/dependencyGraph.js +199 -0
  79. package/dist/recipes/dependencyGraph.js.map +1 -0
  80. package/dist/recipes/legacyRecipeCompat.d.ts +1 -0
  81. package/dist/recipes/legacyRecipeCompat.js +97 -0
  82. package/dist/recipes/legacyRecipeCompat.js.map +1 -0
  83. package/dist/recipes/nestedRecipeStep.d.ts +58 -0
  84. package/dist/recipes/nestedRecipeStep.js +95 -0
  85. package/dist/recipes/nestedRecipeStep.js.map +1 -0
  86. package/dist/recipes/outputRegistry.d.ts +28 -0
  87. package/dist/recipes/outputRegistry.js +52 -0
  88. package/dist/recipes/outputRegistry.js.map +1 -0
  89. package/dist/recipes/schemaGenerator.d.ts +28 -0
  90. package/dist/recipes/schemaGenerator.js +484 -0
  91. package/dist/recipes/schemaGenerator.js.map +1 -0
  92. package/dist/recipes/templateEngine.d.ts +62 -0
  93. package/dist/recipes/templateEngine.js +182 -0
  94. package/dist/recipes/templateEngine.js.map +1 -0
  95. package/dist/recipes/toolRegistry.d.ts +181 -0
  96. package/dist/recipes/toolRegistry.js +300 -0
  97. package/dist/recipes/toolRegistry.js.map +1 -0
  98. package/dist/recipes/tools/calendar.d.ts +6 -0
  99. package/dist/recipes/tools/calendar.js +61 -0
  100. package/dist/recipes/tools/calendar.js.map +1 -0
  101. package/dist/recipes/tools/confluence.d.ts +6 -0
  102. package/dist/recipes/tools/confluence.js +254 -0
  103. package/dist/recipes/tools/confluence.js.map +1 -0
  104. package/dist/recipes/tools/diagnostics.d.ts +6 -0
  105. package/dist/recipes/tools/diagnostics.js +36 -0
  106. package/dist/recipes/tools/diagnostics.js.map +1 -0
  107. package/dist/recipes/tools/file.d.ts +6 -0
  108. package/dist/recipes/tools/file.js +170 -0
  109. package/dist/recipes/tools/file.js.map +1 -0
  110. package/dist/recipes/tools/git.d.ts +6 -0
  111. package/dist/recipes/tools/git.js +63 -0
  112. package/dist/recipes/tools/git.js.map +1 -0
  113. package/dist/recipes/tools/github.d.ts +6 -0
  114. package/dist/recipes/tools/github.js +91 -0
  115. package/dist/recipes/tools/github.js.map +1 -0
  116. package/dist/recipes/tools/gmail.d.ts +6 -0
  117. package/dist/recipes/tools/gmail.js +210 -0
  118. package/dist/recipes/tools/gmail.js.map +1 -0
  119. package/dist/recipes/tools/index.d.ts +18 -0
  120. package/dist/recipes/tools/index.js +21 -0
  121. package/dist/recipes/tools/index.js.map +1 -0
  122. package/dist/recipes/tools/linear.d.ts +6 -0
  123. package/dist/recipes/tools/linear.js +83 -0
  124. package/dist/recipes/tools/linear.js.map +1 -0
  125. package/dist/recipes/tools/notion.d.ts +6 -0
  126. package/dist/recipes/tools/notion.js +278 -0
  127. package/dist/recipes/tools/notion.js.map +1 -0
  128. package/dist/recipes/tools/slack.d.ts +6 -0
  129. package/dist/recipes/tools/slack.js +72 -0
  130. package/dist/recipes/tools/slack.js.map +1 -0
  131. package/dist/recipes/tools/zendesk.d.ts +6 -0
  132. package/dist/recipes/tools/zendesk.js +245 -0
  133. package/dist/recipes/tools/zendesk.js.map +1 -0
  134. package/dist/recipes/yamlRunner.d.ts +71 -7
  135. package/dist/recipes/yamlRunner.js +406 -439
  136. package/dist/recipes/yamlRunner.js.map +1 -1
  137. package/dist/riskTier.js +1 -0
  138. package/dist/riskTier.js.map +1 -1
  139. package/dist/runLog.d.ts +18 -0
  140. package/dist/runLog.js +5 -0
  141. package/dist/runLog.js.map +1 -1
  142. package/dist/server.d.ts +4 -0
  143. package/dist/server.js +224 -0
  144. package/dist/server.js.map +1 -1
  145. package/dist/streamableHttp.js +2 -0
  146. package/dist/streamableHttp.js.map +1 -1
  147. package/dist/tools/github/actions.js +4 -2
  148. package/dist/tools/github/actions.js.map +1 -1
  149. package/dist/tools/github/composite.d.ts +339 -0
  150. package/dist/tools/github/composite.js +343 -0
  151. package/dist/tools/github/composite.js.map +1 -0
  152. package/dist/tools/github/index.d.ts +1 -0
  153. package/dist/tools/github/index.js +1 -0
  154. package/dist/tools/github/index.js.map +1 -1
  155. package/dist/tools/github/issues.js +8 -4
  156. package/dist/tools/github/issues.js.map +1 -1
  157. package/dist/tools/github/pr.js +14 -7
  158. package/dist/tools/github/pr.js.map +1 -1
  159. package/dist/tools/index.js +10 -1
  160. package/dist/tools/index.js.map +1 -1
  161. package/dist/tools/searchTools.js +1 -1
  162. package/dist/tools/searchTools.js.map +1 -1
  163. package/dist/transport.d.ts +7 -1
  164. package/dist/transport.js +85 -11
  165. package/dist/transport.js.map +1 -1
  166. package/package.json +1 -1
  167. package/templates/automation-policies/recipe-authoring.json +25 -0
  168. package/templates/automation-policy.example.json +6 -0
  169. package/templates/recipes/lint-on-save.yaml +1 -2
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Zendesk connector — read/write Zendesk tickets via the Zendesk REST API v2.
3
+ *
4
+ * Auth: API token + email + subdomain.
5
+ * - Env vars: ZENDESK_API_TOKEN, ZENDESK_EMAIL, ZENDESK_SUBDOMAIN
6
+ * - Stored: getSecretJsonSync("zendesk") → ZendeskTokens
7
+ * - Basic auth: `email/token:api_token` (Zendesk token auth convention)
8
+ *
9
+ * Tools: listTickets, getTicket, addComment, updateStatus, listUsers
10
+ *
11
+ * Extends BaseConnector for unified auth, retry, rate-limit, error handling.
12
+ */
13
+ import { type AuthContext, BaseConnector, type ConnectorError, type ConnectorStatus } from "./baseConnector.js";
14
+ export interface ZendeskTokens {
15
+ apiToken: string;
16
+ email: string;
17
+ subdomain: string;
18
+ connected_at: string;
19
+ }
20
+ export interface ZendeskTicket {
21
+ id: number;
22
+ subject: string;
23
+ description: string;
24
+ status: "new" | "open" | "pending" | "hold" | "solved" | "closed";
25
+ priority: "urgent" | "high" | "normal" | "low" | null;
26
+ type: "problem" | "incident" | "question" | "task" | null;
27
+ requester_id: number;
28
+ assignee_id: number | null;
29
+ group_id: number | null;
30
+ tags: string[];
31
+ created_at: string;
32
+ updated_at: string;
33
+ url: string;
34
+ }
35
+ export interface ZendeskComment {
36
+ id: number;
37
+ type: "Comment" | "VoiceComment";
38
+ author_id: number;
39
+ body: string;
40
+ html_body: string;
41
+ public: boolean;
42
+ created_at: string;
43
+ }
44
+ export interface ZendeskUser {
45
+ id: number;
46
+ name: string;
47
+ email: string;
48
+ role: "end-user" | "agent" | "admin";
49
+ active: boolean;
50
+ created_at: string;
51
+ }
52
+ export interface ZendeskListResult<T> {
53
+ results: T[];
54
+ count: number;
55
+ next_page: string | null;
56
+ previous_page: string | null;
57
+ }
58
+ export declare class ZendeskConnector extends BaseConnector {
59
+ readonly providerName = "zendesk";
60
+ private tokens;
61
+ protected getOAuthConfig(): null;
62
+ authenticate(): Promise<AuthContext>;
63
+ healthCheck(): Promise<{
64
+ ok: boolean;
65
+ error?: ConnectorError;
66
+ }>;
67
+ normalizeError(error: unknown): ConnectorError;
68
+ getStatus(): ConnectorStatus;
69
+ listTickets(params?: {
70
+ status?: ZendeskTicket["status"];
71
+ assigneeId?: number;
72
+ query?: string;
73
+ perPage?: number;
74
+ }): Promise<ZendeskListResult<ZendeskTicket>>;
75
+ getTicket(ticketId: number): Promise<ZendeskTicket | null>;
76
+ getTicketComments(ticketId: number): Promise<ZendeskComment[]>;
77
+ addComment(ticketId: number, body: string, isPublic?: boolean): Promise<ZendeskTicket>;
78
+ updateStatus(ticketId: number, status: ZendeskTicket["status"]): Promise<ZendeskTicket>;
79
+ listUsers(role?: ZendeskUser["role"], perPage?: number): Promise<ZendeskUser[]>;
80
+ private baseUrl;
81
+ private buildHeaders;
82
+ }
83
+ export declare function loadTokens(): ZendeskTokens | null;
84
+ export declare function saveTokens(tokens: ZendeskTokens): void;
85
+ export declare function clearTokens(): void;
86
+ export declare function getZendeskConnector(): ZendeskConnector;
87
+ export { getZendeskConnector as zendesk };
88
+ export interface ConnectorHandlerResult {
89
+ status: number;
90
+ body: string;
91
+ contentType?: string;
92
+ }
93
+ /**
94
+ * POST /connections/zendesk/connect { apiToken, email, subdomain }
95
+ */
96
+ export declare function handleZendeskConnect(body: string): Promise<ConnectorHandlerResult>;
97
+ /**
98
+ * POST /connections/zendesk/test
99
+ */
100
+ export declare function handleZendeskTest(): Promise<ConnectorHandlerResult>;
101
+ /**
102
+ * DELETE /connections/zendesk
103
+ */
104
+ export declare function handleZendeskDisconnect(): ConnectorHandlerResult;
@@ -0,0 +1,424 @@
1
+ /**
2
+ * Zendesk connector — read/write Zendesk tickets via the Zendesk REST API v2.
3
+ *
4
+ * Auth: API token + email + subdomain.
5
+ * - Env vars: ZENDESK_API_TOKEN, ZENDESK_EMAIL, ZENDESK_SUBDOMAIN
6
+ * - Stored: getSecretJsonSync("zendesk") → ZendeskTokens
7
+ * - Basic auth: `email/token:api_token` (Zendesk token auth convention)
8
+ *
9
+ * Tools: listTickets, getTicket, addComment, updateStatus, listUsers
10
+ *
11
+ * Extends BaseConnector for unified auth, retry, rate-limit, error handling.
12
+ */
13
+ import { BaseConnector, } from "./baseConnector.js";
14
+ import { deleteSecretJsonSync, getSecretJsonSync, storeSecretJsonSync, } from "./tokenStorage.js";
15
+ export class ZendeskConnector extends BaseConnector {
16
+ providerName = "zendesk";
17
+ tokens = null;
18
+ getOAuthConfig() {
19
+ return null;
20
+ }
21
+ async authenticate() {
22
+ const tokens = loadTokens();
23
+ if (!tokens) {
24
+ throw new Error("Zendesk not connected. Run: patchwork-os connect zendesk or set ZENDESK_API_TOKEN");
25
+ }
26
+ this.tokens = tokens;
27
+ return {
28
+ token: tokens.apiToken,
29
+ scopes: ["read", "write"],
30
+ };
31
+ }
32
+ async healthCheck() {
33
+ try {
34
+ const result = await this.apiCall(async (token) => {
35
+ const res = await fetch(`${this.baseUrl()}/api/v2/users/me`, {
36
+ headers: this.buildHeaders(token),
37
+ });
38
+ if (!res.ok)
39
+ throw new Error(`HTTP ${res.status}`);
40
+ return res.json();
41
+ });
42
+ if ("error" in result)
43
+ return { ok: false, error: result.error };
44
+ return { ok: true };
45
+ }
46
+ catch (err) {
47
+ return { ok: false, error: this.normalizeError(err) };
48
+ }
49
+ }
50
+ normalizeError(error) {
51
+ if (error instanceof Response) {
52
+ const s = error.status;
53
+ if (s === 401)
54
+ return {
55
+ code: "auth_expired",
56
+ message: "Zendesk authentication expired — reconnect",
57
+ retryable: false,
58
+ suggestedAction: "patchwork-os connect zendesk",
59
+ };
60
+ if (s === 403)
61
+ return {
62
+ code: "permission_denied",
63
+ message: "Insufficient Zendesk permissions",
64
+ retryable: false,
65
+ };
66
+ if (s === 404)
67
+ return {
68
+ code: "not_found",
69
+ message: "Zendesk ticket or resource not found",
70
+ retryable: false,
71
+ };
72
+ if (s === 429)
73
+ return {
74
+ code: "rate_limited",
75
+ message: "Zendesk API rate limit exceeded",
76
+ retryable: true,
77
+ suggestedAction: "Wait and retry",
78
+ };
79
+ return {
80
+ code: "provider_error",
81
+ message: `Zendesk API error: HTTP ${s}`,
82
+ retryable: s >= 500,
83
+ };
84
+ }
85
+ if (error instanceof Error) {
86
+ if (error.message.includes("ENOTFOUND") ||
87
+ error.message.includes("ECONNREFUSED")) {
88
+ return {
89
+ code: "network_error",
90
+ message: `Cannot connect to Zendesk: ${error.message}`,
91
+ retryable: true,
92
+ };
93
+ }
94
+ }
95
+ return {
96
+ code: "provider_error",
97
+ message: error instanceof Error ? error.message : String(error),
98
+ retryable: false,
99
+ };
100
+ }
101
+ getStatus() {
102
+ const tokens = loadTokens();
103
+ return {
104
+ id: "zendesk",
105
+ status: tokens ? "connected" : "disconnected",
106
+ lastSync: tokens?.connected_at,
107
+ workspace: tokens ? `https://${tokens.subdomain}.zendesk.com` : undefined,
108
+ };
109
+ }
110
+ // ── API Methods ────────────────────────────────────────────────────────────
111
+ async listTickets(params = {}) {
112
+ const result = await this.apiCall(async (token) => {
113
+ let url;
114
+ if (params.query) {
115
+ const q = encodeURIComponent(`type:ticket ${params.query}`);
116
+ url = `${this.baseUrl()}/api/v2/search.json?query=${q}&per_page=${params.perPage ?? 25}`;
117
+ }
118
+ else {
119
+ const qs = new URLSearchParams({
120
+ per_page: String(params.perPage ?? 25),
121
+ });
122
+ if (params.status)
123
+ qs.set("status", params.status);
124
+ if (params.assigneeId)
125
+ qs.set("assignee_id", String(params.assigneeId));
126
+ url = `${this.baseUrl()}/api/v2/tickets.json?${qs}`;
127
+ }
128
+ const res = await fetch(url, { headers: this.buildHeaders(token) });
129
+ this.updateRateLimitFromHeaders({
130
+ "x-ratelimit-remaining": res.headers.get("x-ratelimit-remaining") ?? undefined,
131
+ "retry-after": res.headers.get("retry-after") ?? undefined,
132
+ });
133
+ if (!res.ok)
134
+ throw res;
135
+ const data = (await res.json());
136
+ const items = data.tickets ?? data.results ?? [];
137
+ return {
138
+ results: items,
139
+ count: data.count ?? items.length,
140
+ next_page: data.next_page ?? null,
141
+ previous_page: data.previous_page ?? null,
142
+ };
143
+ });
144
+ if ("error" in result)
145
+ throw new Error(result.error.message);
146
+ return result.data;
147
+ }
148
+ async getTicket(ticketId) {
149
+ const result = await this.apiCall(async (token) => {
150
+ const res = await fetch(`${this.baseUrl()}/api/v2/tickets/${ticketId}.json`, {
151
+ headers: this.buildHeaders(token),
152
+ });
153
+ if (res.status === 404)
154
+ return null;
155
+ if (!res.ok)
156
+ throw res;
157
+ const data = (await res.json());
158
+ return data.ticket;
159
+ });
160
+ if ("error" in result)
161
+ throw new Error(result.error.message);
162
+ return result.data;
163
+ }
164
+ async getTicketComments(ticketId) {
165
+ const result = await this.apiCall(async (token) => {
166
+ const res = await fetch(`${this.baseUrl()}/api/v2/tickets/${ticketId}/comments.json`, { headers: this.buildHeaders(token) });
167
+ if (!res.ok)
168
+ throw res;
169
+ const data = (await res.json());
170
+ return data.comments;
171
+ });
172
+ if ("error" in result)
173
+ throw new Error(result.error.message);
174
+ return result.data;
175
+ }
176
+ async addComment(ticketId, body, isPublic = true) {
177
+ const result = await this.apiCall(async (token) => {
178
+ const res = await fetch(`${this.baseUrl()}/api/v2/tickets/${ticketId}.json`, {
179
+ method: "PUT",
180
+ headers: {
181
+ ...this.buildHeaders(token),
182
+ "Content-Type": "application/json",
183
+ },
184
+ body: JSON.stringify({
185
+ ticket: {
186
+ comment: { body, public: isPublic },
187
+ },
188
+ }),
189
+ });
190
+ if (!res.ok)
191
+ throw res;
192
+ const data = (await res.json());
193
+ return data.ticket;
194
+ });
195
+ if ("error" in result)
196
+ throw new Error(result.error.message);
197
+ return result.data;
198
+ }
199
+ async updateStatus(ticketId, status) {
200
+ const result = await this.apiCall(async (token) => {
201
+ const res = await fetch(`${this.baseUrl()}/api/v2/tickets/${ticketId}.json`, {
202
+ method: "PUT",
203
+ headers: {
204
+ ...this.buildHeaders(token),
205
+ "Content-Type": "application/json",
206
+ },
207
+ body: JSON.stringify({ ticket: { status } }),
208
+ });
209
+ if (!res.ok)
210
+ throw res;
211
+ const data = (await res.json());
212
+ return data.ticket;
213
+ });
214
+ if ("error" in result)
215
+ throw new Error(result.error.message);
216
+ return result.data;
217
+ }
218
+ async listUsers(role, perPage = 50) {
219
+ const result = await this.apiCall(async (token) => {
220
+ const qs = new URLSearchParams({ per_page: String(perPage) });
221
+ if (role)
222
+ qs.set("role", role);
223
+ const res = await fetch(`${this.baseUrl()}/api/v2/users.json?${qs}`, {
224
+ headers: this.buildHeaders(token),
225
+ });
226
+ if (!res.ok)
227
+ throw res;
228
+ const data = (await res.json());
229
+ return data.users;
230
+ });
231
+ if ("error" in result)
232
+ throw new Error(result.error.message);
233
+ return result.data;
234
+ }
235
+ // ── Helpers ────────────────────────────────────────────────────────────────
236
+ baseUrl() {
237
+ return `https://${this.tokens?.subdomain}.zendesk.com`;
238
+ }
239
+ buildHeaders(token) {
240
+ const email = this.tokens?.email ?? "";
241
+ // Zendesk token auth: email/token:api_token
242
+ const basic = Buffer.from(`${email}/token:${token}`).toString("base64");
243
+ return {
244
+ Authorization: `Basic ${basic}`,
245
+ Accept: "application/json",
246
+ };
247
+ }
248
+ }
249
+ // ── Token persistence ────────────────────────────────────────────────────────
250
+ export function loadTokens() {
251
+ const envToken = process.env.ZENDESK_API_TOKEN;
252
+ const envEmail = process.env.ZENDESK_EMAIL;
253
+ const envSubdomain = process.env.ZENDESK_SUBDOMAIN;
254
+ if (envToken && envEmail && envSubdomain) {
255
+ return {
256
+ apiToken: envToken,
257
+ email: envEmail,
258
+ subdomain: envSubdomain,
259
+ connected_at: new Date().toISOString(),
260
+ };
261
+ }
262
+ return getSecretJsonSync("zendesk");
263
+ }
264
+ export function saveTokens(tokens) {
265
+ storeSecretJsonSync("zendesk", tokens);
266
+ }
267
+ export function clearTokens() {
268
+ try {
269
+ deleteSecretJsonSync("zendesk");
270
+ }
271
+ catch {
272
+ // ignore
273
+ }
274
+ }
275
+ // ── Singleton instance ───────────────────────────────────────────────────────
276
+ let _instance = null;
277
+ function resetZendeskConnector() {
278
+ _instance = null;
279
+ }
280
+ export function getZendeskConnector() {
281
+ if (!_instance) {
282
+ _instance = new ZendeskConnector();
283
+ }
284
+ return _instance;
285
+ }
286
+ export { getZendeskConnector as zendesk };
287
+ /**
288
+ * POST /connections/zendesk/connect { apiToken, email, subdomain }
289
+ */
290
+ export async function handleZendeskConnect(body) {
291
+ let apiToken;
292
+ let email;
293
+ let subdomain;
294
+ try {
295
+ const parsed = JSON.parse(body);
296
+ if (typeof parsed.apiToken !== "string" || !parsed.apiToken) {
297
+ return {
298
+ status: 400,
299
+ contentType: "application/json",
300
+ body: JSON.stringify({ ok: false, error: "apiToken is required" }),
301
+ };
302
+ }
303
+ if (typeof parsed.email !== "string" || !parsed.email) {
304
+ return {
305
+ status: 400,
306
+ contentType: "application/json",
307
+ body: JSON.stringify({ ok: false, error: "email is required" }),
308
+ };
309
+ }
310
+ if (typeof parsed.subdomain !== "string" || !parsed.subdomain) {
311
+ return {
312
+ status: 400,
313
+ contentType: "application/json",
314
+ body: JSON.stringify({
315
+ ok: false,
316
+ error: 'subdomain is required (e.g. "acme" for acme.zendesk.com)',
317
+ }),
318
+ };
319
+ }
320
+ apiToken = parsed.apiToken;
321
+ email = parsed.email;
322
+ subdomain = parsed.subdomain.replace(/\.zendesk\.com$/, ""); // strip if full domain given
323
+ }
324
+ catch {
325
+ return {
326
+ status: 400,
327
+ contentType: "application/json",
328
+ body: JSON.stringify({ ok: false, error: "Invalid JSON body" }),
329
+ };
330
+ }
331
+ try {
332
+ const basic = Buffer.from(`${email}/token:${apiToken}`).toString("base64");
333
+ const res = await fetch(`https://${subdomain}.zendesk.com/api/v2/users/me.json`, {
334
+ headers: {
335
+ Authorization: `Basic ${basic}`,
336
+ Accept: "application/json",
337
+ },
338
+ });
339
+ if (!res.ok) {
340
+ return {
341
+ status: 401,
342
+ contentType: "application/json",
343
+ body: JSON.stringify({
344
+ ok: false,
345
+ error: `Credentials rejected by Zendesk (HTTP ${res.status}) — check apiToken, email, and subdomain`,
346
+ }),
347
+ };
348
+ }
349
+ const me = (await res.json());
350
+ const tokens = {
351
+ apiToken,
352
+ email,
353
+ subdomain,
354
+ connected_at: new Date().toISOString(),
355
+ };
356
+ saveTokens(tokens);
357
+ resetZendeskConnector();
358
+ return {
359
+ status: 200,
360
+ contentType: "application/json",
361
+ body: JSON.stringify({
362
+ ok: true,
363
+ subdomain,
364
+ user: me.user?.name ?? me.user?.email ?? "unknown",
365
+ connectedAt: tokens.connected_at,
366
+ }),
367
+ };
368
+ }
369
+ catch (err) {
370
+ return {
371
+ status: 500,
372
+ contentType: "application/json",
373
+ body: JSON.stringify({
374
+ ok: false,
375
+ error: err instanceof Error ? err.message : String(err),
376
+ }),
377
+ };
378
+ }
379
+ }
380
+ /**
381
+ * POST /connections/zendesk/test
382
+ */
383
+ export async function handleZendeskTest() {
384
+ const tokens = loadTokens();
385
+ if (!tokens) {
386
+ return {
387
+ status: 400,
388
+ contentType: "application/json",
389
+ body: JSON.stringify({ ok: false, error: "Zendesk not connected" }),
390
+ };
391
+ }
392
+ try {
393
+ const connector = getZendeskConnector();
394
+ const check = await connector.healthCheck();
395
+ return {
396
+ status: check.ok ? 200 : 401,
397
+ contentType: "application/json",
398
+ body: JSON.stringify(check.ok ? { ok: true } : { ok: false, error: check.error?.message }),
399
+ };
400
+ }
401
+ catch (err) {
402
+ return {
403
+ status: 500,
404
+ contentType: "application/json",
405
+ body: JSON.stringify({
406
+ ok: false,
407
+ error: err instanceof Error ? err.message : String(err),
408
+ }),
409
+ };
410
+ }
411
+ }
412
+ /**
413
+ * DELETE /connections/zendesk
414
+ */
415
+ export function handleZendeskDisconnect() {
416
+ clearTokens();
417
+ resetZendeskConnector();
418
+ return {
419
+ status: 200,
420
+ contentType: "application/json",
421
+ body: JSON.stringify({ ok: true }),
422
+ };
423
+ }
424
+ //# sourceMappingURL=zendesk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zendesk.js","sourceRoot":"","sources":["../../src/connectors/zendesk.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Feature Flags — runtime gating for new surfaces and kill switches.
3
+ *
4
+ * Supports:
5
+ * - File-based flags (~/.patchwork/config/flags.json)
6
+ * - Environment variable overrides
7
+ * - Kill switch for write-tier operations
8
+ * - Per-feature opt-in with default-off safety
9
+ */
10
+ /** Flag definition */
11
+ export interface FeatureFlag {
12
+ /** Flag identifier (kebab-case) */
13
+ id: string;
14
+ /** Human-readable description */
15
+ description: string;
16
+ /** Default state if not explicitly set */
17
+ defaultValue: boolean;
18
+ /** Category for grouping in dashboard */
19
+ category: "safety" | "ui" | "connector" | "experimental";
20
+ /** Whether this flag requires explicit opt-in (not auto-enabled) */
21
+ requiresOptIn: boolean;
22
+ /** For kill switches: when true, blocks writes */
23
+ isKillSwitch?: boolean;
24
+ }
25
+ /**
26
+ * Register a feature flag. Should be called at module init.
27
+ * Duplicate IDs throw — ensures no accidental double-registration.
28
+ */
29
+ export declare function registerFlag(flag: FeatureFlag): void;
30
+ /**
31
+ * Check if a feature flag is enabled.
32
+ * Resolution order (highest to lowest priority):
33
+ * 1. Environment variable (PATCHWORK_FLAG_<ID>)
34
+ * 2. User config file (~/.patchwork/config/flags.json)
35
+ * 3. Default value from registration
36
+ */
37
+ export declare function isEnabled(flagId: string): boolean;
38
+ /**
39
+ * Set a flag value (persists to config file if persist=true).
40
+ */
41
+ export declare function setFlag(flagId: string, value: boolean, persist?: boolean): void;
42
+ /**
43
+ * Get all registered flags with their current values.
44
+ */
45
+ export declare function listFlags(): Array<FeatureFlag & {
46
+ currentValue: boolean;
47
+ }>;
48
+ /**
49
+ * Load flags from config file.
50
+ */
51
+ export declare function loadFlags(): void;
52
+ /** Kill switch for ALL write-tier operations */
53
+ export declare const KILL_SWITCH_WRITES = "kill-switch.writes";
54
+ /** Enable visual recipe debugger (A3) */
55
+ export declare const FLAG_DEBUGGER = "ui.recipe-debugger";
56
+ /** Enable CLI test/watch commands (A2) */
57
+ export declare const FLAG_CLI_UX = "ui.cli-ux-commands";
58
+ /** Enable mock connector harness (A4) */
59
+ export declare const FLAG_MOCK_HARNESS = "experimental.mock-harness";
60
+ /** Enable Wave 2 connectors (A5) */
61
+ export declare const FLAG_WAVE2_CONNECTORS = "connector.wave2";
62
+ /** Enable recipe lint with schema validation (A1) */
63
+ export declare const FLAG_SCHEMA_LINT = "ui.schema-lint";
64
+ /** Enable community recipe gallery (M5) */
65
+ export declare const FLAG_COMMUNITY_GALLERY = "experimental.community-gallery";
66
+ /**
67
+ * Check if write operations are globally disabled.
68
+ */
69
+ export declare function isWriteKillSwitchActive(): boolean;
70
+ /**
71
+ * Assert write is allowed — throws if kill switch is active.
72
+ */
73
+ export declare function assertWriteAllowed(operation: string): void;