@sweny-ai/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/dist/__tests__/claude.test.d.ts +1 -0
  2. package/dist/__tests__/claude.test.js +328 -0
  3. package/dist/__tests__/executor.test.d.ts +1 -0
  4. package/dist/__tests__/executor.test.js +296 -0
  5. package/dist/__tests__/integration/datadog.integration.test.d.ts +1 -0
  6. package/dist/__tests__/integration/datadog.integration.test.js +23 -0
  7. package/dist/__tests__/integration/e2e-workflow.integration.test.d.ts +1 -0
  8. package/dist/__tests__/integration/e2e-workflow.integration.test.js +75 -0
  9. package/dist/__tests__/integration/github.integration.test.d.ts +1 -0
  10. package/dist/__tests__/integration/github.integration.test.js +37 -0
  11. package/dist/__tests__/integration/harness.d.ts +24 -0
  12. package/dist/__tests__/integration/harness.js +34 -0
  13. package/dist/__tests__/integration/linear.integration.test.d.ts +1 -0
  14. package/dist/__tests__/integration/linear.integration.test.js +15 -0
  15. package/dist/__tests__/integration/sentry.integration.test.d.ts +1 -0
  16. package/dist/__tests__/integration/sentry.integration.test.js +20 -0
  17. package/dist/__tests__/integration/slack.integration.test.d.ts +1 -0
  18. package/dist/__tests__/integration/slack.integration.test.js +22 -0
  19. package/dist/__tests__/schema.test.d.ts +1 -0
  20. package/dist/__tests__/schema.test.js +239 -0
  21. package/dist/__tests__/skills-index.test.d.ts +1 -0
  22. package/dist/__tests__/skills-index.test.js +122 -0
  23. package/dist/__tests__/skills.test.d.ts +1 -0
  24. package/dist/__tests__/skills.test.js +296 -0
  25. package/dist/__tests__/studio.test.d.ts +1 -0
  26. package/dist/__tests__/studio.test.js +172 -0
  27. package/dist/__tests__/testing.test.d.ts +1 -0
  28. package/dist/__tests__/testing.test.js +224 -0
  29. package/dist/browser.d.ts +17 -0
  30. package/dist/browser.js +22 -0
  31. package/dist/claude.d.ts +48 -0
  32. package/dist/claude.js +293 -0
  33. package/dist/cli/check.d.ts +11 -0
  34. package/dist/cli/check.js +237 -0
  35. package/dist/cli/config-file.d.ts +12 -0
  36. package/dist/cli/config-file.js +208 -0
  37. package/dist/cli/config.d.ts +77 -0
  38. package/dist/cli/config.js +565 -0
  39. package/dist/cli/main.d.ts +10 -0
  40. package/dist/cli/main.js +744 -0
  41. package/dist/cli/output.d.ts +26 -0
  42. package/dist/cli/output.js +357 -0
  43. package/dist/cli/renderer.d.ts +33 -0
  44. package/dist/cli/renderer.js +423 -0
  45. package/dist/cli/renderer.test.d.ts +1 -0
  46. package/dist/cli/renderer.test.js +302 -0
  47. package/dist/cli/setup.d.ts +11 -0
  48. package/dist/cli/setup.js +310 -0
  49. package/dist/executor.d.ts +29 -0
  50. package/dist/executor.js +173 -0
  51. package/dist/executor.test.d.ts +1 -0
  52. package/dist/executor.test.js +314 -0
  53. package/dist/index.d.ts +37 -0
  54. package/dist/index.js +36 -0
  55. package/dist/mcp.d.ts +11 -0
  56. package/dist/mcp.js +183 -0
  57. package/dist/mcp.test.d.ts +1 -0
  58. package/dist/mcp.test.js +334 -0
  59. package/dist/schema.d.ts +318 -0
  60. package/dist/schema.js +207 -0
  61. package/dist/skills/betterstack.d.ts +7 -0
  62. package/dist/skills/betterstack.js +114 -0
  63. package/dist/skills/datadog.d.ts +7 -0
  64. package/dist/skills/datadog.js +107 -0
  65. package/dist/skills/github.d.ts +8 -0
  66. package/dist/skills/github.js +155 -0
  67. package/dist/skills/index.d.ts +68 -0
  68. package/dist/skills/index.js +134 -0
  69. package/dist/skills/linear.d.ts +7 -0
  70. package/dist/skills/linear.js +89 -0
  71. package/dist/skills/notification.d.ts +11 -0
  72. package/dist/skills/notification.js +142 -0
  73. package/dist/skills/sentry.d.ts +7 -0
  74. package/dist/skills/sentry.js +105 -0
  75. package/dist/skills/slack.d.ts +8 -0
  76. package/dist/skills/slack.js +115 -0
  77. package/dist/studio.d.ts +124 -0
  78. package/dist/studio.js +174 -0
  79. package/dist/testing.d.ts +88 -0
  80. package/dist/testing.js +253 -0
  81. package/dist/types.d.ts +144 -0
  82. package/dist/types.js +11 -0
  83. package/dist/workflow-builder.d.ts +45 -0
  84. package/dist/workflow-builder.js +120 -0
  85. package/dist/workflow-builder.test.d.ts +1 -0
  86. package/dist/workflow-builder.test.js +117 -0
  87. package/dist/workflows/implement.d.ts +11 -0
  88. package/dist/workflows/implement.js +83 -0
  89. package/dist/workflows/index.d.ts +2 -0
  90. package/dist/workflows/index.js +2 -0
  91. package/dist/workflows/triage.d.ts +18 -0
  92. package/dist/workflows/triage.js +108 -0
  93. package/package.json +83 -0
