@studio-foundation/api 0.3.0-beta.1

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 (188) hide show
  1. package/ARCHITECTURE.md +52 -0
  2. package/LICENSE +663 -0
  3. package/README.md +161 -0
  4. package/dist/api.d.ts +8 -0
  5. package/dist/api.d.ts.map +1 -0
  6. package/dist/api.js +6 -0
  7. package/dist/api.js.map +1 -0
  8. package/dist/bootstrap.d.ts +66 -0
  9. package/dist/bootstrap.d.ts.map +1 -0
  10. package/dist/bootstrap.js +193 -0
  11. package/dist/bootstrap.js.map +1 -0
  12. package/dist/event-bus.d.ts +16 -0
  13. package/dist/event-bus.d.ts.map +1 -0
  14. package/dist/event-bus.js +37 -0
  15. package/dist/event-bus.js.map +1 -0
  16. package/dist/index.d.ts +3 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +52 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/integration-runtime.d.ts +22 -0
  21. package/dist/integration-runtime.d.ts.map +1 -0
  22. package/dist/integration-runtime.js +150 -0
  23. package/dist/integration-runtime.js.map +1 -0
  24. package/dist/integration-store.d.ts +26 -0
  25. package/dist/integration-store.d.ts.map +1 -0
  26. package/dist/integration-store.js +80 -0
  27. package/dist/integration-store.js.map +1 -0
  28. package/dist/integrations/linear/failure-handler.d.ts +5 -0
  29. package/dist/integrations/linear/failure-handler.d.ts.map +1 -0
  30. package/dist/integrations/linear/failure-handler.js +73 -0
  31. package/dist/integrations/linear/failure-handler.js.map +1 -0
  32. package/dist/integrations/linear/webhook-handler.d.ts +6 -0
  33. package/dist/integrations/linear/webhook-handler.d.ts.map +1 -0
  34. package/dist/integrations/linear/webhook-handler.js +131 -0
  35. package/dist/integrations/linear/webhook-handler.js.map +1 -0
  36. package/dist/integrations/registry.d.ts +4 -0
  37. package/dist/integrations/registry.d.ts.map +1 -0
  38. package/dist/integrations/registry.js +9 -0
  39. package/dist/integrations/registry.js.map +1 -0
  40. package/dist/integrations/types.d.ts +33 -0
  41. package/dist/integrations/types.d.ts.map +1 -0
  42. package/dist/integrations/types.js +2 -0
  43. package/dist/integrations/types.js.map +1 -0
  44. package/dist/launcher.d.ts +45 -0
  45. package/dist/launcher.d.ts.map +1 -0
  46. package/dist/launcher.js +149 -0
  47. package/dist/launcher.js.map +1 -0
  48. package/dist/logger.d.ts +7 -0
  49. package/dist/logger.d.ts.map +1 -0
  50. package/dist/logger.js +37 -0
  51. package/dist/logger.js.map +1 -0
  52. package/dist/plans.d.ts +13 -0
  53. package/dist/plans.d.ts.map +1 -0
  54. package/dist/plans.js +33 -0
  55. package/dist/plans.js.map +1 -0
  56. package/dist/routes/agents.d.ts +6 -0
  57. package/dist/routes/agents.d.ts.map +1 -0
  58. package/dist/routes/agents.js +118 -0
  59. package/dist/routes/agents.js.map +1 -0
  60. package/dist/routes/config.d.ts +6 -0
  61. package/dist/routes/config.d.ts.map +1 -0
  62. package/dist/routes/config.js +129 -0
  63. package/dist/routes/config.js.map +1 -0
  64. package/dist/routes/contracts.d.ts +6 -0
  65. package/dist/routes/contracts.d.ts.map +1 -0
  66. package/dist/routes/contracts.js +188 -0
  67. package/dist/routes/contracts.js.map +1 -0
  68. package/dist/routes/pipelines.d.ts +6 -0
  69. package/dist/routes/pipelines.d.ts.map +1 -0
  70. package/dist/routes/pipelines.js +133 -0
  71. package/dist/routes/pipelines.js.map +1 -0
  72. package/dist/routes/projects.d.ts +6 -0
  73. package/dist/routes/projects.d.ts.map +1 -0
  74. package/dist/routes/projects.js +220 -0
  75. package/dist/routes/projects.js.map +1 -0
  76. package/dist/routes/runs.d.ts +6 -0
  77. package/dist/routes/runs.d.ts.map +1 -0
  78. package/dist/routes/runs.js +427 -0
  79. package/dist/routes/runs.js.map +1 -0
  80. package/dist/routes/skills.d.ts +6 -0
  81. package/dist/routes/skills.d.ts.map +1 -0
  82. package/dist/routes/skills.js +123 -0
  83. package/dist/routes/skills.js.map +1 -0
  84. package/dist/routes/tools.d.ts +6 -0
  85. package/dist/routes/tools.d.ts.map +1 -0
  86. package/dist/routes/tools.js +193 -0
  87. package/dist/routes/tools.js.map +1 -0
  88. package/dist/routes/users.d.ts +6 -0
  89. package/dist/routes/users.d.ts.map +1 -0
  90. package/dist/routes/users.js +152 -0
  91. package/dist/routes/users.js.map +1 -0
  92. package/dist/routes/validate.d.ts +6 -0
  93. package/dist/routes/validate.d.ts.map +1 -0
  94. package/dist/routes/validate.js +171 -0
  95. package/dist/routes/validate.js.map +1 -0
  96. package/dist/routes/webhooks.d.ts +8 -0
  97. package/dist/routes/webhooks.d.ts.map +1 -0
  98. package/dist/routes/webhooks.js +102 -0
  99. package/dist/routes/webhooks.js.map +1 -0
  100. package/dist/server.d.ts +46 -0
  101. package/dist/server.d.ts.map +1 -0
  102. package/dist/server.js +101 -0
  103. package/dist/server.js.map +1 -0
  104. package/dist/spawners/http-api-spawner.d.ts +10 -0
  105. package/dist/spawners/http-api-spawner.d.ts.map +1 -0
  106. package/dist/spawners/http-api-spawner.js +88 -0
  107. package/dist/spawners/http-api-spawner.js.map +1 -0
  108. package/dist/user-store-pg.d.ts +21 -0
  109. package/dist/user-store-pg.d.ts.map +1 -0
  110. package/dist/user-store-pg.js +97 -0
  111. package/dist/user-store-pg.js.map +1 -0
  112. package/dist/user-store.d.ts +29 -0
  113. package/dist/user-store.d.ts.map +1 -0
  114. package/dist/user-store.js +97 -0
  115. package/dist/user-store.js.map +1 -0
  116. package/dist/utils/repo-resolver.d.ts +3 -0
  117. package/dist/utils/repo-resolver.d.ts.map +1 -0
  118. package/dist/utils/repo-resolver.js +3 -0
  119. package/dist/utils/repo-resolver.js.map +1 -0
  120. package/dist/webhook-dispatcher.d.ts +13 -0
  121. package/dist/webhook-dispatcher.d.ts.map +1 -0
  122. package/dist/webhook-dispatcher.js +108 -0
  123. package/dist/webhook-dispatcher.js.map +1 -0
  124. package/dist/webhook-store.d.ts +31 -0
  125. package/dist/webhook-store.d.ts.map +1 -0
  126. package/dist/webhook-store.js +91 -0
  127. package/dist/webhook-store.js.map +1 -0
  128. package/package.json +59 -0
  129. package/src/.gitkeep +0 -0
  130. package/src/api.ts +8 -0
  131. package/src/bootstrap.ts +259 -0
  132. package/src/event-bus.ts +64 -0
  133. package/src/index.ts +58 -0
  134. package/src/integration-runtime.ts +180 -0
  135. package/src/integration-store.ts +125 -0
  136. package/src/integrations/linear/failure-handler.ts +93 -0
  137. package/src/integrations/linear/webhook-handler.ts +156 -0
  138. package/src/integrations/registry.ts +12 -0
  139. package/src/integrations/types.ts +37 -0
  140. package/src/launcher.ts +214 -0
  141. package/src/logger.ts +50 -0
  142. package/src/plans.ts +43 -0
  143. package/src/routes/agents.ts +131 -0
  144. package/src/routes/config.ts +154 -0
  145. package/src/routes/contracts.ts +205 -0
  146. package/src/routes/pipelines.ts +146 -0
  147. package/src/routes/projects.ts +237 -0
  148. package/src/routes/runs.ts +468 -0
  149. package/src/routes/skills.ts +136 -0
  150. package/src/routes/tools.ts +222 -0
  151. package/src/routes/users.ts +169 -0
  152. package/src/routes/validate.ts +196 -0
  153. package/src/routes/webhooks.ts +120 -0
  154. package/src/server.ts +155 -0
  155. package/src/spawners/http-api-spawner.ts +96 -0
  156. package/src/user-store-pg.ts +138 -0
  157. package/src/user-store.ts +125 -0
  158. package/src/utils/repo-resolver.ts +3 -0
  159. package/src/webhook-dispatcher.ts +142 -0
  160. package/src/webhook-store.ts +141 -0
  161. package/tests/agents.test.ts +164 -0
  162. package/tests/cancel.test.ts +120 -0
  163. package/tests/config.test.ts +196 -0
  164. package/tests/contracts.test.ts +302 -0
  165. package/tests/event-bus.test.ts +53 -0
  166. package/tests/http-api-spawner.test.ts +158 -0
  167. package/tests/integration-runtime.test.ts +199 -0
  168. package/tests/integration-store.test.ts +66 -0
  169. package/tests/integrations/linear/failure-handler.test.ts +113 -0
  170. package/tests/integrations/linear/webhook-handler.test.ts +191 -0
  171. package/tests/launcher.test.ts +380 -0
  172. package/tests/linear-webhook.test.ts +390 -0
  173. package/tests/pipelines.test.ts +166 -0
  174. package/tests/projects.test.ts +283 -0
  175. package/tests/runs.test.ts +379 -0
  176. package/tests/server.test.ts +208 -0
  177. package/tests/skills.test.ts +149 -0
  178. package/tests/sse.test.ts +129 -0
  179. package/tests/tools.test.ts +233 -0
  180. package/tests/user-store.test.ts +93 -0
  181. package/tests/users.test.ts +189 -0
  182. package/tests/utils/repo-resolver.test.ts +105 -0
  183. package/tests/validate.test.ts +233 -0
  184. package/tests/webhook-dispatcher.test.ts +214 -0
  185. package/tests/webhook-store.test.ts +98 -0
  186. package/tests/webhooks.test.ts +176 -0
  187. package/tsconfig.json +24 -0
  188. package/vitest.config.ts +7 -0
