@almadar/integrations 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1336 @@
1
+ import integratorsRegistry from '@almadar/patterns/integrators-registry.json';
2
+ import Stripe from 'stripe';
3
+ import { google } from 'googleapis';
4
+ import twilio from 'twilio';
5
+ import sgMail from '@sendgrid/mail';
6
+ import { Resend } from 'resend';
7
+ import { spawn } from 'child_process';
8
+ import { promises } from 'fs';
9
+ import { join } from 'path';
10
+
11
+ // src/core/logger.ts
12
+ var ConsoleLogger = class {
13
+ constructor(level = "info") {
14
+ this.level = level;
15
+ }
16
+ debug(message, meta) {
17
+ if (this.shouldLog("debug")) {
18
+ console.debug(`[DEBUG] ${message}`, meta || "");
19
+ }
20
+ }
21
+ info(message, meta) {
22
+ if (this.shouldLog("info")) {
23
+ console.log(`[INFO] ${message}`, meta || "");
24
+ }
25
+ }
26
+ warn(message, meta) {
27
+ if (this.shouldLog("warn")) {
28
+ console.warn(`[WARN] ${message}`, meta || "");
29
+ }
30
+ }
31
+ error(message, meta) {
32
+ if (this.shouldLog("error")) {
33
+ console.error(`[ERROR] ${message}`, meta || "");
34
+ }
35
+ }
36
+ shouldLog(level) {
37
+ const levels = ["debug", "info", "warn", "error"];
38
+ return levels.indexOf(level) >= levels.indexOf(this.level);
39
+ }
40
+ };
41
+ function validateParams(integration, action, params) {
42
+ const registry = integratorsRegistry.integrators[integration];
43
+ if (!registry) {
44
+ return {
45
+ valid: false,
46
+ errors: [
47
+ {
48
+ param: "integration",
49
+ message: `Unknown integration: ${integration}`
50
+ }
51
+ ]
52
+ };
53
+ }
54
+ const actionDef = registry.actions.find((a) => a.name === action);
55
+ if (!actionDef) {
56
+ return {
57
+ valid: false,
58
+ errors: [{ param: "action", message: `Unknown action: ${action}` }]
59
+ };
60
+ }
61
+ const errors = [];
62
+ for (const paramDef of actionDef.params) {
63
+ if (paramDef.required && !(paramDef.name in params)) {
64
+ errors.push({
65
+ param: paramDef.name,
66
+ message: `Missing required parameter: ${paramDef.name}`
67
+ });
68
+ }
69
+ if (paramDef.name in params) {
70
+ const value = params[paramDef.name];
71
+ const expectedType = paramDef.type;
72
+ const actualType = typeof value;
73
+ if (expectedType === "number" && actualType !== "number") {
74
+ errors.push({
75
+ param: paramDef.name,
76
+ message: `Expected ${expectedType}, got ${actualType}`
77
+ });
78
+ }
79
+ if (expectedType === "string" && actualType !== "string") {
80
+ errors.push({
81
+ param: paramDef.name,
82
+ message: `Expected ${expectedType}, got ${actualType}`
83
+ });
84
+ }
85
+ if (expectedType === "array" && !Array.isArray(value)) {
86
+ errors.push({
87
+ param: paramDef.name,
88
+ message: `Expected array, got ${actualType}`
89
+ });
90
+ }
91
+ if (expectedType === "object" && (actualType !== "object" || Array.isArray(value) || value === null)) {
92
+ errors.push({
93
+ param: paramDef.name,
94
+ message: `Expected object, got ${actualType}`
95
+ });
96
+ }
97
+ }
98
+ }
99
+ return {
100
+ valid: errors.length === 0,
101
+ errors
102
+ };
103
+ }
104
+
105
+ // src/core/retry.ts
106
+ async function withRetry(fn, config) {
107
+ const {
108
+ maxAttempts,
109
+ backoffMs,
110
+ maxBackoffMs = 3e4,
111
+ retryableErrors
112
+ } = config;
113
+ let lastError;
114
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
115
+ try {
116
+ return await fn();
117
+ } catch (error) {
118
+ lastError = error;
119
+ if (error && typeof error === "object" && "code" in error && retryableErrors) {
120
+ const integrationError = error;
121
+ if (!retryableErrors.includes(integrationError.code)) {
122
+ throw error;
123
+ }
124
+ }
125
+ if (attempt === maxAttempts) {
126
+ throw error;
127
+ }
128
+ const delay = Math.min(
129
+ backoffMs * Math.pow(2, attempt - 1),
130
+ maxBackoffMs
131
+ );
132
+ await new Promise((resolve) => setTimeout(resolve, delay));
133
+ }
134
+ }
135
+ throw lastError;
136
+ }
137
+
138
+ // src/core/BaseIntegration.ts
139
+ var BaseIntegration = class {
140
+ constructor(config) {
141
+ this.config = config;
142
+ this.logger = config.logger || new ConsoleLogger();
143
+ }
144
+ /**
145
+ * Validate action params against registry
146
+ */
147
+ validateParams(action, params) {
148
+ return validateParams(this.config.name, action, params);
149
+ }
150
+ /**
151
+ * Handle errors uniformly
152
+ */
153
+ handleError(action, error) {
154
+ this.logger.error(`Integration error in ${this.config.name}.${action}`, {
155
+ error
156
+ });
157
+ const integrationError = error instanceof Error ? error : new Error(String(error));
158
+ return {
159
+ success: false,
160
+ error: integrationError,
161
+ metadata: this.createMetadata(action, 0, 0)
162
+ };
163
+ }
164
+ /**
165
+ * Create metadata for result
166
+ */
167
+ createMetadata(action, duration, retries = 0) {
168
+ return {
169
+ integration: this.config.name,
170
+ action,
171
+ duration,
172
+ retries,
173
+ timestamp: Date.now()
174
+ };
175
+ }
176
+ /**
177
+ * Execute with retry logic
178
+ */
179
+ async executeWithRetry(fn) {
180
+ if (!this.config.retry) {
181
+ return fn();
182
+ }
183
+ return withRetry(fn, {
184
+ maxAttempts: this.config.retry.maxAttempts,
185
+ backoffMs: this.config.retry.backoffMs,
186
+ maxBackoffMs: this.config.retry.maxBackoffMs,
187
+ retryableErrors: [
188
+ "TIMEOUT_ERROR",
189
+ "NETWORK_ERROR",
190
+ "RATE_LIMIT_ERROR"
191
+ ]
192
+ });
193
+ }
194
+ };
195
+
196
+ // src/registry.ts
197
+ var INTEGRATION_REGISTRY = {};
198
+ function registerIntegration(name, constructor) {
199
+ INTEGRATION_REGISTRY[name] = constructor;
200
+ }
201
+ function getIntegration(name) {
202
+ return INTEGRATION_REGISTRY[name];
203
+ }
204
+ function isKnownIntegration(name) {
205
+ return name in INTEGRATION_REGISTRY;
206
+ }
207
+ function getRegisteredIntegrations() {
208
+ return Object.keys(INTEGRATION_REGISTRY);
209
+ }
210
+
211
+ // src/factory.ts
212
+ var IntegrationFactory = class {
213
+ constructor() {
214
+ this.instances = /* @__PURE__ */ new Map();
215
+ this.configs = /* @__PURE__ */ new Map();
216
+ }
217
+ /**
218
+ * Configure an integration (doesn't instantiate yet)
219
+ */
220
+ configure(name, config) {
221
+ this.configs.set(name, { name, ...config });
222
+ }
223
+ /**
224
+ * Get or create an integration instance
225
+ */
226
+ get(name) {
227
+ if (this.instances.has(name)) {
228
+ return this.instances.get(name);
229
+ }
230
+ const Constructor = getIntegration(name);
231
+ if (!Constructor) {
232
+ throw new Error(`Unknown integration: ${name}. Make sure it's imported.`);
233
+ }
234
+ const config = this.configs.get(name);
235
+ if (!config) {
236
+ throw new Error(
237
+ `Integration not configured: ${name}. Call configure() first.`
238
+ );
239
+ }
240
+ const instance = new Constructor(config);
241
+ this.instances.set(name, instance);
242
+ return instance;
243
+ }
244
+ /**
245
+ * Execute an action on an integration
246
+ */
247
+ async execute(integration, action, params) {
248
+ const instance = this.get(integration);
249
+ return await instance.execute(action, params);
250
+ }
251
+ /**
252
+ * Check if integration is configured
253
+ */
254
+ isConfigured(name) {
255
+ return this.configs.has(name);
256
+ }
257
+ /**
258
+ * Clear all instances (useful for testing)
259
+ */
260
+ clear() {
261
+ this.instances.clear();
262
+ }
263
+ /**
264
+ * Clear all instances and configs
265
+ */
266
+ reset() {
267
+ this.instances.clear();
268
+ this.configs.clear();
269
+ }
270
+ };
271
+ var StripeIntegration = class extends BaseIntegration {
272
+ constructor(config) {
273
+ super(config);
274
+ const apiKey = config.env.STRIPE_SECRET_KEY;
275
+ if (!apiKey) {
276
+ throw new Error("STRIPE_SECRET_KEY not configured");
277
+ }
278
+ this.client = new Stripe(apiKey, {
279
+ apiVersion: "2025-02-24.acacia"
280
+ });
281
+ this.logger.info("Stripe integration initialized");
282
+ }
283
+ async execute(action, params) {
284
+ const validation = this.validateParams(action, params);
285
+ if (!validation.valid) {
286
+ return {
287
+ success: false,
288
+ error: {
289
+ name: "IntegrationError",
290
+ message: "Validation failed",
291
+ code: "VALIDATION_ERROR",
292
+ details: validation.errors
293
+ },
294
+ metadata: this.createMetadata(action, 0)
295
+ };
296
+ }
297
+ const startTime = Date.now();
298
+ let retries = 0;
299
+ try {
300
+ let data;
301
+ switch (action) {
302
+ case "createPaymentIntent":
303
+ data = await this.executeWithRetry(
304
+ () => this.createPaymentIntent(params)
305
+ );
306
+ break;
307
+ case "confirmPayment":
308
+ data = await this.executeWithRetry(() => this.confirmPayment(params));
309
+ break;
310
+ case "refund":
311
+ data = await this.executeWithRetry(() => this.refund(params));
312
+ break;
313
+ default:
314
+ throw new Error(`Unknown action: ${action}`);
315
+ }
316
+ return {
317
+ success: true,
318
+ data,
319
+ metadata: this.createMetadata(action, Date.now() - startTime, retries)
320
+ };
321
+ } catch (error) {
322
+ return this.handleError(action, error);
323
+ }
324
+ }
325
+ async createPaymentIntent(params) {
326
+ const { amount, currency, metadata } = params;
327
+ this.logger.debug("Creating payment intent", { amount, currency });
328
+ return await this.client.paymentIntents.create({
329
+ amount,
330
+ currency,
331
+ metadata
332
+ });
333
+ }
334
+ async confirmPayment(params) {
335
+ const { paymentIntentId } = params;
336
+ this.logger.debug("Confirming payment", { paymentIntentId });
337
+ return await this.client.paymentIntents.confirm(paymentIntentId);
338
+ }
339
+ async refund(params) {
340
+ const { paymentIntentId, amount } = params;
341
+ this.logger.debug("Creating refund", { paymentIntentId, amount });
342
+ return await this.client.refunds.create({
343
+ payment_intent: paymentIntentId,
344
+ amount
345
+ });
346
+ }
347
+ };
348
+ registerIntegration("stripe", StripeIntegration);
349
+ var YouTubeIntegration = class extends BaseIntegration {
350
+ constructor(config) {
351
+ super(config);
352
+ const apiKey = config.env.YOUTUBE_API_KEY;
353
+ if (!apiKey) {
354
+ throw new Error("YOUTUBE_API_KEY not configured");
355
+ }
356
+ this.client = google.youtube({
357
+ version: "v3",
358
+ auth: apiKey
359
+ });
360
+ this.logger.info("YouTube integration initialized");
361
+ }
362
+ async execute(action, params) {
363
+ const validation = this.validateParams(action, params);
364
+ if (!validation.valid) {
365
+ return {
366
+ success: false,
367
+ error: {
368
+ name: "IntegrationError",
369
+ message: "Validation failed",
370
+ code: "VALIDATION_ERROR",
371
+ details: validation.errors
372
+ },
373
+ metadata: this.createMetadata(action, 0)
374
+ };
375
+ }
376
+ const startTime = Date.now();
377
+ let retries = 0;
378
+ try {
379
+ let data;
380
+ switch (action) {
381
+ case "search":
382
+ data = await this.executeWithRetry(() => this.search(params));
383
+ break;
384
+ case "getVideo":
385
+ data = await this.executeWithRetry(() => this.getVideo(params));
386
+ break;
387
+ case "getChannel":
388
+ data = await this.executeWithRetry(() => this.getChannel(params));
389
+ break;
390
+ default:
391
+ throw new Error(`Unknown action: ${action}`);
392
+ }
393
+ return {
394
+ success: true,
395
+ data,
396
+ metadata: this.createMetadata(action, Date.now() - startTime, retries)
397
+ };
398
+ } catch (error) {
399
+ return this.handleError(action, error);
400
+ }
401
+ }
402
+ async search(params) {
403
+ const { query, maxResults, type } = params;
404
+ this.logger.debug("Searching YouTube", { query, maxResults, type });
405
+ const response = await this.client.search.list({
406
+ part: ["snippet"],
407
+ q: query,
408
+ maxResults: maxResults || 10,
409
+ type: type ? [type] : void 0
410
+ });
411
+ return response.data.items?.map((item) => ({
412
+ videoId: item.id?.videoId,
413
+ title: item.snippet?.title,
414
+ thumbnail: item.snippet?.thumbnails?.default?.url,
415
+ description: item.snippet?.description
416
+ }));
417
+ }
418
+ async getVideo(params) {
419
+ const { videoId } = params;
420
+ this.logger.debug("Getting video details", { videoId });
421
+ const response = await this.client.videos.list({
422
+ part: ["snippet", "statistics"],
423
+ id: [videoId]
424
+ });
425
+ const video = response.data.items?.[0];
426
+ if (!video) {
427
+ throw new Error(`Video not found: ${videoId}`);
428
+ }
429
+ return {
430
+ title: video.snippet?.title,
431
+ description: video.snippet?.description,
432
+ viewCount: video.statistics?.viewCount,
433
+ likeCount: video.statistics?.likeCount
434
+ };
435
+ }
436
+ async getChannel(params) {
437
+ const { channelId } = params;
438
+ this.logger.debug("Getting channel details", { channelId });
439
+ const response = await this.client.channels.list({
440
+ part: ["snippet", "statistics"],
441
+ id: [channelId]
442
+ });
443
+ const channel = response.data.items?.[0];
444
+ if (!channel) {
445
+ throw new Error(`Channel not found: ${channelId}`);
446
+ }
447
+ return {
448
+ name: channel.snippet?.title,
449
+ description: channel.snippet?.description,
450
+ subscriberCount: channel.statistics?.subscriberCount
451
+ };
452
+ }
453
+ };
454
+ registerIntegration("youtube", YouTubeIntegration);
455
+ var TwilioIntegration = class extends BaseIntegration {
456
+ constructor(config) {
457
+ super(config);
458
+ const accountSid = config.env.TWILIO_ACCOUNT_SID;
459
+ const authToken = config.env.TWILIO_AUTH_TOKEN;
460
+ this.phoneNumber = config.env.TWILIO_PHONE_NUMBER || "";
461
+ if (!accountSid || !authToken) {
462
+ throw new Error("TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN not configured");
463
+ }
464
+ this.client = twilio(accountSid, authToken);
465
+ this.logger.info("Twilio integration initialized");
466
+ }
467
+ async execute(action, params) {
468
+ const validation = this.validateParams(action, params);
469
+ if (!validation.valid) {
470
+ return {
471
+ success: false,
472
+ error: {
473
+ name: "IntegrationError",
474
+ message: "Validation failed",
475
+ code: "VALIDATION_ERROR",
476
+ details: validation.errors
477
+ },
478
+ metadata: this.createMetadata(action, 0)
479
+ };
480
+ }
481
+ const startTime = Date.now();
482
+ let retries = 0;
483
+ try {
484
+ let data;
485
+ switch (action) {
486
+ case "sendSMS":
487
+ data = await this.executeWithRetry(() => this.sendSMS(params));
488
+ break;
489
+ case "sendWhatsApp":
490
+ data = await this.executeWithRetry(() => this.sendWhatsApp(params));
491
+ break;
492
+ default:
493
+ throw new Error(`Unknown action: ${action}`);
494
+ }
495
+ return {
496
+ success: true,
497
+ data,
498
+ metadata: this.createMetadata(action, Date.now() - startTime, retries)
499
+ };
500
+ } catch (error) {
501
+ return this.handleError(action, error);
502
+ }
503
+ }
504
+ async sendSMS(params) {
505
+ const { to, body } = params;
506
+ this.logger.debug("Sending SMS", { to });
507
+ const message = await this.client.messages.create({
508
+ from: this.phoneNumber,
509
+ to,
510
+ body
511
+ });
512
+ return {
513
+ sid: message.sid,
514
+ status: message.status
515
+ };
516
+ }
517
+ async sendWhatsApp(params) {
518
+ const { to, body } = params;
519
+ this.logger.debug("Sending WhatsApp message", { to });
520
+ const message = await this.client.messages.create({
521
+ from: `whatsapp:${this.phoneNumber}`,
522
+ to: `whatsapp:${to}`,
523
+ body
524
+ });
525
+ return {
526
+ sid: message.sid,
527
+ status: message.status
528
+ };
529
+ }
530
+ };
531
+ registerIntegration("twilio", TwilioIntegration);
532
+ var EmailIntegration = class extends BaseIntegration {
533
+ constructor(config) {
534
+ super(config);
535
+ this.provider = config.env.PROVIDER || "sendgrid";
536
+ this.fromEmail = config.env.FROM_EMAIL || "noreply@example.com";
537
+ if (this.provider === "sendgrid") {
538
+ const apiKey = config.env.SENDGRID_API_KEY;
539
+ if (!apiKey) {
540
+ throw new Error("SENDGRID_API_KEY not configured");
541
+ }
542
+ sgMail.setApiKey(apiKey);
543
+ } else if (this.provider === "resend") {
544
+ const apiKey = config.env.RESEND_API_KEY;
545
+ if (!apiKey) {
546
+ throw new Error("RESEND_API_KEY not configured");
547
+ }
548
+ this.resendClient = new Resend(apiKey);
549
+ }
550
+ this.logger.info(`Email integration initialized (${this.provider})`);
551
+ }
552
+ async execute(action, params) {
553
+ const validation = this.validateParams(action, params);
554
+ if (!validation.valid) {
555
+ return {
556
+ success: false,
557
+ error: {
558
+ name: "IntegrationError",
559
+ message: "Validation failed",
560
+ code: "VALIDATION_ERROR",
561
+ details: validation.errors
562
+ },
563
+ metadata: this.createMetadata(action, 0)
564
+ };
565
+ }
566
+ const startTime = Date.now();
567
+ let retries = 0;
568
+ try {
569
+ let data;
570
+ switch (action) {
571
+ case "send":
572
+ data = await this.executeWithRetry(() => this.send(params));
573
+ break;
574
+ default:
575
+ throw new Error(`Unknown action: ${action}`);
576
+ }
577
+ return {
578
+ success: true,
579
+ data,
580
+ metadata: this.createMetadata(action, Date.now() - startTime, retries)
581
+ };
582
+ } catch (error) {
583
+ return this.handleError(action, error);
584
+ }
585
+ }
586
+ async send(params) {
587
+ const { to, subject, body, from } = params;
588
+ this.logger.debug("Sending email", { to, subject, provider: this.provider });
589
+ if (this.provider === "sendgrid") {
590
+ return await this.sendViaSendGrid(
591
+ to,
592
+ subject,
593
+ body,
594
+ from || this.fromEmail
595
+ );
596
+ } else if (this.provider === "resend") {
597
+ return await this.sendViaResend(
598
+ to,
599
+ subject,
600
+ body,
601
+ from || this.fromEmail
602
+ );
603
+ }
604
+ throw new Error(`Unknown email provider: ${this.provider}`);
605
+ }
606
+ async sendViaSendGrid(to, subject, body, from) {
607
+ const msg = {
608
+ to,
609
+ from,
610
+ subject,
611
+ html: body
612
+ };
613
+ const response = await sgMail.send(msg);
614
+ return {
615
+ id: response[0].headers["x-message-id"],
616
+ status: "sent"
617
+ };
618
+ }
619
+ async sendViaResend(to, subject, body, from) {
620
+ if (!this.resendClient) {
621
+ throw new Error("Resend client not initialized");
622
+ }
623
+ const response = await this.resendClient.emails.send({
624
+ from,
625
+ to,
626
+ subject,
627
+ html: body
628
+ });
629
+ return {
630
+ id: response.data?.id,
631
+ status: "sent"
632
+ };
633
+ }
634
+ };
635
+ registerIntegration("email", EmailIntegration);
636
+
637
+ // src/integrations/llm/index.ts
638
+ var LLMIntegration = class extends BaseIntegration {
639
+ constructor(config) {
640
+ super(config);
641
+ this.provider = config.env.PROVIDER || "anthropic";
642
+ try {
643
+ this.client = this.createLLMClient(config.env);
644
+ this.logger.info(`LLM integration initialized (${this.provider})`);
645
+ } catch (error) {
646
+ throw new Error(`Failed to initialize LLM client: ${error}`);
647
+ }
648
+ }
649
+ createLLMClient(env) {
650
+ return {
651
+ provider: this.provider,
652
+ apiKey: env.ANTHROPIC_API_KEY || env.OPENAI_API_KEY
653
+ };
654
+ }
655
+ async execute(action, params) {
656
+ const validation = this.validateParams(action, params);
657
+ if (!validation.valid) {
658
+ return {
659
+ success: false,
660
+ error: {
661
+ name: "IntegrationError",
662
+ message: "Validation failed",
663
+ code: "VALIDATION_ERROR",
664
+ details: validation.errors
665
+ },
666
+ metadata: this.createMetadata(action, 0)
667
+ };
668
+ }
669
+ const startTime = Date.now();
670
+ let retries = 0;
671
+ try {
672
+ let data;
673
+ switch (action) {
674
+ case "generate":
675
+ data = await this.executeWithRetry(() => this.generate(params));
676
+ break;
677
+ case "classify":
678
+ data = await this.executeWithRetry(() => this.classify(params));
679
+ break;
680
+ case "extract":
681
+ data = await this.executeWithRetry(() => this.extract(params));
682
+ break;
683
+ case "summarize":
684
+ data = await this.executeWithRetry(() => this.summarize(params));
685
+ break;
686
+ default:
687
+ throw new Error(`Unknown action: ${action}`);
688
+ }
689
+ return {
690
+ success: true,
691
+ data,
692
+ metadata: this.createMetadata(action, Date.now() - startTime, retries)
693
+ };
694
+ } catch (error) {
695
+ return this.handleError(action, error);
696
+ }
697
+ }
698
+ async generate(params) {
699
+ const { systemPrompt, userPrompt, model, temperature, maxTokens } = params;
700
+ this.logger.debug("Generating content", { model, temperature });
701
+ return {
702
+ content: "Generated content placeholder",
703
+ usage: { tokens: 0 }
704
+ };
705
+ }
706
+ async classify(params) {
707
+ const { text, categories, model } = params;
708
+ this.logger.debug("Classifying text", { categories });
709
+ return {
710
+ category: categories[0],
711
+ confidence: 0.95,
712
+ reasoning: "Classification reasoning placeholder"
713
+ };
714
+ }
715
+ async extract(params) {
716
+ const { text, schema, model } = params;
717
+ this.logger.debug("Extracting structured data", { schema });
718
+ return {
719
+ data: {},
720
+ confidence: 0.9
721
+ };
722
+ }
723
+ async summarize(params) {
724
+ const { text, maxLength, style, model } = params;
725
+ this.logger.debug("Summarizing text", { maxLength, style });
726
+ return {
727
+ summary: "Summary placeholder",
728
+ keyPoints: []
729
+ };
730
+ }
731
+ };
732
+ registerIntegration("llm", LLMIntegration);
733
+
734
+ // src/integrations/deepagent/index.ts
735
+ var DeepAgentIntegration = class extends BaseIntegration {
736
+ constructor(config) {
737
+ super(config);
738
+ this.apiUrl = config.env.DEEPAGENT_API_URL || "http://localhost:3000";
739
+ this.apiKey = config.env.DEEPAGENT_API_KEY || "";
740
+ this.logger.info("DeepAgent integration initialized", { apiUrl: this.apiUrl });
741
+ }
742
+ async execute(action, params) {
743
+ const validation = this.validateParams(action, params);
744
+ if (!validation.valid) {
745
+ return {
746
+ success: false,
747
+ error: {
748
+ name: "IntegrationError",
749
+ message: "Validation failed",
750
+ code: "VALIDATION_ERROR",
751
+ details: validation.errors
752
+ },
753
+ metadata: this.createMetadata(action, 0)
754
+ };
755
+ }
756
+ const startTime = Date.now();
757
+ let retries = 0;
758
+ try {
759
+ let data;
760
+ switch (action) {
761
+ case "sendMessage":
762
+ data = await this.executeWithRetry(() => this.sendMessage(params));
763
+ break;
764
+ case "cancelGeneration":
765
+ data = await this.executeWithRetry(
766
+ () => this.cancelGeneration(params)
767
+ );
768
+ break;
769
+ case "validateSchema":
770
+ data = await this.executeWithRetry(() => this.validateSchema(params));
771
+ break;
772
+ case "compileSchema":
773
+ data = await this.executeWithRetry(() => this.compileSchema(params));
774
+ break;
775
+ case "getThreadHistory":
776
+ data = await this.executeWithRetry(
777
+ () => this.getThreadHistory(params)
778
+ );
779
+ break;
780
+ default:
781
+ throw new Error(`Unknown action: ${action}`);
782
+ }
783
+ return {
784
+ success: true,
785
+ data,
786
+ metadata: this.createMetadata(action, Date.now() - startTime, retries)
787
+ };
788
+ } catch (error) {
789
+ return this.handleError(action, error);
790
+ }
791
+ }
792
+ async sendMessage(params) {
793
+ const { message, threadId, skill, context } = params;
794
+ this.logger.debug("Sending message to DeepAgent", { threadId, skill });
795
+ const response = await this.request("/api/agent/message", {
796
+ message,
797
+ threadId,
798
+ skill,
799
+ context
800
+ });
801
+ return response;
802
+ }
803
+ async cancelGeneration(params) {
804
+ const { threadId } = params;
805
+ this.logger.debug("Cancelling generation", { threadId });
806
+ const response = await this.request("/api/agent/cancel", {
807
+ threadId
808
+ });
809
+ return response;
810
+ }
811
+ async validateSchema(params) {
812
+ const { schema } = params;
813
+ this.logger.debug("Validating schema");
814
+ const response = await this.request("/api/schema/validate", {
815
+ schema
816
+ });
817
+ return response;
818
+ }
819
+ async compileSchema(params) {
820
+ const { schema, shell } = params;
821
+ this.logger.debug("Compiling schema", { shell });
822
+ const response = await this.request("/api/schema/compile", {
823
+ schema,
824
+ shell
825
+ });
826
+ return response;
827
+ }
828
+ async getThreadHistory(params) {
829
+ const { threadId } = params;
830
+ this.logger.debug("Getting thread history", { threadId });
831
+ const response = await this.request("/api/agent/history", {
832
+ threadId
833
+ });
834
+ return response;
835
+ }
836
+ async request(endpoint, body) {
837
+ const url = `${this.apiUrl}${endpoint}`;
838
+ const response = await fetch(url, {
839
+ method: "POST",
840
+ headers: {
841
+ "Content-Type": "application/json",
842
+ ...this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {}
843
+ },
844
+ body: JSON.stringify(body)
845
+ });
846
+ if (!response.ok) {
847
+ throw new Error(
848
+ `DeepAgent request failed: ${response.status} ${response.statusText}`
849
+ );
850
+ }
851
+ return await response.json();
852
+ }
853
+ };
854
+ registerIntegration("deepagent", DeepAgentIntegration);
855
+
856
+ // src/types.ts
857
+ var IntegrationError = class extends Error {
858
+ constructor(message, code = "UNKNOWN_ERROR", details) {
859
+ super(message);
860
+ this.name = "IntegrationError";
861
+ this.code = code;
862
+ this.details = details;
863
+ }
864
+ toJSON() {
865
+ return {
866
+ name: this.name,
867
+ message: this.message,
868
+ code: this.code,
869
+ integration: this.integration,
870
+ action: this.action,
871
+ details: this.details
872
+ };
873
+ }
874
+ };
875
+
876
+ // src/integrations/github/github-git.ts
877
+ async function execGit(args, cwd, env) {
878
+ return new Promise((resolve, reject) => {
879
+ const proc = spawn("git", args, {
880
+ cwd,
881
+ env: { ...process.env, ...env },
882
+ stdio: "pipe"
883
+ });
884
+ let stdout = "";
885
+ let stderr = "";
886
+ proc.stdout?.on("data", (data) => {
887
+ stdout += data.toString();
888
+ });
889
+ proc.stderr?.on("data", (data) => {
890
+ stderr += data.toString();
891
+ });
892
+ proc.on("close", (code) => {
893
+ if (code === 0) {
894
+ resolve({ stdout, stderr });
895
+ } else {
896
+ reject(
897
+ new IntegrationError(
898
+ `Git command failed: ${args.join(" ")}
899
+ ${stderr}`,
900
+ "SERVICE_ERROR",
901
+ { code, stderr }
902
+ )
903
+ );
904
+ }
905
+ });
906
+ proc.on("error", (error) => {
907
+ reject(
908
+ new IntegrationError(
909
+ `Failed to execute git: ${error.message}`,
910
+ "SERVICE_ERROR",
911
+ { error }
912
+ )
913
+ );
914
+ });
915
+ });
916
+ }
917
+ async function cloneRepo(params, token) {
918
+ const { repoUrl, targetDir, branch, depth = 1 } = params;
919
+ const authUrl = injectTokenIntoUrl(repoUrl, token);
920
+ const args = ["clone"];
921
+ if (depth > 0) {
922
+ args.push("--depth", depth.toString());
923
+ }
924
+ if (branch) {
925
+ args.push("--branch", branch);
926
+ }
927
+ args.push(authUrl, targetDir);
928
+ try {
929
+ await execGit(args, process.cwd());
930
+ await scrubTokenFromRemote(targetDir, repoUrl);
931
+ } catch (error) {
932
+ throw new IntegrationError(
933
+ `Failed to clone repository: ${error instanceof Error ? error.message : String(error)}`,
934
+ "SERVICE_ERROR",
935
+ { repoUrl, error }
936
+ );
937
+ }
938
+ }
939
+ async function createBranch(params, workDir) {
940
+ const { branchName, baseBranch } = params;
941
+ const cwd = params.workDir || workDir;
942
+ try {
943
+ if (baseBranch) {
944
+ await execGit(["checkout", baseBranch], cwd);
945
+ }
946
+ await execGit(["checkout", "-b", branchName], cwd);
947
+ } catch (error) {
948
+ throw new IntegrationError(
949
+ `Failed to create branch: ${error instanceof Error ? error.message : String(error)}`,
950
+ "SERVICE_ERROR",
951
+ { branchName, baseBranch, error }
952
+ );
953
+ }
954
+ }
955
+ async function commit(params, workDir) {
956
+ const { message, files } = params;
957
+ const cwd = params.workDir || workDir;
958
+ try {
959
+ if (files && files.length > 0) {
960
+ await execGit(["add", ...files], cwd);
961
+ } else {
962
+ await execGit(["add", "."], cwd);
963
+ }
964
+ await execGit(["commit", "-m", message], cwd);
965
+ } catch (error) {
966
+ throw new IntegrationError(
967
+ `Failed to commit: ${error instanceof Error ? error.message : String(error)}`,
968
+ "SERVICE_ERROR",
969
+ { message, error }
970
+ );
971
+ }
972
+ }
973
+ async function push(params, workDir, token) {
974
+ const { branchName, force = false } = params;
975
+ const cwd = params.workDir || workDir;
976
+ const protectedBranches = ["main", "master", "production", "prod"];
977
+ if (force && protectedBranches.includes(branchName.toLowerCase())) {
978
+ throw new IntegrationError(
979
+ `Force push to protected branch '${branchName}' is not allowed`,
980
+ "VALIDATION_ERROR"
981
+ );
982
+ }
983
+ try {
984
+ const credHelper = await createTempCredentialHelper(token);
985
+ const args = ["push"];
986
+ if (force) {
987
+ args.push("--force");
988
+ }
989
+ args.push("-u", "origin", branchName);
990
+ await execGit(args, cwd, {
991
+ GIT_ASKPASS: credHelper,
992
+ GIT_TERMINAL_PROMPT: "0"
993
+ });
994
+ await promises.unlink(credHelper);
995
+ } catch (error) {
996
+ throw new IntegrationError(
997
+ `Failed to push: ${error instanceof Error ? error.message : String(error)}`,
998
+ "SERVICE_ERROR",
999
+ { branchName, error }
1000
+ );
1001
+ }
1002
+ }
1003
+ function injectTokenIntoUrl(repoUrl, token) {
1004
+ const url = new URL(repoUrl);
1005
+ url.username = "x-access-token";
1006
+ url.password = token;
1007
+ return url.toString();
1008
+ }
1009
+ async function scrubTokenFromRemote(workDir, originalUrl) {
1010
+ try {
1011
+ const url = new URL(originalUrl);
1012
+ url.username = "";
1013
+ url.password = "";
1014
+ const cleanUrl = url.toString();
1015
+ await execGit(["remote", "set-url", "origin", cleanUrl], workDir);
1016
+ } catch (error) {
1017
+ console.error("Warning: Failed to scrub token from remote URL:", error);
1018
+ }
1019
+ }
1020
+ async function createTempCredentialHelper(token) {
1021
+ const tmpDir = process.env.TMPDIR || "/tmp";
1022
+ const helperPath = join(tmpDir, `git-cred-${Date.now()}.sh`);
1023
+ const script = `#!/bin/sh
1024
+ echo "${token}"`;
1025
+ await promises.writeFile(helperPath, script, { mode: 448 });
1026
+ return helperPath;
1027
+ }
1028
+
1029
+ // src/integrations/github/github-api.ts
1030
+ async function githubFetch(endpoint, config, options = {}) {
1031
+ const url = `https://api.github.com${endpoint}`;
1032
+ const headers = {
1033
+ "Authorization": `Bearer ${config.token}`,
1034
+ "Accept": "application/vnd.github+json",
1035
+ "X-GitHub-Api-Version": "2022-11-28",
1036
+ ...options.headers
1037
+ };
1038
+ try {
1039
+ const response = await fetch(url, {
1040
+ ...options,
1041
+ headers
1042
+ });
1043
+ const rateLimit = {
1044
+ remaining: parseInt(response.headers.get("x-ratelimit-remaining") || "0", 10),
1045
+ limit: parseInt(response.headers.get("x-ratelimit-limit") || "5000", 10),
1046
+ reset: parseInt(response.headers.get("x-ratelimit-reset") || "0", 10)
1047
+ };
1048
+ if (!response.ok) {
1049
+ const error = await response.json().catch(() => ({ message: response.statusText }));
1050
+ if (response.status === 429) {
1051
+ throw new IntegrationError(
1052
+ "GitHub API rate limit exceeded",
1053
+ "RATE_LIMIT_ERROR",
1054
+ { rateLimit, error }
1055
+ );
1056
+ }
1057
+ if (response.status === 401 || response.status === 403) {
1058
+ throw new IntegrationError(
1059
+ `GitHub API authentication failed: ${error.message || response.statusText}`,
1060
+ "AUTH_ERROR",
1061
+ { status: response.status, error }
1062
+ );
1063
+ }
1064
+ throw new IntegrationError(
1065
+ `GitHub API request failed: ${error.message || response.statusText}`,
1066
+ "SERVICE_ERROR",
1067
+ { status: response.status, error }
1068
+ );
1069
+ }
1070
+ const data = await response.json();
1071
+ return { data, rateLimit };
1072
+ } catch (error) {
1073
+ if (error instanceof IntegrationError) {
1074
+ throw error;
1075
+ }
1076
+ throw new IntegrationError(
1077
+ `GitHub API request failed: ${error instanceof Error ? error.message : String(error)}`,
1078
+ "NETWORK_ERROR",
1079
+ { error }
1080
+ );
1081
+ }
1082
+ }
1083
+ async function createPR(params, config) {
1084
+ const { title, body, baseBranch, headBranch, draft = false } = params;
1085
+ const endpoint = `/repos/${config.owner}/${config.repo}/pulls`;
1086
+ const { data } = await githubFetch(endpoint, config, {
1087
+ method: "POST",
1088
+ body: JSON.stringify({
1089
+ title,
1090
+ body,
1091
+ base: baseBranch,
1092
+ head: headBranch,
1093
+ draft
1094
+ })
1095
+ });
1096
+ return data;
1097
+ }
1098
+ async function getPRComments(params, config) {
1099
+ const { prNumber } = params;
1100
+ const endpoint = `/repos/${config.owner}/${config.repo}/pulls/${prNumber}/comments`;
1101
+ const { data } = await githubFetch(endpoint, config);
1102
+ return data;
1103
+ }
1104
+ async function listIssues(params, config) {
1105
+ const { state = "open", labels = [], limit = 30 } = params;
1106
+ const queryParams = new URLSearchParams({
1107
+ state,
1108
+ per_page: Math.min(limit, 100).toString()
1109
+ });
1110
+ if (labels.length > 0) {
1111
+ queryParams.append("labels", labels.join(","));
1112
+ }
1113
+ const endpoint = `/repos/${config.owner}/${config.repo}/issues?${queryParams}`;
1114
+ const { data } = await githubFetch(endpoint, config);
1115
+ return data;
1116
+ }
1117
+ async function getIssue(params, config) {
1118
+ const { issueNumber } = params;
1119
+ const issueEndpoint = `/repos/${config.owner}/${config.repo}/issues/${issueNumber}`;
1120
+ const { data: issue } = await githubFetch(issueEndpoint, config);
1121
+ const commentsEndpoint = `/repos/${config.owner}/${config.repo}/issues/${issueNumber}/comments`;
1122
+ const { data: comments } = await githubFetch(commentsEndpoint, config);
1123
+ return { issue, comments };
1124
+ }
1125
+ function parseRepoUrl(repoUrl) {
1126
+ try {
1127
+ const url = new URL(repoUrl);
1128
+ const pathParts = url.pathname.split("/").filter(Boolean);
1129
+ if (pathParts.length < 2) {
1130
+ throw new Error("Invalid repository URL format");
1131
+ }
1132
+ const owner = pathParts[0];
1133
+ const repo = pathParts[1].replace(/\.git$/, "");
1134
+ return { owner, repo };
1135
+ } catch (error) {
1136
+ throw new IntegrationError(
1137
+ `Failed to parse repository URL: ${repoUrl}`,
1138
+ "VALIDATION_ERROR",
1139
+ { error }
1140
+ );
1141
+ }
1142
+ }
1143
+
1144
+ // src/integrations/github/index.ts
1145
+ var GitHubIntegration = class extends BaseIntegration {
1146
+ constructor(config) {
1147
+ super(config);
1148
+ this.token = config.env.GITHUB_TOKEN;
1149
+ if (!this.token) {
1150
+ throw new Error("GITHUB_TOKEN not configured");
1151
+ }
1152
+ this.owner = config.env.GITHUB_OWNER || "";
1153
+ this.repo = config.env.GITHUB_REPO || "";
1154
+ this.workDir = config.env.GITHUB_WORK_DIR || process.cwd();
1155
+ this.logger.info("GitHub integration initialized", {
1156
+ owner: this.owner,
1157
+ repo: this.repo
1158
+ });
1159
+ }
1160
+ /**
1161
+ * Execute a GitHub action
1162
+ */
1163
+ async execute(action, params) {
1164
+ const validation = this.validateParams(action, params);
1165
+ if (!validation.valid) {
1166
+ return {
1167
+ success: false,
1168
+ error: {
1169
+ name: "IntegrationError",
1170
+ message: "Validation failed",
1171
+ code: "VALIDATION_ERROR",
1172
+ details: validation.errors
1173
+ },
1174
+ metadata: this.createMetadata(action, 0)
1175
+ };
1176
+ }
1177
+ const startTime = Date.now();
1178
+ let retries = 0;
1179
+ try {
1180
+ let data;
1181
+ switch (action) {
1182
+ case "cloneRepo":
1183
+ data = await this.executeWithRetry(
1184
+ () => this.cloneRepo(params)
1185
+ );
1186
+ break;
1187
+ case "createBranch":
1188
+ data = await this.executeWithRetry(
1189
+ () => this.createBranch(params)
1190
+ );
1191
+ break;
1192
+ case "commit":
1193
+ data = await this.executeWithRetry(
1194
+ () => this.commit(params)
1195
+ );
1196
+ break;
1197
+ case "push":
1198
+ data = await this.executeWithRetry(
1199
+ () => this.push(params)
1200
+ );
1201
+ break;
1202
+ case "createPR":
1203
+ data = await this.executeWithRetry(
1204
+ () => this.createPR(params)
1205
+ );
1206
+ break;
1207
+ case "getPRComments":
1208
+ data = await this.executeWithRetry(
1209
+ () => this.getPRComments(params)
1210
+ );
1211
+ break;
1212
+ case "listIssues":
1213
+ data = await this.executeWithRetry(
1214
+ () => this.listIssues(params)
1215
+ );
1216
+ break;
1217
+ case "getIssue":
1218
+ data = await this.executeWithRetry(
1219
+ () => this.getIssue(params)
1220
+ );
1221
+ break;
1222
+ default:
1223
+ throw new Error(`Unknown GitHub action: ${action}`);
1224
+ }
1225
+ return {
1226
+ success: true,
1227
+ data,
1228
+ metadata: this.createMetadata(action, Date.now() - startTime, retries)
1229
+ };
1230
+ } catch (error) {
1231
+ return this.handleError(action, error);
1232
+ }
1233
+ }
1234
+ /**
1235
+ * Clone a repository
1236
+ */
1237
+ async cloneRepo(params) {
1238
+ this.logger.debug("Cloning repository", { repoUrl: params.repoUrl });
1239
+ if (!this.owner || !this.repo) {
1240
+ const parsed = parseRepoUrl(params.repoUrl);
1241
+ this.owner = parsed.owner;
1242
+ this.repo = parsed.repo;
1243
+ }
1244
+ await cloneRepo(params, this.token);
1245
+ return {
1246
+ message: `Successfully cloned ${params.repoUrl} to ${params.targetDir}`
1247
+ };
1248
+ }
1249
+ /**
1250
+ * Create a branch
1251
+ */
1252
+ async createBranch(params) {
1253
+ this.logger.debug("Creating branch", { branchName: params.branchName });
1254
+ await createBranch(params, this.workDir);
1255
+ return {
1256
+ message: `Successfully created branch: ${params.branchName}`
1257
+ };
1258
+ }
1259
+ /**
1260
+ * Commit changes
1261
+ */
1262
+ async commit(params) {
1263
+ this.logger.debug("Committing changes", { message: params.message });
1264
+ await commit(params, this.workDir);
1265
+ return {
1266
+ message: `Successfully committed changes: ${params.message}`
1267
+ };
1268
+ }
1269
+ /**
1270
+ * Push branch
1271
+ */
1272
+ async push(params) {
1273
+ this.logger.debug("Pushing branch", { branchName: params.branchName });
1274
+ await push(params, this.workDir, this.token);
1275
+ return {
1276
+ message: `Successfully pushed branch: ${params.branchName}`
1277
+ };
1278
+ }
1279
+ /**
1280
+ * Create a pull request
1281
+ */
1282
+ async createPR(params) {
1283
+ this.logger.debug("Creating pull request", { title: params.title });
1284
+ const apiConfig = this.getAPIConfig();
1285
+ const pr = await createPR(params, apiConfig);
1286
+ this.logger.info("Pull request created", { number: pr.number, url: pr.url });
1287
+ return pr;
1288
+ }
1289
+ /**
1290
+ * Get PR comments
1291
+ */
1292
+ async getPRComments(params) {
1293
+ this.logger.debug("Getting PR comments", { prNumber: params.prNumber });
1294
+ const apiConfig = this.getAPIConfig();
1295
+ const comments = await getPRComments(params, apiConfig);
1296
+ return { comments };
1297
+ }
1298
+ /**
1299
+ * List issues
1300
+ */
1301
+ async listIssues(params) {
1302
+ this.logger.debug("Listing issues", params);
1303
+ const apiConfig = this.getAPIConfig();
1304
+ const issues = await listIssues(params, apiConfig);
1305
+ return { issues };
1306
+ }
1307
+ /**
1308
+ * Get issue details
1309
+ */
1310
+ async getIssue(params) {
1311
+ this.logger.debug("Getting issue", { issueNumber: params.issueNumber });
1312
+ const apiConfig = this.getAPIConfig();
1313
+ const result = await getIssue(params, apiConfig);
1314
+ return result;
1315
+ }
1316
+ /**
1317
+ * Get API config for GitHub API calls
1318
+ */
1319
+ getAPIConfig() {
1320
+ if (!this.owner || !this.repo) {
1321
+ throw new Error(
1322
+ "GitHub owner and repo must be configured. Either set GITHUB_OWNER/GITHUB_REPO or clone a repository first."
1323
+ );
1324
+ }
1325
+ return {
1326
+ token: this.token,
1327
+ owner: this.owner,
1328
+ repo: this.repo
1329
+ };
1330
+ }
1331
+ };
1332
+ registerIntegration("github", GitHubIntegration);
1333
+
1334
+ export { BaseIntegration, ConsoleLogger, DeepAgentIntegration, EmailIntegration, GitHubIntegration, IntegrationFactory, LLMIntegration, StripeIntegration, TwilioIntegration, YouTubeIntegration, getIntegration, getRegisteredIntegrations, isKnownIntegration, registerIntegration, validateParams, withRetry };
1335
+ //# sourceMappingURL=index.js.map
1336
+ //# sourceMappingURL=index.js.map