@sweny-ai/providers 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (283) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +260 -0
  3. package/dist/access/allow-all.d.ts +3 -0
  4. package/dist/access/allow-all.d.ts.map +1 -0
  5. package/dist/access/allow-all.js +19 -0
  6. package/dist/access/allow-all.js.map +1 -0
  7. package/dist/access/index.d.ts +5 -0
  8. package/dist/access/index.d.ts.map +1 -0
  9. package/dist/access/index.js +4 -0
  10. package/dist/access/index.js.map +1 -0
  11. package/dist/access/role-based.d.ts +8 -0
  12. package/dist/access/role-based.d.ts.map +1 -0
  13. package/dist/access/role-based.js +42 -0
  14. package/dist/access/role-based.js.map +1 -0
  15. package/dist/access/types.d.ts +41 -0
  16. package/dist/access/types.d.ts.map +1 -0
  17. package/dist/access/types.js +20 -0
  18. package/dist/access/types.js.map +1 -0
  19. package/dist/agent-tool/factory.d.ts +4 -0
  20. package/dist/agent-tool/factory.d.ts.map +1 -0
  21. package/dist/agent-tool/factory.js +4 -0
  22. package/dist/agent-tool/factory.js.map +1 -0
  23. package/dist/agent-tool/index.d.ts +3 -0
  24. package/dist/agent-tool/index.d.ts.map +1 -0
  25. package/dist/agent-tool/index.js +2 -0
  26. package/dist/agent-tool/index.js.map +1 -0
  27. package/dist/agent-tool/types.d.ts +15 -0
  28. package/dist/agent-tool/types.d.ts.map +1 -0
  29. package/dist/agent-tool/types.js +2 -0
  30. package/dist/agent-tool/types.js.map +1 -0
  31. package/dist/auth/api-key.d.ts +6 -0
  32. package/dist/auth/api-key.d.ts.map +1 -0
  33. package/dist/auth/api-key.js +36 -0
  34. package/dist/auth/api-key.js.map +1 -0
  35. package/dist/auth/index.d.ts +4 -0
  36. package/dist/auth/index.d.ts.map +1 -0
  37. package/dist/auth/index.js +3 -0
  38. package/dist/auth/index.js.map +1 -0
  39. package/dist/auth/no-auth.d.ts +3 -0
  40. package/dist/auth/no-auth.d.ts.map +1 -0
  41. package/dist/auth/no-auth.js +21 -0
  42. package/dist/auth/no-auth.js.map +1 -0
  43. package/dist/auth/types.d.ts +58 -0
  44. package/dist/auth/types.d.ts.map +1 -0
  45. package/dist/auth/types.js +2 -0
  46. package/dist/auth/types.js.map +1 -0
  47. package/dist/coding-agent/claude-code.d.ts +10 -0
  48. package/dist/coding-agent/claude-code.d.ts.map +1 -0
  49. package/dist/coding-agent/claude-code.js +38 -0
  50. package/dist/coding-agent/claude-code.js.map +1 -0
  51. package/dist/coding-agent/google-gemini.d.ts +10 -0
  52. package/dist/coding-agent/google-gemini.d.ts.map +1 -0
  53. package/dist/coding-agent/google-gemini.js +29 -0
  54. package/dist/coding-agent/google-gemini.js.map +1 -0
  55. package/dist/coding-agent/index.d.ts +8 -0
  56. package/dist/coding-agent/index.d.ts.map +1 -0
  57. package/dist/coding-agent/index.js +4 -0
  58. package/dist/coding-agent/index.js.map +1 -0
  59. package/dist/coding-agent/openai-codex.d.ts +10 -0
  60. package/dist/coding-agent/openai-codex.d.ts.map +1 -0
  61. package/dist/coding-agent/openai-codex.js +29 -0
  62. package/dist/coding-agent/openai-codex.js.map +1 -0
  63. package/dist/coding-agent/shared.d.ts +10 -0
  64. package/dist/coding-agent/shared.d.ts.map +1 -0
  65. package/dist/coding-agent/shared.js +44 -0
  66. package/dist/coding-agent/shared.js.map +1 -0
  67. package/dist/coding-agent/types.d.ts +10 -0
  68. package/dist/coding-agent/types.d.ts.map +1 -0
  69. package/dist/coding-agent/types.js +2 -0
  70. package/dist/coding-agent/types.js.map +1 -0
  71. package/dist/credential-vault/aws-secrets-manager.d.ts +19 -0
  72. package/dist/credential-vault/aws-secrets-manager.d.ts.map +1 -0
  73. package/dist/credential-vault/aws-secrets-manager.js +96 -0
  74. package/dist/credential-vault/aws-secrets-manager.js.map +1 -0
  75. package/dist/credential-vault/env-vault.d.ts +15 -0
  76. package/dist/credential-vault/env-vault.d.ts.map +1 -0
  77. package/dist/credential-vault/env-vault.js +25 -0
  78. package/dist/credential-vault/env-vault.js.map +1 -0
  79. package/dist/credential-vault/index.d.ts +6 -0
  80. package/dist/credential-vault/index.d.ts.map +1 -0
  81. package/dist/credential-vault/index.js +3 -0
  82. package/dist/credential-vault/index.js.map +1 -0
  83. package/dist/credential-vault/types.d.ts +30 -0
  84. package/dist/credential-vault/types.d.ts.map +1 -0
  85. package/dist/credential-vault/types.js +2 -0
  86. package/dist/credential-vault/types.js.map +1 -0
  87. package/dist/errors.d.ts +18 -0
  88. package/dist/errors.d.ts.map +1 -0
  89. package/dist/errors.js +35 -0
  90. package/dist/errors.js.map +1 -0
  91. package/dist/incident/index.d.ts +4 -0
  92. package/dist/incident/index.d.ts.map +1 -0
  93. package/dist/incident/index.js +3 -0
  94. package/dist/incident/index.js.map +1 -0
  95. package/dist/incident/opsgenie.d.ts +19 -0
  96. package/dist/incident/opsgenie.d.ts.map +1 -0
  97. package/dist/incident/opsgenie.js +104 -0
  98. package/dist/incident/opsgenie.js.map +1 -0
  99. package/dist/incident/pagerduty.d.ts +19 -0
  100. package/dist/incident/pagerduty.d.ts.map +1 -0
  101. package/dist/incident/pagerduty.js +115 -0
  102. package/dist/incident/pagerduty.js.map +1 -0
  103. package/dist/incident/types.d.ts +67 -0
  104. package/dist/incident/types.d.ts.map +1 -0
  105. package/dist/incident/types.js +2 -0
  106. package/dist/incident/types.js.map +1 -0
  107. package/dist/index.d.ts +28 -0
  108. package/dist/index.d.ts.map +1 -0
  109. package/dist/index.js +16 -0
  110. package/dist/index.js.map +1 -0
  111. package/dist/issue-tracking/github-issues.d.ts +22 -0
  112. package/dist/issue-tracking/github-issues.d.ts.map +1 -0
  113. package/dist/issue-tracking/github-issues.js +136 -0
  114. package/dist/issue-tracking/github-issues.js.map +1 -0
  115. package/dist/issue-tracking/index.d.ts +6 -0
  116. package/dist/issue-tracking/index.d.ts.map +1 -0
  117. package/dist/issue-tracking/index.js +5 -0
  118. package/dist/issue-tracking/index.js.map +1 -0
  119. package/dist/issue-tracking/jira.d.ts +22 -0
  120. package/dist/issue-tracking/jira.d.ts.map +1 -0
  121. package/dist/issue-tracking/jira.js +225 -0
  122. package/dist/issue-tracking/jira.js.map +1 -0
  123. package/dist/issue-tracking/linear.d.ts +16 -0
  124. package/dist/issue-tracking/linear.d.ts.map +1 -0
  125. package/dist/issue-tracking/linear.js +311 -0
  126. package/dist/issue-tracking/linear.js.map +1 -0
  127. package/dist/issue-tracking/types.d.ts +163 -0
  128. package/dist/issue-tracking/types.d.ts.map +1 -0
  129. package/dist/issue-tracking/types.js +28 -0
  130. package/dist/issue-tracking/types.js.map +1 -0
  131. package/dist/logger.d.ts +8 -0
  132. package/dist/logger.d.ts.map +1 -0
  133. package/dist/logger.js +7 -0
  134. package/dist/logger.js.map +1 -0
  135. package/dist/messaging/index.d.ts +6 -0
  136. package/dist/messaging/index.d.ts.map +1 -0
  137. package/dist/messaging/index.js +3 -0
  138. package/dist/messaging/index.js.map +1 -0
  139. package/dist/messaging/slack.d.ts +16 -0
  140. package/dist/messaging/slack.d.ts.map +1 -0
  141. package/dist/messaging/slack.js +41 -0
  142. package/dist/messaging/slack.js.map +1 -0
  143. package/dist/messaging/teams.d.ts +22 -0
  144. package/dist/messaging/teams.d.ts.map +1 -0
  145. package/dist/messaging/teams.js +125 -0
  146. package/dist/messaging/teams.js.map +1 -0
  147. package/dist/messaging/types.d.ts +30 -0
  148. package/dist/messaging/types.d.ts.map +1 -0
  149. package/dist/messaging/types.js +2 -0
  150. package/dist/messaging/types.js.map +1 -0
  151. package/dist/notification/discord-webhook.d.ts +16 -0
  152. package/dist/notification/discord-webhook.d.ts.map +1 -0
  153. package/dist/notification/discord-webhook.js +104 -0
  154. package/dist/notification/discord-webhook.js.map +1 -0
  155. package/dist/notification/email.d.ts +22 -0
  156. package/dist/notification/email.d.ts.map +1 -0
  157. package/dist/notification/email.js +127 -0
  158. package/dist/notification/email.js.map +1 -0
  159. package/dist/notification/github-summary.d.ts +13 -0
  160. package/dist/notification/github-summary.d.ts.map +1 -0
  161. package/dist/notification/github-summary.js +67 -0
  162. package/dist/notification/github-summary.js.map +1 -0
  163. package/dist/notification/index.d.ts +8 -0
  164. package/dist/notification/index.d.ts.map +1 -0
  165. package/dist/notification/index.js +7 -0
  166. package/dist/notification/index.js.map +1 -0
  167. package/dist/notification/slack-webhook.d.ts +16 -0
  168. package/dist/notification/slack-webhook.d.ts.map +1 -0
  169. package/dist/notification/slack-webhook.js +123 -0
  170. package/dist/notification/slack-webhook.js.map +1 -0
  171. package/dist/notification/teams-webhook.d.ts +16 -0
  172. package/dist/notification/teams-webhook.d.ts.map +1 -0
  173. package/dist/notification/teams-webhook.js +125 -0
  174. package/dist/notification/teams-webhook.js.map +1 -0
  175. package/dist/notification/types.d.ts +47 -0
  176. package/dist/notification/types.d.ts.map +1 -0
  177. package/dist/notification/types.js +2 -0
  178. package/dist/notification/types.js.map +1 -0
  179. package/dist/notification/webhook.d.ts +28 -0
  180. package/dist/notification/webhook.d.ts.map +1 -0
  181. package/dist/notification/webhook.js +64 -0
  182. package/dist/notification/webhook.js.map +1 -0
  183. package/dist/observability/cloudwatch.d.ts +19 -0
  184. package/dist/observability/cloudwatch.d.ts.map +1 -0
  185. package/dist/observability/cloudwatch.js +182 -0
  186. package/dist/observability/cloudwatch.js.map +1 -0
  187. package/dist/observability/datadog.d.ts +22 -0
  188. package/dist/observability/datadog.d.ts.map +1 -0
  189. package/dist/observability/datadog.js +139 -0
  190. package/dist/observability/datadog.js.map +1 -0
  191. package/dist/observability/elastic.d.ts +42 -0
  192. package/dist/observability/elastic.d.ts.map +1 -0
  193. package/dist/observability/elastic.js +244 -0
  194. package/dist/observability/elastic.js.map +1 -0
  195. package/dist/observability/file.d.ts +16 -0
  196. package/dist/observability/file.d.ts.map +1 -0
  197. package/dist/observability/file.js +92 -0
  198. package/dist/observability/file.js.map +1 -0
  199. package/dist/observability/index.d.ts +10 -0
  200. package/dist/observability/index.d.ts.map +1 -0
  201. package/dist/observability/index.js +9 -0
  202. package/dist/observability/index.js.map +1 -0
  203. package/dist/observability/loki.d.ts +22 -0
  204. package/dist/observability/loki.d.ts.map +1 -0
  205. package/dist/observability/loki.js +206 -0
  206. package/dist/observability/loki.js.map +1 -0
  207. package/dist/observability/newrelic.d.ts +22 -0
  208. package/dist/observability/newrelic.d.ts.map +1 -0
  209. package/dist/observability/newrelic.js +147 -0
  210. package/dist/observability/newrelic.js.map +1 -0
  211. package/dist/observability/sentry.d.ts +25 -0
  212. package/dist/observability/sentry.d.ts.map +1 -0
  213. package/dist/observability/sentry.js +151 -0
  214. package/dist/observability/sentry.js.map +1 -0
  215. package/dist/observability/splunk.d.ts +22 -0
  216. package/dist/observability/splunk.d.ts.map +1 -0
  217. package/dist/observability/splunk.js +178 -0
  218. package/dist/observability/splunk.js.map +1 -0
  219. package/dist/observability/types.d.ts +54 -0
  220. package/dist/observability/types.d.ts.map +1 -0
  221. package/dist/observability/types.js +2 -0
  222. package/dist/observability/types.js.map +1 -0
  223. package/dist/source-control/github.d.ts +11 -0
  224. package/dist/source-control/github.d.ts.map +1 -0
  225. package/dist/source-control/github.js +162 -0
  226. package/dist/source-control/github.js.map +1 -0
  227. package/dist/source-control/gitlab.d.ts +25 -0
  228. package/dist/source-control/gitlab.d.ts.map +1 -0
  229. package/dist/source-control/gitlab.js +224 -0
  230. package/dist/source-control/gitlab.js.map +1 -0
  231. package/dist/source-control/index.d.ts +6 -0
  232. package/dist/source-control/index.d.ts.map +1 -0
  233. package/dist/source-control/index.js +3 -0
  234. package/dist/source-control/index.js.map +1 -0
  235. package/dist/source-control/types.d.ts +115 -0
  236. package/dist/source-control/types.d.ts.map +1 -0
  237. package/dist/source-control/types.js +2 -0
  238. package/dist/source-control/types.js.map +1 -0
  239. package/dist/storage/csi.d.ts +36 -0
  240. package/dist/storage/csi.d.ts.map +1 -0
  241. package/dist/storage/csi.js +39 -0
  242. package/dist/storage/csi.js.map +1 -0
  243. package/dist/storage/fs.d.ts +5 -0
  244. package/dist/storage/fs.d.ts.map +1 -0
  245. package/dist/storage/fs.js +11 -0
  246. package/dist/storage/fs.js.map +1 -0
  247. package/dist/storage/index.d.ts +13 -0
  248. package/dist/storage/index.d.ts.map +1 -0
  249. package/dist/storage/index.js +14 -0
  250. package/dist/storage/index.js.map +1 -0
  251. package/dist/storage/memory/fs.d.ts +15 -0
  252. package/dist/storage/memory/fs.d.ts.map +1 -0
  253. package/dist/storage/memory/fs.js +65 -0
  254. package/dist/storage/memory/fs.js.map +1 -0
  255. package/dist/storage/memory/s3.d.ts +17 -0
  256. package/dist/storage/memory/s3.d.ts.map +1 -0
  257. package/dist/storage/memory/s3.js +77 -0
  258. package/dist/storage/memory/s3.js.map +1 -0
  259. package/dist/storage/s3.d.ts +7 -0
  260. package/dist/storage/s3.d.ts.map +1 -0
  261. package/dist/storage/s3.js +12 -0
  262. package/dist/storage/s3.js.map +1 -0
  263. package/dist/storage/session/fs.d.ts +16 -0
  264. package/dist/storage/session/fs.d.ts.map +1 -0
  265. package/dist/storage/session/fs.js +81 -0
  266. package/dist/storage/session/fs.js.map +1 -0
  267. package/dist/storage/session/s3.d.ts +18 -0
  268. package/dist/storage/session/s3.d.ts.map +1 -0
  269. package/dist/storage/session/s3.js +121 -0
  270. package/dist/storage/session/s3.js.map +1 -0
  271. package/dist/storage/types.d.ts +206 -0
  272. package/dist/storage/types.d.ts.map +1 -0
  273. package/dist/storage/types.js +10 -0
  274. package/dist/storage/types.js.map +1 -0
  275. package/dist/storage/workspace/fs.d.ts +18 -0
  276. package/dist/storage/workspace/fs.d.ts.map +1 -0
  277. package/dist/storage/workspace/fs.js +153 -0
  278. package/dist/storage/workspace/fs.js.map +1 -0
  279. package/dist/storage/workspace/s3.d.ts +20 -0
  280. package/dist/storage/workspace/s3.d.ts.map +1 -0
  281. package/dist/storage/workspace/s3.js +180 -0
  282. package/dist/storage/workspace/s3.js.map +1 -0
  283. package/package.json +137 -0