@@ -0,0 +1,427 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { randomUUID } from 'node:crypto';
4
+ import { resolveRepoPath } from '../utils/repo-resolver.js';
5
+ import { loadPipelineByName } from '@studio-foundation/engine';
6
+ async function replayJsonl(logPath, send) {
7
+ let content;
8
+ try {
9
+ content = await readFile(logPath, 'utf-8');
10
+ }
11
+ catch {
12
+ return; // log not yet written or missing
13
+ }
14
+ for (const line of content.split('\n')) {
15
+ const trimmed = line.trim();
16
+ if (!trimmed)
17
+ continue;
18
+ try {
19
+ const parsed = JSON.parse(trimmed);
20
+ if (parsed.event)
21
+ send(parsed.event, parsed);
22
+ }
23
+ catch {
24
+ // skip malformed lines
25
+ }
26
+ }
27
+ }
28
+ const stageRunSchema = {
29
+ type: 'object',
30
+ properties: {
31
+ id: { type: 'string' },
32
+ stage_name: { type: 'string' },
33
+ status: { type: 'string' },
34
+ started_at: { type: 'string' },
35
+ completed_at: { type: 'string' },
36
+ tasks: { type: 'array', items: { type: 'object', additionalProperties: true } },
37
+ },
38
+ };
39
+ const pipelineRunSchema = {
40
+ type: 'object',
41
+ properties: {
42
+ id: { type: 'string' },
43
+ pipeline_name: { type: 'string' },
44
+ status: { type: 'string', enum: ['pending', 'running', 'success', 'failed', 'rejected', 'skipped', 'cancelled'] },
45
+ started_at: { type: 'string' },
46
+ completed_at: { type: 'string' },
47
+ stages: { type: 'array', items: stageRunSchema },
48
+ parent_run_id: { type: 'string' },
49
+ },
50
+ };
51
+ const errorSchema = { type: 'object', properties: { error: { type: 'string' } } };
52
+ export async function runsRoutes(fastify, options) {
53
+ const { store, launcher } = options.deps;
54
+ // Shared cancel handler — used by both POST /runs/:id/cancel and DELETE /runs/:id
55
+ const handleCancel = async (id, reply) => {
56
+ const run = await store.getPipelineRun(id);
57
+ if (!run) {
58
+ return reply.status(404).send({ error: 'Run not found' });
59
+ }
60
+ if (run.status !== 'running') {
61
+ return reply.status(409).send({ error: `Run is not cancellable (status: ${run.status})` });
62
+ }
63
+ await launcher.cancel(id);
64
+ return reply.send({ run_id: id });
65
+ };
66
+ // POST /api/runs — fire-and-forget
67
+ fastify.post('/runs', {
68
+ schema: {
69
+ tags: ['runs'],
70
+ summary: 'Start a pipeline run',
71
+ body: {
72
+ type: 'object',
73
+ required: ['pipeline', 'input'],
74
+ properties: {
75
+ pipeline: { type: 'string' },
76
+ input: {
77
+ type: 'object',
78
+ description: 'Pipeline input. If input contains "repo_url", the repo is cloned before the run starts.',
79
+ },
80
+ provider: { type: 'string' },
81
+ },
82
+ },
83
+ response: {
84
+ 201: {
85
+ type: 'object',
86
+ properties: {
87
+ run_id: { type: 'string' },
88
+ status: { type: 'string' },
89
+ stream_url: { type: 'string' },
90
+ },
91
+ },
92
+ 400: errorSchema,
93
+ 429: errorSchema,
94
+ },
95
+ },
96
+ }, async (request, reply) => {
97
+ const { pipeline, provider } = request.body;
98
+ const runId = randomUUID();
99
+ const depth = parseInt(request.headers['x-studio-depth'] ?? '0', 10) || 0;
100
+ const parentRunId = request.headers['x-studio-parent-run-id'];
101
+ // Extract repo_url from input (like CLI does with --input-file), then strip it before passing to engine
102
+ const input = { ...request.body.input };
103
+ const inputRepoUrl = typeof input['repo_url'] === 'string' ? input['repo_url'] : undefined;
104
+ if (inputRepoUrl !== undefined)
105
+ delete input['repo_url'];
106
+ // Fall back to pipeline YAML repo.url when not provided in input (mirrors CLI behaviour)
107
+ let pipelineRepoUrl;
108
+ let pipelineRepoBranch;
109
+ try {
110
+ const pipelineDef = await loadPipelineByName(pipeline, join(options.deps.configsDir, 'pipelines'));
111
+ pipelineRepoUrl = pipelineDef.repo?.url;
112
+ pipelineRepoBranch = pipelineDef.repo?.branch;
113
+ }
114
+ catch {
115
+ // Pipeline not found — launcher.launch() will throw a proper error later
116
+ }
117
+ const repoUrl = inputRepoUrl ?? pipelineRepoUrl;
118
+ let repoPath;
119
+ try {
120
+ repoPath = await resolveRepoPath({
121
+ repoUrl,
122
+ rawProjectsDir: options.deps.projectsDir,
123
+ pipelineName: pipeline,
124
+ branch: pipelineRepoBranch,
125
+ });
126
+ }
127
+ catch (err) {
128
+ return reply.status(400).send({ error: err instanceof Error ? err.message : String(err) });
129
+ }
130
+ let run_id;
131
+ try {
132
+ const result = await launcher.launch({
133
+ runId,
134
+ pipeline,
135
+ input,
136
+ configsDir: options.deps.configsDir,
137
+ repoPath,
138
+ providerOverride: provider,
139
+ depth,
140
+ parentRunId,
141
+ userId: request.user?.id,
142
+ });
143
+ run_id = result.run_id;
144
+ }
145
+ catch (err) {
146
+ const code = err.code;
147
+ if (code === 'QUOTA_EXCEEDED') {
148
+ return reply.status(429).send({ error: err instanceof Error ? err.message : String(err) });
149
+ }
150
+ return reply.status(500).send({ error: err instanceof Error ? err.message : String(err) });
151
+ }
152
+ return reply.status(201).send({
153
+ run_id,
154
+ status: 'running',
155
+ stream_url: `/api/runs/${run_id}/stream`,
156
+ });
157
+ });
158
+ // GET /api/runs
159
+ fastify.get('/runs', {
160
+ schema: {
161
+ tags: ['runs'],
162
+ summary: 'List pipeline runs',
163
+ querystring: {
164
+ type: 'object',
165
+ properties: {
166
+ status: { type: 'string' },
167
+ limit: { type: 'string' },
168
+ },
169
+ },
170
+ response: {
171
+ 200: {
172
+ type: 'object',
173
+ properties: {
174
+ runs: { type: 'array', items: pipelineRunSchema },
175
+ },
176
+ },
177
+ },
178
+ },
179
+ }, async (request, reply) => {
180
+ const { status, limit } = request.query;
181
+ const runs = await store.listPipelineRuns({
182
+ status,
183
+ limit: limit ? parseInt(limit, 10) : undefined,
184
+ });
185
+ return reply.send({ runs });
186
+ });
187
+ // GET /api/runs/:id
188
+ fastify.get('/runs/:id', {
189
+ schema: {
190
+ tags: ['runs'],
191
+ summary: 'Get a run by ID',
192
+ params: {
193
+ type: 'object',
194
+ properties: { id: { type: 'string' } },
195
+ required: ['id'],
196
+ },
197
+ response: {
198
+ 200: pipelineRunSchema,
199
+ 404: errorSchema,
200
+ },
201
+ },
202
+ }, async (request, reply) => {
203
+ const run = await store.getPipelineRun(request.params.id);
204
+ if (!run) {
205
+ return reply.status(404).send({ error: 'Run not found' });
206
+ }
207
+ return reply.send(run);
208
+ });
209
+ // GET /api/runs/:id/logs
210
+ fastify.get('/runs/:id/logs', {
211
+ schema: {
212
+ tags: ['runs'],
213
+ summary: 'Get run logs (parsed JSONL or raw text)',
214
+ params: {
215
+ type: 'object',
216
+ properties: { id: { type: 'string' } },
217
+ required: ['id'],
218
+ },
219
+ querystring: {
220
+ type: 'object',
221
+ properties: { raw: { type: 'string', description: 'Set to "true" for raw JSONL text' } },
222
+ },
223
+ response: {
224
+ 200: {
225
+ type: 'object',
226
+ properties: {
227
+ run_id: { type: 'string' },
228
+ entries: {
229
+ type: 'array',
230
+ items: {
231
+ type: 'object',
232
+ properties: {
233
+ event: { type: 'string' },
234
+ timestamp: { type: 'string' },
235
+ data: { type: 'object', additionalProperties: true },
236
+ },
237
+ },
238
+ },
239
+ },
240
+ },
241
+ 404: errorSchema,
242
+ },
243
+ },
244
+ }, async (request, reply) => {
245
+ const { id } = request.params;
246
+ const isRaw = request.query.raw === 'true';
247
+ const run = await store.getPipelineRun(id);
248
+ if (!run) {
249
+ return reply.status(404).send({ error: 'Run not found' });
250
+ }
251
+ const logPath = await store.getLogPath(id);
252
+ if (!logPath) {
253
+ return reply.status(404).send({ error: 'Log not yet available' });
254
+ }
255
+ let content;
256
+ try {
257
+ content = await readFile(logPath, 'utf-8');
258
+ }
259
+ catch {
260
+ return reply.status(404).send({ error: 'Log file not found' });
261
+ }
262
+ if (isRaw) {
263
+ return reply.type('text/plain').send(content);
264
+ }
265
+ const entries = [];
266
+ for (const line of content.split('\n')) {
267
+ const trimmed = line.trim();
268
+ if (!trimmed)
269
+ continue;
270
+ try {
271
+ const parsed = JSON.parse(trimmed);
272
+ const { event, ts, ...data } = parsed;
273
+ if (typeof event !== 'string')
274
+ continue;
275
+ entries.push({ event, timestamp: typeof ts === 'string' ? ts : '', data });
276
+ }
277
+ catch {
278
+ // skip malformed lines
279
+ }
280
+ }
281
+ return reply.send({ run_id: id, entries });
282
+ });
283
+ // POST /api/runs/:id/cancel
284
+ fastify.post('/runs/:id/cancel', {
285
+ schema: {
286
+ tags: ['runs'],
287
+ summary: 'Cancel a running pipeline',
288
+ params: {
289
+ type: 'object',
290
+ properties: { id: { type: 'string' } },
291
+ required: ['id'],
292
+ },
293
+ response: {
294
+ 200: {
295
+ type: 'object',
296
+ properties: { run_id: { type: 'string' } },
297
+ },
298
+ 404: errorSchema,
299
+ 409: errorSchema,
300
+ },
301
+ },
302
+ }, async (request, reply) => {
303
+ return handleCancel(request.params.id, reply);
304
+ });
305
+ // DELETE /api/runs/:id — cancel a running pipeline (spec-aligned alias for POST /runs/:id/cancel)
306
+ fastify.delete('/runs/:id', {
307
+ schema: {
308
+ tags: ['runs'],
309
+ summary: 'Cancel a running pipeline (DELETE alias for POST /runs/:id/cancel)',
310
+ params: {
311
+ type: 'object',
312
+ properties: { id: { type: 'string' } },
313
+ required: ['id'],
314
+ },
315
+ response: {
316
+ 200: {
317
+ type: 'object',
318
+ properties: { run_id: { type: 'string' } },
319
+ },
320
+ 404: errorSchema,
321
+ 409: errorSchema,
322
+ },
323
+ },
324
+ }, async (request, reply) => {
325
+ return handleCancel(request.params.id, reply);
326
+ });
327
+ // GET /api/runs/:id/stream — SSE
328
+ fastify.get('/runs/:id/stream', {
329
+ schema: {
330
+ tags: ['runs'],
331
+ summary: 'Stream run events via SSE',
332
+ params: {
333
+ type: 'object',
334
+ properties: { id: { type: 'string' } },
335
+ required: ['id'],
336
+ },
337
+ querystring: {
338
+ type: 'object',
339
+ properties: { events: { type: 'string', description: 'Comma-separated event types to filter' } },
340
+ },
341
+ response: {
342
+ 404: errorSchema,
343
+ },
344
+ },
345
+ }, async (request, reply) => {
346
+ const { id } = request.params;
347
+ const filterParam = request.query.events;
348
+ const filter = filterParam ? filterParam.split(',') : null;
349
+ const run = await store.getPipelineRun(id);
350
+ if (!run) {
351
+ return reply.status(404).send({ error: 'Run not found' });
352
+ }
353
+ reply.raw.writeHead(200, {
354
+ 'Content-Type': 'text/event-stream',
355
+ 'Cache-Control': 'no-cache',
356
+ 'Connection': 'keep-alive',
357
+ });
358
+ const send = (type, data) => {
359
+ if (filter && !filter.includes(type))
360
+ return;
361
+ reply.raw.write(`event: ${type}\ndata: ${JSON.stringify(data)}\n\n`);
362
+ };
363
+ // Replay historical events from JSONL
364
+ const logPath = await store.getLogPath(id);
365
+ if (logPath)
366
+ await replayJsonl(logPath, send);
367
+ const TERMINAL = ['success', 'failed', 'rejected', 'cancelled'];
368
+ if (TERMINAL.includes(run.status)) {
369
+ reply.raw.end();
370
+ return reply;
371
+ }
372
+ // Subscribe to live events
373
+ const unsub = options.deps.launcher.subscribe(id, ({ type, data }) => send(type, data));
374
+ // Cleanup on client disconnect
375
+ request.raw.on('close', unsub);
376
+ // Keep connection open — Fastify won't auto-close since we used reply.raw
377
+ return reply;
378
+ });
379
+ // POST /api/runs/:id/retry — re-run with the same pipeline + input
380
+ fastify.post('/runs/:id/retry', {
381
+ schema: {
382
+ tags: ['runs'],
383
+ summary: 'Retry a run with the same parameters',
384
+ params: {
385
+ type: 'object',
386
+ properties: { id: { type: 'string' } },
387
+ required: ['id'],
388
+ },
389
+ response: {
390
+ 201: {
391
+ type: 'object',
392
+ properties: {
393
+ run_id: { type: 'string' },
394
+ status: { type: 'string' },
395
+ stream_url: { type: 'string' },
396
+ parent_run_id: { type: 'string' },
397
+ },
398
+ },
399
+ 404: errorSchema,
400
+ 422: errorSchema,
401
+ },
402
+ },
403
+ }, async (request, reply) => {
404
+ const { id } = request.params;
405
+ const originalRun = await store.getPipelineRun(id);
406
+ if (!originalRun) {
407
+ return reply.status(404).send({ error: 'Run not found' });
408
+ }
409
+ if (!originalRun.input) {
410
+ return reply.status(422).send({ error: 'Original run has no stored input — cannot retry' });
411
+ }
412
+ const { run_id: runId } = await launcher.launch({
413
+ runId: randomUUID(),
414
+ pipeline: originalRun.pipeline_name,
415
+ input: originalRun.input,
416
+ configsDir: options.deps.configsDir,
417
+ parentRunId: id,
418
+ });
419
+ return reply.status(201).send({
420
+ run_id: runId,
421
+ status: 'running',
422
+ stream_url: `/api/runs/${runId}/stream`,
423
+ parent_run_id: id,
424
+ });
425
+ });
426
+ }
427
+ //# sourceMappingURL=runs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runs.js","sourceRoot":"","sources":["../../src/routes/runs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+ import type { ServerDeps } from '../server.js';
3
+ export declare function skillsRoutes(fastify: FastifyInstance, options: {
4
+ deps: ServerDeps;
5
+ }): Promise<void>;
6
+ //# sourceMappingURL=skills.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/routes/skills.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,wBAAsB,YAAY,CAChC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GAC5B,OAAO,CAAC,IAAI,CAAC,CA+Hf"}
@@ -0,0 +1,123 @@
1
+ import { readdir, readFile, writeFile, unlink, mkdir } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ export async function skillsRoutes(fastify, options) {
4
+ const skillsDir = join(options.deps.configsDir, 'skills');
5
+ const errorSchema = { type: 'object', properties: { error: { type: 'string' } } };
6
+ // GET /api/skills
7
+ fastify.get('/skills', {
8
+ schema: {
9
+ tags: ['skills'],
10
+ summary: 'List all skill names',
11
+ response: {
12
+ 200: {
13
+ type: 'object',
14
+ properties: {
15
+ skills: { type: 'array', items: { type: 'string' } },
16
+ },
17
+ },
18
+ },
19
+ },
20
+ }, async (_request, reply) => {
21
+ let entries;
22
+ try {
23
+ entries = await readdir(skillsDir);
24
+ }
25
+ catch {
26
+ return reply.send({ skills: [] });
27
+ }
28
+ const skills = entries
29
+ .filter(f => f.endsWith('.skill.md'))
30
+ .map(f => f.slice(0, -'.skill.md'.length));
31
+ return reply.send({ skills });
32
+ });
33
+ // GET /api/skills/:name
34
+ fastify.get('/skills/:name', {
35
+ schema: {
36
+ tags: ['skills'],
37
+ summary: 'Get a skill by name',
38
+ params: {
39
+ type: 'object',
40
+ properties: { name: { type: 'string' } },
41
+ required: ['name'],
42
+ },
43
+ response: {
44
+ 200: {
45
+ type: 'object',
46
+ properties: {
47
+ name: { type: 'string' },
48
+ content: { type: 'string' },
49
+ },
50
+ },
51
+ 404: errorSchema,
52
+ },
53
+ },
54
+ }, async (request, reply) => {
55
+ const filePath = join(skillsDir, `${request.params.name}.skill.md`);
56
+ let content;
57
+ try {
58
+ content = await readFile(filePath, 'utf-8');
59
+ }
60
+ catch {
61
+ return reply.status(404).send({ error: 'Skill not found' });
62
+ }
63
+ return reply.send({ name: request.params.name, content });
64
+ });
65
+ // PUT /api/skills/:name
66
+ fastify.put('/skills/:name', {
67
+ schema: {
68
+ tags: ['skills'],
69
+ summary: 'Create or update a skill',
70
+ params: {
71
+ type: 'object',
72
+ properties: { name: { type: 'string' } },
73
+ required: ['name'],
74
+ },
75
+ body: { type: 'object' },
76
+ response: {
77
+ 200: {
78
+ type: 'object',
79
+ properties: {
80
+ name: { type: 'string' },
81
+ content: { type: 'string' },
82
+ },
83
+ },
84
+ 400: errorSchema,
85
+ },
86
+ },
87
+ }, async (request, reply) => {
88
+ const { content } = request.body;
89
+ if (typeof content !== 'string') {
90
+ return reply.status(400).send({ error: "Skill must have a 'content' field (string)" });
91
+ }
92
+ await mkdir(skillsDir, { recursive: true });
93
+ const filePath = join(skillsDir, `${request.params.name}.skill.md`);
94
+ await writeFile(filePath, content, 'utf-8');
95
+ return reply.send({ name: request.params.name, content });
96
+ });
97
+ // DELETE /api/skills/:name
98
+ fastify.delete('/skills/:name', {
99
+ schema: {
100
+ tags: ['skills'],
101
+ summary: 'Delete a skill',
102
+ params: {
103
+ type: 'object',
104
+ properties: { name: { type: 'string' } },
105
+ required: ['name'],
106
+ },
107
+ response: {
108
+ 204: { type: 'null', description: 'No content' },
109
+ 404: errorSchema,
110
+ },
111
+ },
112
+ }, async (request, reply) => {
113
+ const filePath = join(skillsDir, `${request.params.name}.skill.md`);
114
+ try {
115
+ await unlink(filePath);
116
+ }
117
+ catch {
118
+ return reply.status(404).send({ error: 'Skill not found' });
119
+ }
120
+ return reply.status(204).send();
121
+ });
122
+ }
123
+ //# sourceMappingURL=skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/routes/skills.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+ import type { ServerDeps } from '../server.js';
3
+ export declare function toolsRoutes(fastify: FastifyInstance, options: {
4
+ deps: ServerDeps;
5
+ }): Promise<void>;
6
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/routes/tools.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAoB/C,wBAAsB,WAAW,CAC/B,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GAC5B,OAAO,CAAC,IAAI,CAAC,CAkMf"}