@@ -0,0 +1,318 @@
1
+ /**
2
+ * Workflow Schema & Validation
3
+ *
4
+ * Zod schemas that define the canonical Workflow spec.
5
+ * Use `validateWorkflow()` for structural validation (cycles,
6
+ * reachability, missing nodes). Use the Zod schemas for
7
+ * parsing untrusted input (JSON/YAML import, Studio editor).
8
+ */
9
+ import { z } from "zod";
10
+ export declare const jsonSchemaZ: z.ZodRecord<z.ZodString, z.ZodUnknown>;
11
+ export declare const configFieldZ: z.ZodObject<{
12
+ description: z.ZodString;
13
+ required: z.ZodOptional<z.ZodBoolean>;
14
+ env: z.ZodOptional<z.ZodString>;
15
+ }, "strip", z.ZodTypeAny, {
16
+ description: string;
17
+ required?: boolean | undefined;
18
+ env?: string | undefined;
19
+ }, {
20
+ description: string;
21
+ required?: boolean | undefined;
22
+ env?: string | undefined;
23
+ }>;
24
+ /**
25
+ * Zod schema for tool metadata (name, description, input_schema).
26
+ * Note: `handler` is intentionally omitted — Zod schemas validate
27
+ * serializable data (JSON import/export), not runtime function refs.
28
+ */
29
+ export declare const toolZ: z.ZodObject<{
30
+ name: z.ZodString;
31
+ description: z.ZodString;
32
+ input_schema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
33
+ }, "strip", z.ZodTypeAny, {
34
+ name: string;
35
+ description: string;
36
+ input_schema: Record<string, unknown>;
37
+ }, {
38
+ name: string;
39
+ description: string;
40
+ input_schema: Record<string, unknown>;
41
+ }>;
42
+ export declare const skillCategoryZ: z.ZodEnum<["git", "observability", "tasks", "notification", "general"]>;
43
+ export declare const skillZ: z.ZodObject<{
44
+ id: z.ZodString;
45
+ name: z.ZodString;
46
+ description: z.ZodString;
47
+ category: z.ZodEnum<["git", "observability", "tasks", "notification", "general"]>;
48
+ config: z.ZodRecord<z.ZodString, z.ZodObject<{
49
+ description: z.ZodString;
50
+ required: z.ZodOptional<z.ZodBoolean>;
51
+ env: z.ZodOptional<z.ZodString>;
52
+ }, "strip", z.ZodTypeAny, {
53
+ description: string;
54
+ required?: boolean | undefined;
55
+ env?: string | undefined;
56
+ }, {
57
+ description: string;
58
+ required?: boolean | undefined;
59
+ env?: string | undefined;
60
+ }>>;
61
+ tools: z.ZodArray<z.ZodObject<{
62
+ name: z.ZodString;
63
+ description: z.ZodString;
64
+ input_schema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
65
+ }, "strip", z.ZodTypeAny, {
66
+ name: string;
67
+ description: string;
68
+ input_schema: Record<string, unknown>;
69
+ }, {
70
+ name: string;
71
+ description: string;
72
+ input_schema: Record<string, unknown>;
73
+ }>, "many">;
74
+ }, "strip", z.ZodTypeAny, {
75
+ id: string;
76
+ name: string;
77
+ description: string;
78
+ category: "git" | "observability" | "tasks" | "notification" | "general";
79
+ config: Record<string, {
80
+ description: string;
81
+ required?: boolean | undefined;
82
+ env?: string | undefined;
83
+ }>;
84
+ tools: {
85
+ name: string;
86
+ description: string;
87
+ input_schema: Record<string, unknown>;
88
+ }[];
89
+ }, {
90
+ id: string;
91
+ name: string;
92
+ description: string;
93
+ category: "git" | "observability" | "tasks" | "notification" | "general";
94
+ config: Record<string, {
95
+ description: string;
96
+ required?: boolean | undefined;
97
+ env?: string | undefined;
98
+ }>;
99
+ tools: {
100
+ name: string;
101
+ description: string;
102
+ input_schema: Record<string, unknown>;
103
+ }[];
104
+ }>;
105
+ export declare const nodeZ: z.ZodObject<{
106
+ name: z.ZodString;
107
+ instruction: z.ZodString;
108
+ skills: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
109
+ output: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
110
+ }, "strip", z.ZodTypeAny, {
111
+ skills: string[];
112
+ name: string;
113
+ instruction: string;
114
+ output?: Record<string, unknown> | undefined;
115
+ }, {
116
+ name: string;
117
+ instruction: string;
118
+ skills?: string[] | undefined;
119
+ output?: Record<string, unknown> | undefined;
120
+ }>;
121
+ export declare const edgeZ: z.ZodObject<{
122
+ from: z.ZodString;
123
+ to: z.ZodString;
124
+ when: z.ZodOptional<z.ZodString>;
125
+ }, "strip", z.ZodTypeAny, {
126
+ from: string;
127
+ to: string;
128
+ when?: string | undefined;
129
+ }, {
130
+ from: string;
131
+ to: string;
132
+ when?: string | undefined;
133
+ }>;
134
+ export declare const workflowZ: z.ZodObject<{
135
+ id: z.ZodString;
136
+ name: z.ZodString;
137
+ description: z.ZodDefault<z.ZodString>;
138
+ nodes: z.ZodRecord<z.ZodString, z.ZodObject<{
139
+ name: z.ZodString;
140
+ instruction: z.ZodString;
141
+ skills: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
142
+ output: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
143
+ }, "strip", z.ZodTypeAny, {
144
+ skills: string[];
145
+ name: string;
146
+ instruction: string;
147
+ output?: Record<string, unknown> | undefined;
148
+ }, {
149
+ name: string;
150
+ instruction: string;
151
+ skills?: string[] | undefined;
152
+ output?: Record<string, unknown> | undefined;
153
+ }>>;
154
+ edges: z.ZodArray<z.ZodObject<{
155
+ from: z.ZodString;
156
+ to: z.ZodString;
157
+ when: z.ZodOptional<z.ZodString>;
158
+ }, "strip", z.ZodTypeAny, {
159
+ from: string;
160
+ to: string;
161
+ when?: string | undefined;
162
+ }, {
163
+ from: string;
164
+ to: string;
165
+ when?: string | undefined;
166
+ }>, "many">;
167
+ entry: z.ZodString;
168
+ }, "strip", z.ZodTypeAny, {
169
+ id: string;
170
+ name: string;
171
+ description: string;
172
+ nodes: Record<string, {
173
+ skills: string[];
174
+ name: string;
175
+ instruction: string;
176
+ output?: Record<string, unknown> | undefined;
177
+ }>;
178
+ edges: {
179
+ from: string;
180
+ to: string;
181
+ when?: string | undefined;
182
+ }[];
183
+ entry: string;
184
+ }, {
185
+ id: string;
186
+ name: string;
187
+ nodes: Record<string, {
188
+ name: string;
189
+ instruction: string;
190
+ skills?: string[] | undefined;
191
+ output?: Record<string, unknown> | undefined;
192
+ }>;
193
+ edges: {
194
+ from: string;
195
+ to: string;
196
+ when?: string | undefined;
197
+ }[];
198
+ entry: string;
199
+ description?: string | undefined;
200
+ }>;
201
+ /** Parse + validate a raw object as a Workflow. Throws on invalid input. */
202
+ export declare function parseWorkflow(raw: unknown): {
203
+ id: string;
204
+ name: string;
205
+ description: string;
206
+ nodes: Record<string, {
207
+ skills: string[];
208
+ name: string;
209
+ instruction: string;
210
+ output?: Record<string, unknown> | undefined;
211
+ }>;
212
+ edges: {
213
+ from: string;
214
+ to: string;
215
+ when?: string | undefined;
216
+ }[];
217
+ entry: string;
218
+ };
219
+ export interface WorkflowError {
220
+ code: "MISSING_ENTRY" | "UNKNOWN_EDGE_SOURCE" | "UNKNOWN_EDGE_TARGET" | "UNREACHABLE_NODE" | "UNKNOWN_SKILL" | "SELF_LOOP" | "NO_OUTGOING_EDGE";
221
+ message: string;
222
+ nodeId?: string;
223
+ }
224
+ /**
225
+ * Validate a workflow's graph structure.
226
+ *
227
+ * Checks:
228
+ * - Entry node exists
229
+ * - All edge sources and targets reference existing nodes
230
+ * - No self-loops
231
+ * - All nodes are reachable from entry
232
+ * - All non-terminal nodes have at least one outgoing edge
233
+ * - (optional) All referenced skills exist in the provided skill set
234
+ */
235
+ export declare function validateWorkflow(workflow: z.infer<typeof workflowZ>, knownSkills?: Set<string>): WorkflowError[];
236
+ /**
237
+ * Static JSON Schema for the Workflow type.
238
+ * Use this for external validation (YAML files, Studio import, CI checks).
239
+ */
240
+ export declare const workflowJsonSchema: {
241
+ readonly $schema: "https://json-schema.org/draft/2020-12/schema";
242
+ readonly $id: "https://sweny.ai/schemas/workflow.json";
243
+ readonly title: "SWEny Workflow";
244
+ readonly description: "A DAG workflow definition for skill-based orchestration";
245
+ readonly type: "object";
246
+ readonly required: readonly ["id", "name", "nodes", "edges", "entry"];
247
+ readonly additionalProperties: false;
248
+ readonly properties: {
249
+ readonly id: {
250
+ readonly type: "string";
251
+ readonly minLength: 1;
252
+ };
253
+ readonly name: {
254
+ readonly type: "string";
255
+ readonly minLength: 1;
256
+ };
257
+ readonly description: {
258
+ readonly type: "string";
259
+ };
260
+ readonly entry: {
261
+ readonly type: "string";
262
+ readonly minLength: 1;
263
+ readonly description: "ID of the entry node";
264
+ };
265
+ readonly nodes: {
266
+ readonly type: "object";
267
+ readonly additionalProperties: {
268
+ readonly type: "object";
269
+ readonly required: readonly ["name", "instruction"];
270
+ readonly additionalProperties: false;
271
+ readonly properties: {
272
+ readonly name: {
273
+ readonly type: "string";
274
+ readonly minLength: 1;
275
+ };
276
+ readonly instruction: {
277
+ readonly type: "string";
278
+ readonly minLength: 1;
279
+ readonly description: "What Claude should do at this node";
280
+ };
281
+ readonly skills: {
282
+ readonly type: "array";
283
+ readonly items: {
284
+ readonly type: "string";
285
+ };
286
+ readonly description: "Skill IDs available at this node";
287
+ };
288
+ readonly output: {
289
+ readonly type: "object";
290
+ readonly description: "Optional JSON Schema for structured output";
291
+ };
292
+ };
293
+ };
294
+ };
295
+ readonly edges: {
296
+ readonly type: "array";
297
+ readonly items: {
298
+ readonly type: "object";
299
+ readonly required: readonly ["from", "to"];
300
+ readonly additionalProperties: false;
301
+ readonly properties: {
302
+ readonly from: {
303
+ readonly type: "string";
304
+ readonly minLength: 1;
305
+ };
306
+ readonly to: {
307
+ readonly type: "string";
308
+ readonly minLength: 1;
309
+ };
310
+ readonly when: {
311
+ readonly type: "string";
312
+ readonly description: "Natural language condition — Claude evaluates at runtime";
313
+ };
314
+ };
315
+ };
316
+ };
317
+ };
318
+ };
package/dist/schema.js ADDED
@@ -0,0 +1,207 @@
1
+ /**
2
+ * Workflow Schema & Validation
3
+ *
4
+ * Zod schemas that define the canonical Workflow spec.
5
+ * Use `validateWorkflow()` for structural validation (cycles,
6
+ * reachability, missing nodes). Use the Zod schemas for
7
+ * parsing untrusted input (JSON/YAML import, Studio editor).
8
+ */
9
+ import { z } from "zod";
10
+ // ─── Zod Schemas ─────────────────────────────────────────────────
11
+ export const jsonSchemaZ = z.record(z.unknown());
12
+ export const configFieldZ = z.object({
13
+ description: z.string(),
14
+ required: z.boolean().optional(),
15
+ env: z.string().optional(),
16
+ });
17
+ /**
18
+ * Zod schema for tool metadata (name, description, input_schema).
19
+ * Note: `handler` is intentionally omitted — Zod schemas validate
20
+ * serializable data (JSON import/export), not runtime function refs.
21
+ */
22
+ export const toolZ = z.object({
23
+ name: z.string().min(1),
24
+ description: z.string(),
25
+ input_schema: jsonSchemaZ,
26
+ });
27
+ export const skillCategoryZ = z.enum(["git", "observability", "tasks", "notification", "general"]);
28
+ export const skillZ = z.object({
29
+ id: z.string().min(1),
30
+ name: z.string(),
31
+ description: z.string(),
32
+ category: skillCategoryZ,
33
+ config: z.record(configFieldZ),
34
+ tools: z.array(toolZ),
35
+ });
36
+ export const nodeZ = z.object({
37
+ name: z.string().min(1),
38
+ instruction: z.string().min(1),
39
+ skills: z.array(z.string()).default([]),
40
+ output: jsonSchemaZ.optional(),
41
+ });
42
+ export const edgeZ = z.object({
43
+ from: z.string().min(1),
44
+ to: z.string().min(1),
45
+ when: z.string().optional(),
46
+ });
47
+ export const workflowZ = z.object({
48
+ id: z.string().min(1),
49
+ name: z.string().min(1),
50
+ description: z.string().default(""),
51
+ nodes: z.record(nodeZ),
52
+ edges: z.array(edgeZ),
53
+ entry: z.string().min(1),
54
+ });
55
+ /** Parse + validate a raw object as a Workflow. Throws on invalid input. */
56
+ export function parseWorkflow(raw) {
57
+ return workflowZ.parse(raw);
58
+ }
59
+ /**
60
+ * Validate a workflow's graph structure.
61
+ *
62
+ * Checks:
63
+ * - Entry node exists
64
+ * - All edge sources and targets reference existing nodes
65
+ * - No self-loops
66
+ * - All nodes are reachable from entry
67
+ * - All non-terminal nodes have at least one outgoing edge
68
+ * - (optional) All referenced skills exist in the provided skill set
69
+ */
70
+ export function validateWorkflow(workflow, knownSkills) {
71
+ const errors = [];
72
+ const nodeIds = new Set(Object.keys(workflow.nodes));
73
+ // Entry must exist
74
+ if (!nodeIds.has(workflow.entry)) {
75
+ errors.push({
76
+ code: "MISSING_ENTRY",
77
+ message: `Entry node "${workflow.entry}" does not exist`,
78
+ });
79
+ }
80
+ // Edge targets must exist
81
+ for (const edge of workflow.edges) {
82
+ if (!nodeIds.has(edge.from)) {
83
+ errors.push({
84
+ code: "UNKNOWN_EDGE_SOURCE",
85
+ message: `Edge source "${edge.from}" does not exist`,
86
+ nodeId: edge.from,
87
+ });
88
+ }
89
+ if (!nodeIds.has(edge.to)) {
90
+ errors.push({
91
+ code: "UNKNOWN_EDGE_TARGET",
92
+ message: `Edge target "${edge.to}" does not exist`,
93
+ nodeId: edge.to,
94
+ });
95
+ }
96
+ if (edge.from === edge.to) {
97
+ errors.push({
98
+ code: "SELF_LOOP",
99
+ message: `Edge from "${edge.from}" to itself`,
100
+ nodeId: edge.from,
101
+ });
102
+ }
103
+ }
104
+ // Don't check reachability if there are structural errors
105
+ if (errors.length > 0)
106
+ return errors;
107
+ // Reachability: BFS from entry
108
+ const visited = new Set();
109
+ const queue = [workflow.entry];
110
+ while (queue.length > 0) {
111
+ const id = queue.shift();
112
+ if (visited.has(id))
113
+ continue;
114
+ visited.add(id);
115
+ for (const edge of workflow.edges) {
116
+ if (edge.from === id && !visited.has(edge.to)) {
117
+ queue.push(edge.to);
118
+ }
119
+ }
120
+ }
121
+ for (const nodeId of nodeIds) {
122
+ if (!visited.has(nodeId)) {
123
+ errors.push({
124
+ code: "UNREACHABLE_NODE",
125
+ message: `Node "${nodeId}" is unreachable from entry "${workflow.entry}"`,
126
+ nodeId,
127
+ });
128
+ }
129
+ }
130
+ // Non-terminal nodes must have outgoing edges
131
+ for (const nodeId of nodeIds) {
132
+ const hasOutgoing = workflow.edges.some((e) => e.from === nodeId);
133
+ if (!hasOutgoing && visited.has(nodeId)) {
134
+ // Terminal node — fine, no error. This is intentional.
135
+ // But if it has outgoing in the graph, it's fine too.
136
+ }
137
+ }
138
+ // Skill references
139
+ if (knownSkills) {
140
+ for (const [nodeId, node] of Object.entries(workflow.nodes)) {
141
+ for (const skillId of node.skills) {
142
+ if (!knownSkills.has(skillId)) {
143
+ errors.push({
144
+ code: "UNKNOWN_SKILL",
145
+ message: `Node "${nodeId}" references unknown skill "${skillId}"`,
146
+ nodeId,
147
+ });
148
+ }
149
+ }
150
+ }
151
+ }
152
+ return errors;
153
+ }
154
+ // ─── JSON Schema Export ──────────────────────────────────────────
155
+ /**
156
+ * Static JSON Schema for the Workflow type.
157
+ * Use this for external validation (YAML files, Studio import, CI checks).
158
+ */
159
+ export const workflowJsonSchema = {
160
+ $schema: "https://json-schema.org/draft/2020-12/schema",
161
+ $id: "https://sweny.ai/schemas/workflow.json",
162
+ title: "SWEny Workflow",
163
+ description: "A DAG workflow definition for skill-based orchestration",
164
+ type: "object",
165
+ required: ["id", "name", "nodes", "edges", "entry"],
166
+ additionalProperties: false,
167
+ properties: {
168
+ id: { type: "string", minLength: 1 },
169
+ name: { type: "string", minLength: 1 },
170
+ description: { type: "string" },
171
+ entry: { type: "string", minLength: 1, description: "ID of the entry node" },
172
+ nodes: {
173
+ type: "object",
174
+ additionalProperties: {
175
+ type: "object",
176
+ required: ["name", "instruction"],
177
+ additionalProperties: false,
178
+ properties: {
179
+ name: { type: "string", minLength: 1 },
180
+ instruction: { type: "string", minLength: 1, description: "What Claude should do at this node" },
181
+ skills: {
182
+ type: "array",
183
+ items: { type: "string" },
184
+ description: "Skill IDs available at this node",
185
+ },
186
+ output: {
187
+ type: "object",
188
+ description: "Optional JSON Schema for structured output",
189
+ },
190
+ },
191
+ },
192
+ },
193
+ edges: {
194
+ type: "array",
195
+ items: {
196
+ type: "object",
197
+ required: ["from", "to"],
198
+ additionalProperties: false,
199
+ properties: {
200
+ from: { type: "string", minLength: 1 },
201
+ to: { type: "string", minLength: 1 },
202
+ when: { type: "string", description: "Natural language condition — Claude evaluates at runtime" },
203
+ },
204
+ },
205
+ },
206
+ },
207
+ };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * BetterStack Skill
3
+ *
4
+ * Uptime monitoring (incidents, monitors) and log search via BetterStack APIs.
5
+ */
6
+ import type { Skill } from "../types.js";
7
+ export declare const betterstack: Skill;
@@ -0,0 +1,114 @@
1
+ /**
2
+ * BetterStack Skill
3
+ *
4
+ * Uptime monitoring (incidents, monitors) and log search via BetterStack APIs.
5
+ */
6
+ const UPTIME_BASE = "https://uptime.betterstack.com/api/v2";
7
+ async function uptimeApi(path, ctx, init) {
8
+ const res = await fetch(`${UPTIME_BASE}${path}`, {
9
+ ...init,
10
+ headers: {
11
+ Authorization: `Bearer ${ctx.config.BETTERSTACK_API_TOKEN}`,
12
+ "Content-Type": "application/json",
13
+ ...init?.headers,
14
+ },
15
+ signal: AbortSignal.timeout(30_000),
16
+ });
17
+ if (!res.ok)
18
+ throw new Error(`[BetterStack] API request failed (HTTP ${res.status}): ${await res.text()}`);
19
+ return res.json();
20
+ }
21
+ export const betterstack = {
22
+ id: "betterstack",
23
+ name: "BetterStack",
24
+ description: "Query incidents, monitors, and logs from BetterStack (Better Uptime + Logtail)",
25
+ category: "observability",
26
+ config: {
27
+ BETTERSTACK_API_TOKEN: {
28
+ description: "BetterStack API token (from Uptime > Settings > API)",
29
+ required: true,
30
+ env: "BETTERSTACK_API_TOKEN",
31
+ },
32
+ },
33
+ tools: [
34
+ {
35
+ name: "betterstack_list_incidents",
36
+ description: "List recent incidents from BetterStack Uptime. Returns ongoing and resolved incidents.",
37
+ input_schema: {
38
+ type: "object",
39
+ properties: {
40
+ from: { type: "string", description: "ISO 8601 start date (e.g. 2024-01-01T00:00:00Z)" },
41
+ to: { type: "string", description: "ISO 8601 end date" },
42
+ per_page: { type: "number", description: "Results per page (default 20, max 100)" },
43
+ },
44
+ },
45
+ handler: async (input, ctx) => {
46
+ const params = new URLSearchParams();
47
+ if (input.from)
48
+ params.set("from", input.from);
49
+ if (input.to)
50
+ params.set("to", input.to);
51
+ if (input.per_page)
52
+ params.set("per_page", String(input.per_page));
53
+ const qs = params.toString();
54
+ return uptimeApi(`/incidents${qs ? `?${qs}` : ""}`, ctx);
55
+ },
56
+ },
57
+ {
58
+ name: "betterstack_get_incident",
59
+ description: "Get detailed information about a specific incident including timeline.",
60
+ input_schema: {
61
+ type: "object",
62
+ properties: {
63
+ incident_id: { type: "string", description: "Incident ID" },
64
+ },
65
+ required: ["incident_id"],
66
+ },
67
+ handler: async (input, ctx) => {
68
+ return uptimeApi(`/incidents/${input.incident_id}`, ctx);
69
+ },
70
+ },
71
+ {
72
+ name: "betterstack_list_monitors",
73
+ description: "List all monitors (uptime checks) and their current status.",
74
+ input_schema: {
75
+ type: "object",
76
+ properties: {
77
+ per_page: { type: "number", description: "Results per page (default 20, max 100)" },
78
+ },
79
+ },
80
+ handler: async (input, ctx) => {
81
+ const params = new URLSearchParams();
82
+ if (input.per_page)
83
+ params.set("per_page", String(input.per_page));
84
+ const qs = params.toString();
85
+ return uptimeApi(`/monitors${qs ? `?${qs}` : ""}`, ctx);
86
+ },
87
+ },
88
+ {
89
+ name: "betterstack_get_monitor",
90
+ description: "Get details and recent status of a specific monitor.",
91
+ input_schema: {
92
+ type: "object",
93
+ properties: {
94
+ monitor_id: { type: "string", description: "Monitor ID" },
95
+ },
96
+ required: ["monitor_id"],
97
+ },
98
+ handler: async (input, ctx) => {
99
+ return uptimeApi(`/monitors/${input.monitor_id}`, ctx);
100
+ },
101
+ },
102
+ {
103
+ name: "betterstack_list_on_call",
104
+ description: "List current on-call calendars and who is on-call.",
105
+ input_schema: {
106
+ type: "object",
107
+ properties: {},
108
+ },
109
+ handler: async (_input, ctx) => {
110
+ return uptimeApi("/on-calls", ctx);
111
+ },
112
+ },
113
+ ],
114
+ };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Datadog Skill
3
+ *
4
+ * Replaces: observability/datadog.ts
5
+ */
6
+ import type { Skill } from "../types.js";
7
+ export declare const datadog: Skill;