@@ -0,0 +1,182 @@
1
+ import { z } from "zod";
2
+ import { consoleLogger } from "../logger.js";
3
+ import { ProviderApiError } from "../errors.js";
4
+ export const cloudwatchConfigSchema = z.object({
5
+ region: z.string().default("us-east-1"),
6
+ logGroupPrefix: z.string().min(1, "CloudWatch log group prefix is required"),
7
+ logger: z.custom().optional(),
8
+ });
9
+ export function cloudwatch(config) {
10
+ const parsed = cloudwatchConfigSchema.parse(config);
11
+ return new CloudWatchProvider(parsed);
12
+ }
13
+ function parseTimeRange(timeRange) {
14
+ const match = timeRange.match(/^(\d+)(m|h|d)$/);
15
+ if (!match)
16
+ throw new Error(`Invalid time range: ${timeRange}`);
17
+ const [, value, unit] = match;
18
+ const ms = { m: 60_000, h: 3_600_000, d: 86_400_000 };
19
+ return parseInt(value, 10) * ms[unit];
20
+ }
21
+ class CloudWatchProvider {
22
+ region;
23
+ logGroupPrefix;
24
+ log;
25
+ client;
26
+ constructor(config) {
27
+ this.region = config.region;
28
+ this.logGroupPrefix = config.logGroupPrefix;
29
+ this.log = config.logger ?? consoleLogger;
30
+ }
31
+ async getClient() {
32
+ if (!this.client) {
33
+ const { CloudWatchLogsClient } = await import("@aws-sdk/client-cloudwatch-logs");
34
+ this.client = new CloudWatchLogsClient({ region: this.region });
35
+ }
36
+ return this.client;
37
+ }
38
+ async verifyAccess() {
39
+ this.log.info(`Verifying CloudWatch access (region: ${this.region})`);
40
+ const client = (await this.getClient());
41
+ const { DescribeLogGroupsCommand } = await import("@aws-sdk/client-cloudwatch-logs");
42
+ await client.send(new DescribeLogGroupsCommand({
43
+ logGroupNamePrefix: this.logGroupPrefix,
44
+ limit: 1,
45
+ }));
46
+ this.log.info("CloudWatch access verified");
47
+ }
48
+ async queryLogs(opts) {
49
+ this.log.info(`Querying CloudWatch logs (range: ${opts.timeRange}, severity: ${opts.severity})`);
50
+ const client = (await this.getClient());
51
+ const { StartQueryCommand, GetQueryResultsCommand } = await import("@aws-sdk/client-cloudwatch-logs");
52
+ const endTime = Date.now();
53
+ const startTime = endTime - parseTimeRange(opts.timeRange);
54
+ const serviceFilter = opts.serviceFilter && opts.serviceFilter !== "*" ? `| filter @logStream like /${opts.serviceFilter}/` : "";
55
+ const queryString = `fields @timestamp, @message, @logStream
56
+ ${serviceFilter}
57
+ | filter @message like /(?i)${opts.severity}/
58
+ | sort @timestamp desc
59
+ | limit 100`;
60
+ const startResult = await client.send(new StartQueryCommand({
61
+ logGroupName: this.logGroupPrefix,
62
+ startTime: Math.floor(startTime / 1000),
63
+ endTime: Math.floor(endTime / 1000),
64
+ queryString,
65
+ }));
66
+ const queryId = startResult.queryId;
67
+ if (!queryId)
68
+ throw new ProviderApiError("CloudWatch", 0, "StartQuery did not return a queryId", "");
69
+ // Poll for results
70
+ let results = [];
71
+ for (let i = 0; i < 30; i++) {
72
+ await new Promise((r) => setTimeout(r, 1000));
73
+ const queryResult = await client.send(new GetQueryResultsCommand({ queryId }));
74
+ if (queryResult.status === "Complete") {
75
+ results = queryResult.results ?? [];
76
+ break;
77
+ }
78
+ }
79
+ const logs = results.map((row) => {
80
+ const fields = Object.fromEntries(row.map((f) => [f.field, f.value]));
81
+ return {
82
+ timestamp: fields["@timestamp"] || "",
83
+ service: fields["@logStream"] || "unknown",
84
+ level: opts.severity,
85
+ message: fields["@message"] || "",
86
+ attributes: {},
87
+ };
88
+ });
89
+ this.log.info(`Found ${logs.length} CloudWatch log entries`);
90
+ return logs;
91
+ }
92
+ getAgentEnv() {
93
+ return {
94
+ AWS_REGION: this.region,
95
+ CW_LOG_GROUP_PREFIX: this.logGroupPrefix,
96
+ };
97
+ }
98
+ getPromptInstructions() {
99
+ return `### CloudWatch Logs Insights
100
+ - \`AWS_REGION\` - AWS region (${this.region})
101
+ - \`CW_LOG_GROUP_PREFIX\` - Log group prefix (${this.logGroupPrefix})
102
+
103
+ **DO NOT make up data** - only use real data from APIs. If no data, report that honestly.
104
+
105
+ Investigate logs from CloudWatch Logs across **BOTH production AND staging environments** to find bugs and issues.
106
+ You have DIRECT ACCESS to AWS CloudWatch Logs via the AWS CLI.
107
+
108
+ **Key Insight**: Catching issues in staging BEFORE they hit production is extremely valuable!
109
+ - Issues in staging only → Fix before users are affected
110
+ - Issues in both environments → Critical, affects users now
111
+ - Issues in production only → May be load/scale related
112
+
113
+ AWS credentials are configured via the standard AWS credential chain (environment variables or instance profile).
114
+
115
+ #### Example: Start a Logs Insights query
116
+ \`\`\`bash
117
+ aws logs start-query \\
118
+ --log-group-name "\${CW_LOG_GROUP_PREFIX}" \\
119
+ --start-time $(date -d '-1 hour' +%s) \\
120
+ --end-time $(date +%s) \\
121
+ --query-string 'fields @timestamp, @message | filter @message like /(?i)error/ | sort @timestamp desc | limit 100' \\
122
+ --region "\${AWS_REGION}"
123
+ \`\`\`
124
+
125
+ #### Example: Get query results
126
+ \`\`\`bash
127
+ aws logs get-query-results --query-id "<query-id>" --region "\${AWS_REGION}"
128
+ \`\`\`
129
+
130
+ #### Example: Get error counts by log stream
131
+ \`\`\`bash
132
+ aws logs start-query \\
133
+ --log-group-name "\${CW_LOG_GROUP_PREFIX}" \\
134
+ --start-time $(date -d '-1 hour' +%s) \\
135
+ --end-time $(date +%s) \\
136
+ --query-string 'filter @message like /(?i)error/ | stats count(*) as errorCount by @logStream | sort errorCount desc | limit 20' \\
137
+ --region "\${AWS_REGION}"
138
+ \`\`\``;
139
+ }
140
+ async aggregate(opts) {
141
+ this.log.info(`Aggregating CloudWatch errors (range: ${opts.timeRange})`);
142
+ const client = (await this.getClient());
143
+ const { StartQueryCommand, GetQueryResultsCommand } = await import("@aws-sdk/client-cloudwatch-logs");
144
+ const endTime = Date.now();
145
+ const startTime = endTime - parseTimeRange(opts.timeRange);
146
+ const serviceFilter = opts.serviceFilter && opts.serviceFilter !== "*" ? `| filter @logStream like /${opts.serviceFilter}/` : "";
147
+ const queryString = `fields @logStream
148
+ ${serviceFilter}
149
+ | filter @message like /(?i)error/
150
+ | stats count(*) as errorCount by @logStream
151
+ | sort errorCount desc
152
+ | limit 20`;
153
+ const startResult = await client.send(new StartQueryCommand({
154
+ logGroupName: this.logGroupPrefix,
155
+ startTime: Math.floor(startTime / 1000),
156
+ endTime: Math.floor(endTime / 1000),
157
+ queryString,
158
+ }));
159
+ const queryId = startResult.queryId;
160
+ if (!queryId)
161
+ throw new ProviderApiError("CloudWatch", 0, "StartQuery did not return a queryId", "");
162
+ let results = [];
163
+ for (let i = 0; i < 30; i++) {
164
+ await new Promise((r) => setTimeout(r, 1000));
165
+ const queryResult = await client.send(new GetQueryResultsCommand({ queryId }));
166
+ if (queryResult.status === "Complete") {
167
+ results = queryResult.results ?? [];
168
+ break;
169
+ }
170
+ }
171
+ const groups = results.map((row) => {
172
+ const fields = Object.fromEntries(row.map((f) => [f.field, f.value]));
173
+ return {
174
+ service: fields["@logStream"] || "unknown",
175
+ count: parseInt(fields["errorCount"] || "0", 10),
176
+ };
177
+ });
178
+ this.log.info(`Aggregated ${groups.length} service groups`);
179
+ return groups;
180
+ }
181
+ }
182
+ //# sourceMappingURL=cloudwatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudwatch.js","sourceRoot":"","sources":["../../src/observability/cloudwatch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { z } from "zod";
2
+ import type { Logger } from "../logger.js";
3
+ import type { ObservabilityProvider } from "./types.js";
4
+ export declare const datadogConfigSchema: z.ZodObject<{
5
+ apiKey: z.ZodString;
6
+ appKey: z.ZodString;
7
+ site: z.ZodDefault<z.ZodString>;
8
+ logger: z.ZodOptional<z.ZodType<Logger, z.ZodTypeDef, Logger>>;
9
+ }, "strip", z.ZodTypeAny, {
10
+ apiKey: string;
11
+ appKey: string;
12
+ site: string;
13
+ logger?: Logger | undefined;
14
+ }, {
15
+ apiKey: string;
16
+ appKey: string;
17
+ site?: string | undefined;
18
+ logger?: Logger | undefined;
19
+ }>;
20
+ export type DatadogConfig = z.infer<typeof datadogConfigSchema>;
21
+ export declare function datadog(config: DatadogConfig): ObservabilityProvider;
22
+ //# sourceMappingURL=datadog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"datadog.d.ts","sourceRoot":"","sources":["../../src/observability/datadog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAG3C,OAAO,KAAK,EAAE,qBAAqB,EAA8C,MAAM,YAAY,CAAC;AAEpG,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;EAK9B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,wBAAgB,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG,qBAAqB,CAGpE"}
@@ -0,0 +1,139 @@
1
+ import { z } from "zod";
2
+ import { consoleLogger } from "../logger.js";
3
+ import { ProviderApiError } from "../errors.js";
4
+ export const datadogConfigSchema = z.object({
5
+ apiKey: z.string().min(1, "Datadog API key is required"),
6
+ appKey: z.string().min(1, "Datadog Application key is required"),
7
+ site: z.string().default("datadoghq.com"),
8
+ logger: z.custom().optional(),
9
+ });
10
+ export function datadog(config) {
11
+ const parsed = datadogConfigSchema.parse(config);
12
+ return new DatadogProvider(parsed);
13
+ }
14
+ class DatadogProvider {
15
+ apiKey;
16
+ appKey;
17
+ site;
18
+ log;
19
+ constructor(config) {
20
+ this.apiKey = config.apiKey;
21
+ this.appKey = config.appKey;
22
+ this.site = config.site;
23
+ this.log = config.logger ?? consoleLogger;
24
+ }
25
+ async request(path, body) {
26
+ const url = `https://api.${this.site}${path}`;
27
+ const response = await fetch(url, {
28
+ method: "POST",
29
+ headers: {
30
+ "Content-Type": "application/json",
31
+ "DD-API-KEY": this.apiKey,
32
+ "DD-APPLICATION-KEY": this.appKey,
33
+ },
34
+ body: JSON.stringify(body),
35
+ });
36
+ if (!response.ok) {
37
+ const body = await response.text().catch(() => "");
38
+ throw new ProviderApiError("Datadog", response.status, response.statusText, body);
39
+ }
40
+ return (await response.json());
41
+ }
42
+ async verifyAccess() {
43
+ this.log.info(`Verifying Datadog access (site: ${this.site})`);
44
+ await this.request("/api/v2/logs/analytics/aggregate", {
45
+ filter: { query: "*", from: "now-5m", to: "now" },
46
+ compute: [{ type: "total", aggregation: "count" }],
47
+ });
48
+ this.log.info("Datadog API access verified");
49
+ }
50
+ async queryLogs(opts) {
51
+ const query = `service:${opts.serviceFilter} status:${opts.severity}`;
52
+ this.log.info(`Querying Datadog logs: ${query} (range: ${opts.timeRange})`);
53
+ const result = await this.request("/api/v2/logs/events/search", {
54
+ filter: { query, from: `now-${opts.timeRange}`, to: "now" },
55
+ sort: "-timestamp",
56
+ page: { limit: 100 },
57
+ });
58
+ const logs = (result.data || []).map((entry) => ({
59
+ timestamp: entry.attributes?.timestamp || "",
60
+ service: entry.attributes?.service || "",
61
+ level: entry.attributes?.status || "",
62
+ message: entry.attributes?.message || "",
63
+ attributes: entry.attributes?.attributes || {},
64
+ }));
65
+ this.log.info(`Found ${logs.length} ${opts.severity} logs for ${opts.serviceFilter} in last ${opts.timeRange}`);
66
+ return logs;
67
+ }
68
+ getAgentEnv() {
69
+ return {
70
+ DD_API_KEY: this.apiKey,
71
+ DD_APP_KEY: this.appKey,
72
+ DD_SITE: this.site,
73
+ };
74
+ }
75
+ getPromptInstructions() {
76
+ return `### Datadog Logs API
77
+ - \`DD_API_KEY\` - API key (use in DD-API-KEY header)
78
+ - \`DD_APP_KEY\` - Application key (use in DD-APPLICATION-KEY header)
79
+ - \`DD_SITE\` - Datadog site (${this.site})
80
+
81
+ **DO NOT make up data** - only use real data from APIs. If no data, report that honestly.
82
+
83
+ Investigate logs from Datadog across **BOTH production AND staging environments** to find bugs and issues.
84
+ You have DIRECT ACCESS to Datadog's Logs API via curl commands.
85
+
86
+ **Key Insight**: Catching issues in staging BEFORE they hit production is extremely valuable!
87
+ - Issues in staging only → Fix before users are affected
88
+ - Issues in both environments → Critical, affects users now
89
+ - Issues in production only → May be load/scale related
90
+
91
+ Use these environment variables in your curl commands:
92
+ - \`DD_API_KEY\` - API key (use in DD-API-KEY header)
93
+ - \`DD_APP_KEY\` - Application key (use in DD-APPLICATION-KEY header)
94
+ - \`DD_SITE\` - Datadog site (${this.site})
95
+
96
+ #### Example: Get error counts by service
97
+ \`\`\`bash
98
+ curl -s -X POST "https://api.\${DD_SITE}/api/v2/logs/analytics/aggregate" \\
99
+ -H "Content-Type: application/json" \\
100
+ -H "DD-API-KEY: \${DD_API_KEY}" \\
101
+ -H "DD-APPLICATION-KEY: \${DD_APP_KEY}" \\
102
+ -d '{"filter":{"query":"service:* status:error","from":"now-1h","to":"now"},"compute":[{"type":"total","aggregation":"count"}],"group_by":[{"facet":"service","limit":20,"sort":{"type":"measure","aggregation":"count","order":"desc"}}]}'
103
+ \`\`\`
104
+
105
+ #### Example: Get recent error logs
106
+ \`\`\`bash
107
+ curl -s -X POST "https://api.\${DD_SITE}/api/v2/logs/events/search" \\
108
+ -H "Content-Type: application/json" \\
109
+ -H "DD-API-KEY: \${DD_API_KEY}" \\
110
+ -H "DD-APPLICATION-KEY: \${DD_APP_KEY}" \\
111
+ -d '{"filter":{"query":"service:* status:error","from":"now-1h","to":"now"},"sort":"-timestamp","page":{"limit":100}}'
112
+ \`\`\``;
113
+ }
114
+ async aggregate(opts) {
115
+ this.log.info(`Aggregating Datadog errors for ${opts.serviceFilter} (range: ${opts.timeRange})`);
116
+ const result = await this.request("/api/v2/logs/analytics/aggregate", {
117
+ filter: {
118
+ query: `service:${opts.serviceFilter} status:error`,
119
+ from: `now-${opts.timeRange}`,
120
+ to: "now",
121
+ },
122
+ compute: [{ type: "total", aggregation: "count" }],
123
+ group_by: [
124
+ {
125
+ facet: "service",
126
+ limit: 20,
127
+ sort: { type: "measure", aggregation: "count", order: "desc" },
128
+ },
129
+ ],
130
+ });
131
+ const groups = (result.data?.buckets || []).map((bucket) => ({
132
+ service: bucket.by?.service || "unknown",
133
+ count: bucket.computes?.c0 || 0,
134
+ }));
135
+ this.log.info(`Aggregated ${groups.length} service groups`);
136
+ return groups;
137
+ }
138
+ }
139
+ //# sourceMappingURL=datadog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"datadog.js","sourceRoot":"","sources":["../../src/observability/datadog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import { z } from "zod";
2
+ import type { Logger } from "../logger.js";
3
+ import type { ObservabilityProvider } from "./types.js";
4
+ export declare const elasticConfigSchema: z.ZodEffects<z.ZodObject<{
5
+ baseUrl: z.ZodString;
6
+ apiKey: z.ZodOptional<z.ZodString>;
7
+ username: z.ZodOptional<z.ZodString>;
8
+ password: z.ZodOptional<z.ZodString>;
9
+ index: z.ZodDefault<z.ZodString>;
10
+ logger: z.ZodOptional<z.ZodType<Logger, z.ZodTypeDef, Logger>>;
11
+ }, "strip", z.ZodTypeAny, {
12
+ baseUrl: string;
13
+ index: string;
14
+ apiKey?: string | undefined;
15
+ logger?: Logger | undefined;
16
+ username?: string | undefined;
17
+ password?: string | undefined;
18
+ }, {
19
+ baseUrl: string;
20
+ apiKey?: string | undefined;
21
+ logger?: Logger | undefined;
22
+ index?: string | undefined;
23
+ username?: string | undefined;
24
+ password?: string | undefined;
25
+ }>, {
26
+ baseUrl: string;
27
+ index: string;
28
+ apiKey?: string | undefined;
29
+ logger?: Logger | undefined;
30
+ username?: string | undefined;
31
+ password?: string | undefined;
32
+ }, {
33
+ baseUrl: string;
34
+ apiKey?: string | undefined;
35
+ logger?: Logger | undefined;
36
+ index?: string | undefined;
37
+ username?: string | undefined;
38
+ password?: string | undefined;
39
+ }>;
40
+ export type ElasticConfig = z.infer<typeof elasticConfigSchema>;
41
+ export declare function elastic(config: ElasticConfig): ObservabilityProvider;
42
+ //# sourceMappingURL=elastic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elastic.d.ts","sourceRoot":"","sources":["../../src/observability/elastic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAG3C,OAAO,KAAK,EAAE,qBAAqB,EAA8C,MAAM,YAAY,CAAC;AAEpG,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAW5B,CAAC;AAEL,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,wBAAgB,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG,qBAAqB,CAGpE"}
@@ -0,0 +1,244 @@
1
+ import { z } from "zod";
2
+ import { consoleLogger } from "../logger.js";
3
+ import { ProviderApiError } from "../errors.js";
4
+ export const elasticConfigSchema = z
5
+ .object({
6
+ baseUrl: z.string().min(1, "Elasticsearch URL is required"),
7
+ apiKey: z.string().min(1).optional(),
8
+ username: z.string().min(1).optional(),
9
+ password: z.string().min(1).optional(),
10
+ index: z.string().default("logs-*"),
11
+ logger: z.custom().optional(),
12
+ })
13
+ .refine((c) => c.apiKey || (c.username && c.password), {
14
+ message: "Either apiKey or both username and password must be provided",
15
+ });
16
+ export function elastic(config) {
17
+ const parsed = elasticConfigSchema.parse(config);
18
+ return new ElasticProvider(parsed);
19
+ }
20
+ /** Safely extract a string from an unknown value, returning undefined for non-strings. */
21
+ function str(v) {
22
+ return typeof v === "string" ? v : undefined;
23
+ }
24
+ class ElasticProvider {
25
+ baseUrl;
26
+ apiKey;
27
+ username;
28
+ password;
29
+ index;
30
+ log;
31
+ constructor(config) {
32
+ this.baseUrl = config.baseUrl.replace(/\/+$/, "");
33
+ this.apiKey = config.apiKey;
34
+ this.username = config.username;
35
+ this.password = config.password;
36
+ this.index = config.index;
37
+ this.log = config.logger ?? consoleLogger;
38
+ }
39
+ authHeaders() {
40
+ if (this.apiKey) {
41
+ return { Authorization: `ApiKey ${this.apiKey}` };
42
+ }
43
+ const encoded = Buffer.from(`${this.username}:${this.password}`).toString("base64");
44
+ return { Authorization: `Basic ${encoded}` };
45
+ }
46
+ async request(method, path, body) {
47
+ const url = `${this.baseUrl}${path}`;
48
+ const response = await fetch(url, {
49
+ method,
50
+ headers: {
51
+ "Content-Type": "application/json",
52
+ ...this.authHeaders(),
53
+ },
54
+ ...(body ? { body: JSON.stringify(body) } : {}),
55
+ });
56
+ if (!response.ok) {
57
+ const body = await response.text().catch(() => "");
58
+ throw new ProviderApiError("Elasticsearch", response.status, response.statusText, body);
59
+ }
60
+ return (await response.json());
61
+ }
62
+ /**
63
+ * Convert time range strings like "1h", "24h", "7d" to Elasticsearch
64
+ * date math format "now-1h", "now-24h", "now-7d".
65
+ */
66
+ toElasticRange(timeRange) {
67
+ // Already in Elasticsearch format
68
+ if (timeRange.startsWith("now-")) {
69
+ return timeRange;
70
+ }
71
+ return `now-${timeRange}`;
72
+ }
73
+ async verifyAccess() {
74
+ this.log.info(`Verifying Elasticsearch access (${this.baseUrl})`);
75
+ const info = await this.request("GET", "/");
76
+ this.log.info(`Elasticsearch access verified (cluster: ${info.cluster_name ?? "unknown"}, version: ${info.version?.number ?? "unknown"})`);
77
+ }
78
+ async queryLogs(opts) {
79
+ this.log.info(`Querying Elasticsearch logs (severity: ${opts.severity}, range: ${opts.timeRange}, service: ${opts.serviceFilter})`);
80
+ const must = [
81
+ {
82
+ range: {
83
+ "@timestamp": {
84
+ gte: this.toElasticRange(opts.timeRange),
85
+ lte: "now",
86
+ },
87
+ },
88
+ },
89
+ ];
90
+ if (opts.severity && opts.severity !== "*") {
91
+ must.push({ match: { "log.level": opts.severity } });
92
+ }
93
+ if (opts.serviceFilter && opts.serviceFilter !== "*") {
94
+ must.push({
95
+ bool: {
96
+ should: [{ match: { "service.name": opts.serviceFilter } }, { match: { "host.name": opts.serviceFilter } }],
97
+ minimum_should_match: 1,
98
+ },
99
+ });
100
+ }
101
+ const result = await this.request("POST", `/${this.index}/_search`, {
102
+ size: 100,
103
+ sort: [{ "@timestamp": { order: "desc" } }],
104
+ query: {
105
+ bool: { must },
106
+ },
107
+ });
108
+ const hits = result.hits?.hits ?? [];
109
+ const logs = hits.map((hit) => {
110
+ const src = hit._source ?? {};
111
+ const service = str(src["service.name"]) ??
112
+ (src["service"] && typeof src["service"] === "object"
113
+ ? str(src["service"]["name"])
114
+ : undefined) ??
115
+ str(src["host.name"]) ??
116
+ (src["host"] && typeof src["host"] === "object"
117
+ ? str(src["host"]["name"])
118
+ : undefined) ??
119
+ "unknown";
120
+ const level = str(src["log.level"]) ??
121
+ (src["log"] && typeof src["log"] === "object"
122
+ ? str(src["log"]["level"])
123
+ : undefined) ??
124
+ "unknown";
125
+ return {
126
+ timestamp: str(src["@timestamp"]) ?? "",
127
+ service,
128
+ level,
129
+ message: str(src["message"]) ?? "",
130
+ attributes: src,
131
+ };
132
+ });
133
+ this.log.info(`Found ${logs.length} log entries`);
134
+ return logs;
135
+ }
136
+ async aggregate(opts) {
137
+ this.log.info(`Aggregating Elasticsearch logs (range: ${opts.timeRange}, service: ${opts.serviceFilter})`);
138
+ const must = [
139
+ {
140
+ range: {
141
+ "@timestamp": {
142
+ gte: this.toElasticRange(opts.timeRange),
143
+ lte: "now",
144
+ },
145
+ },
146
+ },
147
+ ];
148
+ if (opts.serviceFilter && opts.serviceFilter !== "*") {
149
+ must.push({
150
+ bool: {
151
+ should: [{ match: { "service.name": opts.serviceFilter } }, { match: { "host.name": opts.serviceFilter } }],
152
+ minimum_should_match: 1,
153
+ },
154
+ });
155
+ }
156
+ const result = await this.request("POST", `/${this.index}/_search`, {
157
+ size: 0,
158
+ query: {
159
+ bool: { must },
160
+ },
161
+ aggs: {
162
+ services: {
163
+ terms: {
164
+ field: "service.keyword",
165
+ size: 50,
166
+ order: { _count: "desc" },
167
+ },
168
+ },
169
+ },
170
+ });
171
+ const buckets = result.aggregations?.services?.buckets ?? [];
172
+ const results = buckets.map((bucket) => ({
173
+ service: bucket.key,
174
+ count: bucket.doc_count,
175
+ }));
176
+ this.log.info(`Aggregated ${results.length} service groups`);
177
+ return results;
178
+ }
179
+ getAgentEnv() {
180
+ const env = {
181
+ ELASTIC_URL: this.baseUrl,
182
+ ELASTIC_INDEX: this.index,
183
+ };
184
+ if (this.apiKey) {
185
+ env.ELASTIC_API_KEY = this.apiKey;
186
+ }
187
+ else {
188
+ // Zod refine guarantees username+password exist when apiKey is absent
189
+ env.ELASTIC_USERNAME = this.username ?? "";
190
+ env.ELASTIC_PASSWORD = this.password ?? "";
191
+ }
192
+ return env;
193
+ }
194
+ getPromptInstructions() {
195
+ const authHeader = this.apiKey
196
+ ? `-H "Authorization: ApiKey \${ELASTIC_API_KEY}"`
197
+ : `-u "\${ELASTIC_USERNAME}:\${ELASTIC_PASSWORD}"`;
198
+ return `### Elasticsearch Logs API
199
+ - \`ELASTIC_URL\` - Elasticsearch base URL (${this.baseUrl})
200
+ - \`ELASTIC_INDEX\` - Index pattern (${this.index})
201
+ ${this.apiKey ? "- `ELASTIC_API_KEY` - API key for authentication" : "- `ELASTIC_USERNAME` / `ELASTIC_PASSWORD` - Basic auth credentials"}
202
+
203
+ **DO NOT make up data** - only use real data from APIs. If no data, report that honestly.
204
+
205
+ Investigate logs from Elasticsearch across **BOTH production AND staging environments** to find bugs and issues.
206
+ You have DIRECT ACCESS to Elasticsearch's REST API via curl commands.
207
+
208
+ **Key Insight**: Catching issues in staging BEFORE they hit production is extremely valuable!
209
+ - Issues in staging only -> Fix before users are affected
210
+ - Issues in both environments -> Critical, affects users now
211
+ - Issues in production only -> May be load/scale related
212
+
213
+ #### Example: Search for error logs in the last hour
214
+ \`\`\`bash
215
+ curl -s -X POST "\${ELASTIC_URL}/\${ELASTIC_INDEX}/_search" \\
216
+ -H "Content-Type: application/json" \\
217
+ ${authHeader} \\
218
+ -d '{"size":100,"sort":[{"@timestamp":{"order":"desc"}}],"query":{"bool":{"must":[{"range":{"@timestamp":{"gte":"now-1h","lte":"now"}}},{"match":{"log.level":"error"}}]}}}'
219
+ \`\`\`
220
+
221
+ #### Example: Aggregate log counts by service
222
+ \`\`\`bash
223
+ curl -s -X POST "\${ELASTIC_URL}/\${ELASTIC_INDEX}/_search" \\
224
+ -H "Content-Type: application/json" \\
225
+ ${authHeader} \\
226
+ -d '{"size":0,"query":{"bool":{"must":[{"range":{"@timestamp":{"gte":"now-24h","lte":"now"}}}]}},"aggs":{"services":{"terms":{"field":"service.keyword","size":50,"order":{"_count":"desc"}}}}}'
227
+ \`\`\`
228
+
229
+ #### Example: Filter logs by service name
230
+ \`\`\`bash
231
+ curl -s -X POST "\${ELASTIC_URL}/\${ELASTIC_INDEX}/_search" \\
232
+ -H "Content-Type: application/json" \\
233
+ ${authHeader} \\
234
+ -d '{"size":100,"sort":[{"@timestamp":{"order":"desc"}}],"query":{"bool":{"must":[{"range":{"@timestamp":{"gte":"now-1h","lte":"now"}}},{"match":{"service.name":"my-service"}}]}}}'
235
+ \`\`\`
236
+
237
+ #### Example: Get cluster health
238
+ \`\`\`bash
239
+ curl -s "\${ELASTIC_URL}/_cluster/health" \\
240
+ ${authHeader}
241
+ \`\`\``;
242
+ }
243
+ }
244
+ //# sourceMappingURL=elastic.js.map