skedyul 1.2.32 → 1.2.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -2429,13 +2429,6 @@ function getDefaultHeaders(options) {
2429
2429
  "Access-Control-Allow-Headers": options?.allowHeaders ?? "Content-Type"
2430
2430
  };
2431
2431
  }
2432
- function createResponse(statusCode, body, headers) {
2433
- return {
2434
- statusCode,
2435
- headers,
2436
- body: JSON.stringify(body)
2437
- };
2438
- }
2439
2432
  function getListeningPort(config) {
2440
2433
  const envPort = Number.parseInt(process.env.PORT ?? "", 10);
2441
2434
  if (!Number.isNaN(envPort)) {
@@ -2693,10 +2686,174 @@ function createCallToolHandler(registry, state, onMaxRequests) {
2693
2686
  }
2694
2687
 
2695
2688
  // src/server/dedicated.ts
2696
- var fs7 = __toESM(require("fs"));
2697
2689
  var import_http2 = __toESM(require("http"));
2698
2690
  var import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
2699
2691
 
2692
+ // src/server/startup-logger.ts
2693
+ function padEnd(str, length) {
2694
+ if (str.length >= length) {
2695
+ return str.slice(0, length);
2696
+ }
2697
+ return str + " ".repeat(length - str.length);
2698
+ }
2699
+ function printStartupLog(config, tools, port) {
2700
+ if (process.env.NODE_ENV === "test") {
2701
+ return;
2702
+ }
2703
+ const webhookRegistry = config.webhooks;
2704
+ const webhookCount = webhookRegistry ? Object.keys(webhookRegistry).length : 0;
2705
+ const webhookNames = webhookRegistry ? Object.keys(webhookRegistry) : [];
2706
+ const maxRequests = config.maxRequests ?? parseNumberEnv(process.env.MCP_MAX_REQUESTS) ?? null;
2707
+ const ttlExtendSeconds = config.ttlExtendSeconds ?? parseNumberEnv(process.env.MCP_TTL_EXTEND) ?? 3600;
2708
+ const executableId = process.env.SKEDYUL_EXECUTABLE_ID || "local";
2709
+ const divider = "\u2550".repeat(70);
2710
+ const thinDivider = "\u2500".repeat(70);
2711
+ console.log("");
2712
+ console.log(`\u2554${divider}\u2557`);
2713
+ console.log(`\u2551 \u{1F680} Skedyul MCP Server Starting \u2551`);
2714
+ console.log(`\u2560${divider}\u2563`);
2715
+ console.log(`\u2551 \u2551`);
2716
+ console.log(`\u2551 \u{1F4E6} Server: ${padEnd(config.name, 49)}\u2551`);
2717
+ console.log(`\u2551 \u{1F3F7}\uFE0F Version: ${padEnd(config.version ?? "N/A", 49)}\u2551`);
2718
+ console.log(`\u2551 \u26A1 Compute: ${padEnd(config.computeLayer ?? "serverless", 49)}\u2551`);
2719
+ if (port) {
2720
+ console.log(`\u2551 \u{1F310} Port: ${padEnd(String(port), 49)}\u2551`);
2721
+ }
2722
+ console.log(`\u2551 \u{1F511} Executable: ${padEnd(executableId, 49)}\u2551`);
2723
+ console.log(`\u2551 \u2551`);
2724
+ console.log(`\u255F${thinDivider}\u2562`);
2725
+ console.log(`\u2551 \u2551`);
2726
+ console.log(`\u2551 \u{1F527} Tools (${tools.length}): \u2551`);
2727
+ const maxToolsToShow = 10;
2728
+ const toolsToShow = tools.slice(0, maxToolsToShow);
2729
+ for (const tool of toolsToShow) {
2730
+ console.log(`\u2551 \u2022 ${padEnd(tool.name, 61)}\u2551`);
2731
+ }
2732
+ if (tools.length > maxToolsToShow) {
2733
+ console.log(`\u2551 ... and ${tools.length - maxToolsToShow} more \u2551`);
2734
+ }
2735
+ if (webhookCount > 0) {
2736
+ console.log(`\u2551 \u2551`);
2737
+ console.log(`\u2551 \u{1FA9D} Webhooks (${webhookCount}): \u2551`);
2738
+ const maxWebhooksToShow = 5;
2739
+ const webhooksToShow = webhookNames.slice(0, maxWebhooksToShow);
2740
+ for (const name of webhooksToShow) {
2741
+ console.log(`\u2551 \u2022 /webhooks/${padEnd(name, 51)}\u2551`);
2742
+ }
2743
+ if (webhookCount > maxWebhooksToShow) {
2744
+ console.log(`\u2551 ... and ${webhookCount - maxWebhooksToShow} more \u2551`);
2745
+ }
2746
+ }
2747
+ console.log(`\u2551 \u2551`);
2748
+ console.log(`\u255F${thinDivider}\u2562`);
2749
+ console.log(`\u2551 \u2551`);
2750
+ console.log(`\u2551 \u2699\uFE0F Configuration: \u2551`);
2751
+ console.log(`\u2551 Max Requests: ${padEnd(maxRequests !== null ? String(maxRequests) : "unlimited", 46)}\u2551`);
2752
+ console.log(`\u2551 TTL Extend: ${padEnd(`${ttlExtendSeconds}s`, 46)}\u2551`);
2753
+ console.log(`\u2551 \u2551`);
2754
+ console.log(`\u255F${thinDivider}\u2562`);
2755
+ console.log(`\u2551 \u2705 Ready at ${padEnd((/* @__PURE__ */ new Date()).toISOString(), 55)}\u2551`);
2756
+ console.log(`\u255A${divider}\u255D`);
2757
+ console.log("");
2758
+ }
2759
+
2760
+ // src/server/route-handlers/adapters.ts
2761
+ function fromLambdaEvent(event) {
2762
+ const path17 = event.path || event.rawPath || "/";
2763
+ const method = event.httpMethod || event.requestContext?.http?.method || "POST";
2764
+ const forwardedProto = event.headers?.["x-forwarded-proto"] ?? event.headers?.["X-Forwarded-Proto"];
2765
+ const protocol = forwardedProto ?? "https";
2766
+ const host = event.headers?.host ?? event.headers?.Host ?? "localhost";
2767
+ const queryString = event.queryStringParameters ? "?" + new URLSearchParams(
2768
+ event.queryStringParameters
2769
+ ).toString() : "";
2770
+ const url = `${protocol}://${host}${path17}${queryString}`;
2771
+ return {
2772
+ path: path17,
2773
+ method,
2774
+ headers: event.headers,
2775
+ query: event.queryStringParameters ?? {},
2776
+ body: event.body,
2777
+ url
2778
+ };
2779
+ }
2780
+ function toLambdaResponse(response, defaultHeaders) {
2781
+ return {
2782
+ statusCode: response.status,
2783
+ headers: {
2784
+ ...defaultHeaders,
2785
+ ...response.headers
2786
+ },
2787
+ body: response.body !== void 0 ? typeof response.body === "string" ? response.body : JSON.stringify(response.body) : ""
2788
+ };
2789
+ }
2790
+ function parseJsonBody(req, errorCode = -32700, errorMessage = "Parse error") {
2791
+ try {
2792
+ const data = req.body ? JSON.parse(req.body) : {};
2793
+ return { success: true, data };
2794
+ } catch {
2795
+ return {
2796
+ success: false,
2797
+ error: {
2798
+ status: 400,
2799
+ body: {
2800
+ error: {
2801
+ code: errorCode,
2802
+ message: errorMessage
2803
+ }
2804
+ }
2805
+ }
2806
+ };
2807
+ }
2808
+ }
2809
+ function parseJsonRpcBody(req) {
2810
+ try {
2811
+ const data = req.body ? JSON.parse(req.body) : {};
2812
+ return { success: true, data };
2813
+ } catch {
2814
+ return {
2815
+ success: false,
2816
+ error: {
2817
+ status: 400,
2818
+ body: {
2819
+ jsonrpc: "2.0",
2820
+ id: null,
2821
+ error: {
2822
+ code: -32700,
2823
+ message: "Parse error"
2824
+ }
2825
+ }
2826
+ }
2827
+ };
2828
+ }
2829
+ }
2830
+ function getHeader(req, name) {
2831
+ const value = req.headers[name.toLowerCase()] ?? req.headers[name];
2832
+ if (Array.isArray(value)) {
2833
+ return value[0];
2834
+ }
2835
+ return value;
2836
+ }
2837
+ function getContentType(req) {
2838
+ return getHeader(req, "content-type") ?? "";
2839
+ }
2840
+ function parseBodyByContentType(req) {
2841
+ const contentType = getContentType(req);
2842
+ const rawBody = req.body ?? "";
2843
+ if (contentType.includes("application/json")) {
2844
+ try {
2845
+ return rawBody ? JSON.parse(rawBody) : {};
2846
+ } catch {
2847
+ return rawBody;
2848
+ }
2849
+ }
2850
+ return rawBody;
2851
+ }
2852
+
2853
+ // src/server/route-handlers/handlers.ts
2854
+ var fs7 = __toESM(require("fs"));
2855
+ var path7 = __toESM(require("path"));
2856
+
2700
2857
  // src/server/core-api-handler.ts
2701
2858
  async function handleCoreMethod(method, params) {
2702
2859
  const service = coreApiService.getService();
@@ -2840,74 +2997,6 @@ async function handleCoreMethod(method, params) {
2840
2997
  };
2841
2998
  }
2842
2999
 
2843
- // src/server/startup-logger.ts
2844
- function padEnd(str, length) {
2845
- if (str.length >= length) {
2846
- return str.slice(0, length);
2847
- }
2848
- return str + " ".repeat(length - str.length);
2849
- }
2850
- function printStartupLog(config, tools, port) {
2851
- if (process.env.NODE_ENV === "test") {
2852
- return;
2853
- }
2854
- const webhookRegistry = config.webhooks;
2855
- const webhookCount = webhookRegistry ? Object.keys(webhookRegistry).length : 0;
2856
- const webhookNames = webhookRegistry ? Object.keys(webhookRegistry) : [];
2857
- const maxRequests = config.maxRequests ?? parseNumberEnv(process.env.MCP_MAX_REQUESTS) ?? null;
2858
- const ttlExtendSeconds = config.ttlExtendSeconds ?? parseNumberEnv(process.env.MCP_TTL_EXTEND) ?? 3600;
2859
- const executableId = process.env.SKEDYUL_EXECUTABLE_ID || "local";
2860
- const divider = "\u2550".repeat(70);
2861
- const thinDivider = "\u2500".repeat(70);
2862
- console.log("");
2863
- console.log(`\u2554${divider}\u2557`);
2864
- console.log(`\u2551 \u{1F680} Skedyul MCP Server Starting \u2551`);
2865
- console.log(`\u2560${divider}\u2563`);
2866
- console.log(`\u2551 \u2551`);
2867
- console.log(`\u2551 \u{1F4E6} Server: ${padEnd(config.name, 49)}\u2551`);
2868
- console.log(`\u2551 \u{1F3F7}\uFE0F Version: ${padEnd(config.version ?? "N/A", 49)}\u2551`);
2869
- console.log(`\u2551 \u26A1 Compute: ${padEnd(config.computeLayer ?? "serverless", 49)}\u2551`);
2870
- if (port) {
2871
- console.log(`\u2551 \u{1F310} Port: ${padEnd(String(port), 49)}\u2551`);
2872
- }
2873
- console.log(`\u2551 \u{1F511} Executable: ${padEnd(executableId, 49)}\u2551`);
2874
- console.log(`\u2551 \u2551`);
2875
- console.log(`\u255F${thinDivider}\u2562`);
2876
- console.log(`\u2551 \u2551`);
2877
- console.log(`\u2551 \u{1F527} Tools (${tools.length}): \u2551`);
2878
- const maxToolsToShow = 10;
2879
- const toolsToShow = tools.slice(0, maxToolsToShow);
2880
- for (const tool of toolsToShow) {
2881
- console.log(`\u2551 \u2022 ${padEnd(tool.name, 61)}\u2551`);
2882
- }
2883
- if (tools.length > maxToolsToShow) {
2884
- console.log(`\u2551 ... and ${tools.length - maxToolsToShow} more \u2551`);
2885
- }
2886
- if (webhookCount > 0) {
2887
- console.log(`\u2551 \u2551`);
2888
- console.log(`\u2551 \u{1FA9D} Webhooks (${webhookCount}): \u2551`);
2889
- const maxWebhooksToShow = 5;
2890
- const webhooksToShow = webhookNames.slice(0, maxWebhooksToShow);
2891
- for (const name of webhooksToShow) {
2892
- console.log(`\u2551 \u2022 /webhooks/${padEnd(name, 51)}\u2551`);
2893
- }
2894
- if (webhookCount > maxWebhooksToShow) {
2895
- console.log(`\u2551 ... and ${webhookCount - maxWebhooksToShow} more \u2551`);
2896
- }
2897
- }
2898
- console.log(`\u2551 \u2551`);
2899
- console.log(`\u255F${thinDivider}\u2562`);
2900
- console.log(`\u2551 \u2551`);
2901
- console.log(`\u2551 \u2699\uFE0F Configuration: \u2551`);
2902
- console.log(`\u2551 Max Requests: ${padEnd(maxRequests !== null ? String(maxRequests) : "unlimited", 46)}\u2551`);
2903
- console.log(`\u2551 TTL Extend: ${padEnd(`${ttlExtendSeconds}s`, 46)}\u2551`);
2904
- console.log(`\u2551 \u2551`);
2905
- console.log(`\u255F${thinDivider}\u2562`);
2906
- console.log(`\u2551 \u2705 Ready at ${padEnd((/* @__PURE__ */ new Date()).toISOString(), 55)}\u2551`);
2907
- console.log(`\u255A${divider}\u255D`);
2908
- console.log("");
2909
- }
2910
-
2911
3000
  // src/server/config-serializer.ts
2912
3001
  function serializeConfig(config) {
2913
3002
  const registry = config.tools;
@@ -3226,7 +3315,7 @@ async function handleOAuthCallback(parsedBody, hooks) {
3226
3315
  }
3227
3316
 
3228
3317
  // src/server/handlers/webhook-handler.ts
3229
- function parseWebhookRequest(parsedBody, method, url, path16, headers, query, rawBody, appIdHeader, appVersionIdHeader) {
3318
+ function parseWebhookRequest(parsedBody, method, url, path17, headers, query, rawBody, appIdHeader, appVersionIdHeader) {
3230
3319
  const isEnvelope = typeof parsedBody === "object" && parsedBody !== null && "env" in parsedBody && "request" in parsedBody && "context" in parsedBody;
3231
3320
  if (isEnvelope) {
3232
3321
  const envelope = parsedBody;
@@ -3280,7 +3369,7 @@ function parseWebhookRequest(parsedBody, method, url, path16, headers, query, ra
3280
3369
  const webhookRequest = {
3281
3370
  method,
3282
3371
  url,
3283
- path: path16,
3372
+ path: path17,
3284
3373
  headers,
3285
3374
  query,
3286
3375
  body: parsedBody,
@@ -3335,322 +3424,517 @@ function isMethodAllowed(webhookRegistry, handle, method) {
3335
3424
  const allowedMethods = webhookDef.methods ?? ["POST"];
3336
3425
  return allowedMethods.includes(method);
3337
3426
  }
3338
-
3339
- // src/server/dedicated.ts
3340
- var CONFIG_FILE_PATH = ".skedyul/config.json";
3427
+
3428
+ // src/server/route-handlers/handlers.ts
3429
+ function getConfigFilePath() {
3430
+ return process.env.LAMBDA_TASK_ROOT ? path7.join(process.env.LAMBDA_TASK_ROOT, ".skedyul", "config.json") : ".skedyul/config.json";
3431
+ }
3432
+ function handleHealthRoute(ctx) {
3433
+ return {
3434
+ status: 200,
3435
+ body: ctx.state.getHealthStatus()
3436
+ };
3437
+ }
3438
+ function handleConfigRoute(ctx) {
3439
+ const configFilePath = getConfigFilePath();
3440
+ try {
3441
+ console.log(`[/config] Checking for config file at: ${configFilePath}`);
3442
+ if (fs7.existsSync(configFilePath)) {
3443
+ const fileConfig = JSON.parse(fs7.readFileSync(configFilePath, "utf-8"));
3444
+ console.log(
3445
+ `[/config] Loaded config from file: tools=${fileConfig.tools?.length ?? 0}, webhooks=${fileConfig.webhooks?.length ?? 0}`
3446
+ );
3447
+ return { status: 200, body: fileConfig };
3448
+ }
3449
+ console.log("[/config] Config file not found, falling back to runtime serialization");
3450
+ } catch (err) {
3451
+ console.warn("[/config] Failed to read config file, falling back to runtime serialization:", err);
3452
+ }
3453
+ const serialized = serializeConfig(ctx.config);
3454
+ console.log(
3455
+ `[/config] Runtime serialization: tools=${serialized.tools?.length ?? 0}, webhooks=${serialized.webhooks?.length ?? 0}`
3456
+ );
3457
+ return { status: 200, body: serialized };
3458
+ }
3459
+ async function handleCoreRoute(req, ctx) {
3460
+ const parseResult = parseJsonBody(req);
3461
+ if (!parseResult.success) {
3462
+ return parseResult.error;
3463
+ }
3464
+ const coreBody = parseResult.data;
3465
+ if (!coreBody?.method) {
3466
+ return {
3467
+ status: 400,
3468
+ body: {
3469
+ error: {
3470
+ code: -32602,
3471
+ message: "Missing method"
3472
+ }
3473
+ }
3474
+ };
3475
+ }
3476
+ const result = await handleCoreMethod(coreBody.method, coreBody.params);
3477
+ return { status: result.status, body: result.payload };
3478
+ }
3479
+ async function handleCoreWebhookRoute(req, ctx) {
3480
+ const rawBody = req.body ?? "";
3481
+ let webhookBody;
3482
+ try {
3483
+ webhookBody = rawBody ? JSON.parse(rawBody) : {};
3484
+ } catch {
3485
+ return { status: 400, body: { status: "parse-error" } };
3486
+ }
3487
+ const coreWebhookRequest = {
3488
+ method: req.method,
3489
+ headers: req.headers,
3490
+ body: webhookBody,
3491
+ query: req.query,
3492
+ url: req.url,
3493
+ path: req.path,
3494
+ rawBody: rawBody ? Buffer.from(rawBody, "utf-8") : void 0
3495
+ };
3496
+ const webhookResponse = await coreApiService.dispatchWebhook(coreWebhookRequest);
3497
+ return {
3498
+ status: webhookResponse.status,
3499
+ body: webhookResponse.body ?? {}
3500
+ };
3501
+ }
3502
+ async function handleEstimateRoute(req, ctx) {
3503
+ const parseResult = parseJsonBody(req);
3504
+ if (!parseResult.success) {
3505
+ return parseResult.error;
3506
+ }
3507
+ const estimateBody = parseResult.data;
3508
+ try {
3509
+ const toolName = estimateBody.name;
3510
+ const toolArgs = estimateBody.inputs ?? {};
3511
+ let toolKey = null;
3512
+ let tool = null;
3513
+ for (const [key, t] of Object.entries(ctx.registry)) {
3514
+ if (t.name === toolName || key === toolName) {
3515
+ toolKey = key;
3516
+ tool = t;
3517
+ break;
3518
+ }
3519
+ }
3520
+ if (!tool || !toolKey) {
3521
+ return {
3522
+ status: 400,
3523
+ body: {
3524
+ error: {
3525
+ code: -32602,
3526
+ message: `Tool "${toolName}" not found`
3527
+ }
3528
+ }
3529
+ };
3530
+ }
3531
+ const inputSchema = getZodSchema3(tool.inputSchema);
3532
+ const validatedArgs = inputSchema ? inputSchema.parse(toolArgs) : toolArgs;
3533
+ const estimateResponse = await ctx.callTool(toolKey, {
3534
+ inputs: validatedArgs,
3535
+ estimate: true
3536
+ });
3537
+ return {
3538
+ status: 200,
3539
+ body: {
3540
+ billing: estimateResponse.billing ?? { credits: 0 }
3541
+ }
3542
+ };
3543
+ } catch (err) {
3544
+ return {
3545
+ status: 500,
3546
+ body: {
3547
+ error: {
3548
+ code: -32603,
3549
+ message: err instanceof Error ? err.message : String(err ?? "")
3550
+ }
3551
+ }
3552
+ };
3553
+ }
3554
+ }
3555
+ async function handleInstallRoute(req, ctx) {
3556
+ const parseResult = parseJsonBody(req);
3557
+ if (!parseResult.success) {
3558
+ return parseResult.error;
3559
+ }
3560
+ const result = await handleInstall(parseResult.data, ctx.config.hooks);
3561
+ return { status: result.status, body: result.body };
3562
+ }
3563
+ async function handleUninstallRoute(req, ctx) {
3564
+ const parseResult = parseJsonBody(req);
3565
+ if (!parseResult.success) {
3566
+ return parseResult.error;
3567
+ }
3568
+ const result = await handleUninstall(parseResult.data, ctx.config.hooks);
3569
+ return { status: result.status, body: result.body };
3570
+ }
3571
+ async function handleProvisionRoute(req, ctx) {
3572
+ const parseResult = parseJsonBody(req);
3573
+ if (!parseResult.success) {
3574
+ return parseResult.error;
3575
+ }
3576
+ const result = await handleProvision(parseResult.data, ctx.config.hooks);
3577
+ return { status: result.status, body: result.body };
3578
+ }
3579
+ async function handleOAuthCallbackRoute(req, ctx) {
3580
+ const parseResult = parseJsonBody(req);
3581
+ if (!parseResult.success) {
3582
+ console.error("[OAuth Callback] Failed to parse JSON body");
3583
+ return parseResult.error;
3584
+ }
3585
+ const result = await handleOAuthCallback(parseResult.data, ctx.config.hooks);
3586
+ return { status: result.status, body: result.body };
3587
+ }
3588
+ async function handleWebhookRoute(req, handle, ctx) {
3589
+ if (!ctx.webhookRegistry) {
3590
+ return { status: 404, body: { error: `Webhook handler '${handle}' not found` } };
3591
+ }
3592
+ if (!ctx.webhookRegistry[handle]) {
3593
+ return { status: 404, body: { error: `Webhook handler '${handle}' not found` } };
3594
+ }
3595
+ if (!isMethodAllowed(ctx.webhookRegistry, handle, req.method)) {
3596
+ return { status: 405, body: { error: `Method ${req.method} not allowed` } };
3597
+ }
3598
+ const rawBody = req.body ?? "";
3599
+ const parsedBody = parseBodyByContentType(req);
3600
+ const parseResult = parseWebhookRequest(
3601
+ parsedBody,
3602
+ req.method,
3603
+ req.url,
3604
+ req.path,
3605
+ req.headers,
3606
+ req.query,
3607
+ rawBody,
3608
+ getHeader(req, "x-skedyul-app-id"),
3609
+ getHeader(req, "x-skedyul-app-version-id")
3610
+ );
3611
+ if ("error" in parseResult) {
3612
+ return { status: 400, body: { error: parseResult.error } };
3613
+ }
3614
+ const result = await executeWebhookHandler(handle, ctx.webhookRegistry, parseResult);
3615
+ return {
3616
+ status: result.status,
3617
+ body: result.body,
3618
+ headers: result.headers
3619
+ };
3620
+ }
3621
+ async function handleMcpRoute(req, ctx) {
3622
+ const parseResult = parseJsonRpcBody(req);
3623
+ if (!parseResult.success) {
3624
+ return parseResult.error;
3625
+ }
3626
+ const body = parseResult.data;
3627
+ try {
3628
+ const { jsonrpc, id, method: rpcMethod, params } = body;
3629
+ if (jsonrpc !== "2.0") {
3630
+ return {
3631
+ status: 400,
3632
+ body: {
3633
+ jsonrpc: "2.0",
3634
+ id,
3635
+ error: {
3636
+ code: -32600,
3637
+ message: "Invalid Request"
3638
+ }
3639
+ }
3640
+ };
3641
+ }
3642
+ let result;
3643
+ if (rpcMethod === "tools/list") {
3644
+ result = { tools: ctx.tools };
3645
+ } else if (rpcMethod === "tools/call") {
3646
+ return handleMcpToolsCall(params, id, ctx);
3647
+ } else if (rpcMethod === "webhooks/list") {
3648
+ const webhooks = ctx.webhookRegistry ? Object.values(ctx.webhookRegistry).map((w) => ({
3649
+ name: w.name,
3650
+ description: w.description,
3651
+ methods: w.methods ?? ["POST"],
3652
+ type: w.type ?? "WEBHOOK"
3653
+ })) : [];
3654
+ result = { webhooks };
3655
+ } else {
3656
+ return {
3657
+ status: 200,
3658
+ body: {
3659
+ jsonrpc: "2.0",
3660
+ id,
3661
+ error: {
3662
+ code: -32601,
3663
+ message: `Method not found: ${rpcMethod}`
3664
+ }
3665
+ }
3666
+ };
3667
+ }
3668
+ return {
3669
+ status: 200,
3670
+ body: {
3671
+ jsonrpc: "2.0",
3672
+ id,
3673
+ result
3674
+ }
3675
+ };
3676
+ } catch (err) {
3677
+ return {
3678
+ status: 500,
3679
+ body: {
3680
+ jsonrpc: "2.0",
3681
+ id: body?.id ?? null,
3682
+ error: {
3683
+ code: -32603,
3684
+ message: err instanceof Error ? err.message : String(err ?? "")
3685
+ }
3686
+ }
3687
+ };
3688
+ }
3689
+ }
3690
+ async function handleMcpToolsCall(params, id, ctx) {
3691
+ const toolName = params?.name;
3692
+ const rawArgs = params?.arguments ?? {};
3693
+ console.log("[route-handlers /mcp] Received tools/call request:", JSON.stringify({
3694
+ toolName,
3695
+ hasArguments: !!params?.arguments,
3696
+ argumentKeys: rawArgs ? Object.keys(rawArgs) : [],
3697
+ hasEnv: "env" in rawArgs,
3698
+ envKeys: rawArgs.env ? Object.keys(rawArgs.env) : [],
3699
+ hasApiToken: !!rawArgs.env?.SKEDYUL_API_TOKEN
3700
+ }, null, 2));
3701
+ const hasSkedyulFormat = "inputs" in rawArgs || "env" in rawArgs || "context" in rawArgs || "invocation" in rawArgs;
3702
+ const toolInputs = hasSkedyulFormat ? rawArgs.inputs ?? {} : rawArgs;
3703
+ const toolContext = hasSkedyulFormat ? rawArgs.context : void 0;
3704
+ const toolEnv = hasSkedyulFormat ? rawArgs.env : void 0;
3705
+ const toolInvocation = hasSkedyulFormat ? rawArgs.invocation : void 0;
3706
+ console.log("[route-handlers /mcp] Extracted env:", JSON.stringify({
3707
+ hasSkedyulFormat,
3708
+ hasToolEnv: !!toolEnv,
3709
+ toolEnvKeys: toolEnv ? Object.keys(toolEnv) : [],
3710
+ hasApiToken: toolEnv?.SKEDYUL_API_TOKEN ? `yes (${toolEnv.SKEDYUL_API_TOKEN.length} chars)` : "no"
3711
+ }, null, 2));
3712
+ let toolKey = null;
3713
+ let tool = null;
3714
+ for (const [key, t] of Object.entries(ctx.registry)) {
3715
+ if (t.name === toolName || key === toolName) {
3716
+ toolKey = key;
3717
+ tool = t;
3718
+ break;
3719
+ }
3720
+ }
3721
+ if (!tool || !toolKey) {
3722
+ return {
3723
+ status: 200,
3724
+ body: {
3725
+ jsonrpc: "2.0",
3726
+ id,
3727
+ error: {
3728
+ code: -32602,
3729
+ message: `Tool "${toolName}" not found`
3730
+ }
3731
+ }
3732
+ };
3733
+ }
3734
+ try {
3735
+ const inputSchema = getZodSchema3(tool.inputSchema);
3736
+ const outputSchema = getZodSchema3(tool.outputSchema);
3737
+ const hasOutputSchema = Boolean(outputSchema);
3738
+ const validatedInputs = inputSchema ? inputSchema.parse(toolInputs) : toolInputs;
3739
+ const toolResult = await ctx.callTool(toolKey, {
3740
+ inputs: validatedInputs,
3741
+ context: toolContext,
3742
+ env: toolEnv,
3743
+ invocation: toolInvocation
3744
+ });
3745
+ let result;
3746
+ if (toolResult.error) {
3747
+ const errorOutput = { error: toolResult.error };
3748
+ result = {
3749
+ content: [{ type: "text", text: JSON.stringify(errorOutput) }],
3750
+ structuredContent: hasOutputSchema ? void 0 : errorOutput,
3751
+ isError: true,
3752
+ billing: toolResult.billing
3753
+ };
3754
+ } else {
3755
+ const outputData = toolResult.output;
3756
+ let structuredContent;
3757
+ if (outputData) {
3758
+ structuredContent = { ...outputData, __effect: toolResult.effect };
3759
+ } else if (toolResult.effect) {
3760
+ structuredContent = { __effect: toolResult.effect };
3761
+ } else if (hasOutputSchema) {
3762
+ structuredContent = {};
3763
+ }
3764
+ result = {
3765
+ content: [{ type: "text", text: JSON.stringify(toolResult.output) }],
3766
+ structuredContent,
3767
+ billing: toolResult.billing
3768
+ };
3769
+ }
3770
+ return {
3771
+ status: 200,
3772
+ body: {
3773
+ jsonrpc: "2.0",
3774
+ id,
3775
+ result
3776
+ }
3777
+ };
3778
+ } catch (validationError) {
3779
+ return {
3780
+ status: 200,
3781
+ body: {
3782
+ jsonrpc: "2.0",
3783
+ id,
3784
+ error: {
3785
+ code: -32602,
3786
+ message: validationError instanceof Error ? validationError.message : "Invalid arguments"
3787
+ }
3788
+ }
3789
+ };
3790
+ }
3791
+ }
3792
+ function createNotFoundResponse() {
3793
+ return {
3794
+ status: 404,
3795
+ body: {
3796
+ jsonrpc: "2.0",
3797
+ id: null,
3798
+ error: {
3799
+ code: -32601,
3800
+ message: "Not Found"
3801
+ }
3802
+ }
3803
+ };
3804
+ }
3805
+ function createOptionsResponse() {
3806
+ return {
3807
+ status: 200,
3808
+ body: { message: "OK" }
3809
+ };
3810
+ }
3811
+ function createErrorResponse(err) {
3812
+ return {
3813
+ status: 500,
3814
+ body: {
3815
+ jsonrpc: "2.0",
3816
+ id: null,
3817
+ error: {
3818
+ code: -32603,
3819
+ message: err instanceof Error ? err.message : String(err ?? "")
3820
+ }
3821
+ }
3822
+ };
3823
+ }
3824
+
3825
+ // src/server/route-handlers/router.ts
3826
+ async function routeRequest(req, ctx) {
3827
+ try {
3828
+ if (req.method === "OPTIONS") {
3829
+ return createOptionsResponse();
3830
+ }
3831
+ if (req.path.startsWith("/webhooks/") && ctx.webhookRegistry) {
3832
+ const handle = req.path.slice("/webhooks/".length);
3833
+ return handleWebhookRoute(req, handle, ctx);
3834
+ }
3835
+ if (req.path === "/core" && req.method === "POST") {
3836
+ return handleCoreRoute(req, ctx);
3837
+ }
3838
+ if (req.path === "/core/webhook" && req.method === "POST") {
3839
+ return handleCoreWebhookRoute(req, ctx);
3840
+ }
3841
+ if (req.path === "/estimate" && req.method === "POST") {
3842
+ return handleEstimateRoute(req, ctx);
3843
+ }
3844
+ if (req.path === "/install" && req.method === "POST") {
3845
+ return handleInstallRoute(req, ctx);
3846
+ }
3847
+ if (req.path === "/uninstall" && req.method === "POST") {
3848
+ return handleUninstallRoute(req, ctx);
3849
+ }
3850
+ if (req.path === "/provision" && req.method === "POST") {
3851
+ return handleProvisionRoute(req, ctx);
3852
+ }
3853
+ if (req.path === "/oauth_callback" && req.method === "POST") {
3854
+ return handleOAuthCallbackRoute(req, ctx);
3855
+ }
3856
+ if (req.path === "/health" && req.method === "GET") {
3857
+ return handleHealthRoute(ctx);
3858
+ }
3859
+ if (req.path === "/config" && req.method === "GET") {
3860
+ return handleConfigRoute(ctx);
3861
+ }
3862
+ if (req.path === "/mcp" && req.method === "POST") {
3863
+ return handleMcpRoute(req, ctx);
3864
+ }
3865
+ return createNotFoundResponse();
3866
+ } catch (err) {
3867
+ return createErrorResponse(err);
3868
+ }
3869
+ }
3870
+
3871
+ // src/server/dedicated.ts
3872
+ function fromHttpRequest(req, url, rawBody) {
3873
+ return {
3874
+ path: url.pathname,
3875
+ method: req.method ?? "GET",
3876
+ headers: req.headers,
3877
+ query: Object.fromEntries(url.searchParams.entries()),
3878
+ body: rawBody,
3879
+ url: url.toString()
3880
+ };
3881
+ }
3882
+ function sendUnifiedResponse(res, response, defaultHeaders) {
3883
+ const headers = {
3884
+ ...defaultHeaders,
3885
+ ...response.headers
3886
+ };
3887
+ if (!headers["Content-Type"] && !headers["content-type"]) {
3888
+ headers["Content-Type"] = "application/json";
3889
+ }
3890
+ res.writeHead(response.status, headers);
3891
+ if (response.body !== void 0) {
3892
+ if (typeof response.body === "string") {
3893
+ res.end(response.body);
3894
+ } else {
3895
+ res.end(JSON.stringify(response.body));
3896
+ }
3897
+ } else {
3898
+ res.end();
3899
+ }
3900
+ }
3341
3901
  function createDedicatedServerInstance(config, tools, callTool, state, mcpServer) {
3342
3902
  const port = getListeningPort(config);
3903
+ const defaultHeaders = getDefaultHeaders(config.cors);
3343
3904
  const registry = config.tools;
3344
3905
  const webhookRegistry = config.webhooks;
3906
+ const ctx = {
3907
+ config,
3908
+ tools,
3909
+ registry,
3910
+ webhookRegistry,
3911
+ callTool,
3912
+ state,
3913
+ mcpServer,
3914
+ defaultHeaders
3915
+ };
3345
3916
  const httpServer = import_http2.default.createServer(
3346
3917
  async (req, res) => {
3347
- function sendCoreResult(result) {
3348
- sendJSON(res, result.status, result.payload);
3349
- }
3350
3918
  try {
3351
3919
  const url = new URL(
3352
3920
  req.url || "/",
3353
3921
  `http://${req.headers.host || "localhost"}`
3354
3922
  );
3355
3923
  const pathname = url.pathname;
3356
- if (pathname === "/health" && req.method === "GET") {
3357
- sendJSON(res, 200, state.getHealthStatus());
3358
- return;
3359
- }
3360
- if (pathname === "/config" && req.method === "GET") {
3361
- try {
3362
- if (fs7.existsSync(CONFIG_FILE_PATH)) {
3363
- const fileConfig = JSON.parse(fs7.readFileSync(CONFIG_FILE_PATH, "utf-8"));
3364
- sendJSON(res, 200, fileConfig);
3365
- return;
3366
- }
3367
- } catch (err) {
3368
- console.warn("[/config] Failed to read config file, falling back to runtime serialization:", err);
3369
- }
3370
- sendJSON(res, 200, serializeConfig(config));
3371
- return;
3372
- }
3373
- if (pathname.startsWith("/webhooks/") && webhookRegistry) {
3374
- const handle = pathname.slice("/webhooks/".length);
3375
- if (!webhookRegistry[handle]) {
3376
- sendJSON(res, 404, { error: `Webhook handler '${handle}' not found` });
3377
- return;
3378
- }
3379
- if (!isMethodAllowed(webhookRegistry, handle, req.method ?? "POST")) {
3380
- sendJSON(res, 405, { error: `Method ${req.method} not allowed` });
3381
- return;
3382
- }
3383
- let rawBody;
3384
- try {
3385
- rawBody = await readRawRequestBody(req);
3386
- } catch {
3387
- sendJSON(res, 400, { error: "Failed to read request body" });
3388
- return;
3389
- }
3390
- let parsedBody;
3391
- const contentType = req.headers["content-type"] ?? "";
3392
- if (contentType.includes("application/json")) {
3393
- try {
3394
- parsedBody = rawBody ? JSON.parse(rawBody) : {};
3395
- } catch {
3396
- parsedBody = rawBody;
3397
- }
3398
- } else {
3399
- parsedBody = rawBody;
3400
- }
3401
- const parseResult = parseWebhookRequest(
3402
- parsedBody,
3403
- req.method ?? "POST",
3404
- url.toString(),
3405
- pathname,
3406
- req.headers,
3407
- Object.fromEntries(url.searchParams.entries()),
3408
- rawBody,
3409
- req.headers["x-skedyul-app-id"],
3410
- req.headers["x-skedyul-app-version-id"]
3411
- );
3412
- if ("error" in parseResult) {
3413
- sendJSON(res, 400, { error: parseResult.error });
3414
- return;
3415
- }
3416
- const result = await executeWebhookHandler(handle, webhookRegistry, parseResult);
3417
- const responseHeaders = {
3418
- ...result.headers
3419
- };
3420
- if (!responseHeaders["Content-Type"] && !responseHeaders["content-type"]) {
3421
- responseHeaders["Content-Type"] = "application/json";
3422
- }
3423
- res.writeHead(result.status, responseHeaders);
3424
- if (result.body !== void 0) {
3425
- if (typeof result.body === "string") {
3426
- res.end(result.body);
3427
- } else {
3428
- res.end(JSON.stringify(result.body));
3429
- }
3430
- } else {
3431
- res.end();
3432
- }
3433
- return;
3434
- }
3435
- if (pathname === "/estimate" && req.method === "POST") {
3436
- let estimateBody;
3437
- try {
3438
- estimateBody = await parseJSONBody(req);
3439
- } catch {
3440
- sendJSON(res, 400, {
3441
- error: {
3442
- code: -32700,
3443
- message: "Parse error"
3444
- }
3445
- });
3446
- return;
3447
- }
3448
- try {
3449
- const estimateResponse = await callTool(estimateBody.name, {
3450
- inputs: estimateBody.inputs,
3451
- estimate: true
3452
- });
3453
- sendJSON(res, 200, {
3454
- billing: estimateResponse.billing ?? { credits: 0 }
3455
- });
3456
- } catch (err) {
3457
- sendJSON(res, 500, {
3458
- error: {
3459
- code: -32603,
3460
- message: err instanceof Error ? err.message : String(err ?? "")
3461
- }
3462
- });
3463
- }
3464
- return;
3465
- }
3466
- if (pathname === "/oauth_callback" && req.method === "POST") {
3467
- let parsedBody;
3468
- try {
3469
- parsedBody = await parseJSONBody(req);
3470
- } catch (err) {
3471
- console.error("[OAuth Callback] Failed to parse JSON body:", err);
3472
- sendJSON(res, 400, {
3473
- error: { code: -32700, message: "Parse error" }
3474
- });
3475
- return;
3476
- }
3477
- const result = await handleOAuthCallback(parsedBody, config.hooks);
3478
- sendJSON(res, result.status, result.body);
3479
- return;
3480
- }
3481
- if (pathname === "/install" && req.method === "POST") {
3482
- let installBody;
3483
- try {
3484
- installBody = await parseJSONBody(req);
3485
- } catch {
3486
- sendJSON(res, 400, {
3487
- error: { code: -32700, message: "Parse error" }
3488
- });
3489
- return;
3490
- }
3491
- const result = await handleInstall(installBody, config.hooks);
3492
- sendJSON(res, result.status, result.body);
3493
- return;
3494
- }
3495
- if (pathname === "/uninstall" && req.method === "POST") {
3496
- let uninstallBody;
3497
- try {
3498
- uninstallBody = await parseJSONBody(req);
3499
- } catch {
3500
- sendJSON(res, 400, {
3501
- error: { code: -32700, message: "Parse error" }
3502
- });
3503
- return;
3504
- }
3505
- const result = await handleUninstall(uninstallBody, config.hooks);
3506
- sendJSON(res, result.status, result.body);
3507
- return;
3508
- }
3509
- if (pathname === "/provision" && req.method === "POST") {
3510
- let provisionBody;
3511
- try {
3512
- provisionBody = await parseJSONBody(req);
3513
- } catch {
3514
- sendJSON(res, 400, {
3515
- error: { code: -32700, message: "Parse error" }
3516
- });
3517
- return;
3518
- }
3519
- const result = await handleProvision(provisionBody, config.hooks);
3520
- sendJSON(res, result.status, result.body);
3521
- return;
3522
- }
3523
- if (pathname === "/core" && req.method === "POST") {
3524
- let coreBody;
3525
- try {
3526
- coreBody = await parseJSONBody(req);
3527
- } catch {
3528
- sendJSON(res, 400, {
3529
- error: {
3530
- code: -32700,
3531
- message: "Parse error"
3532
- }
3533
- });
3534
- return;
3535
- }
3536
- if (!coreBody?.method) {
3537
- sendJSON(res, 400, {
3538
- error: {
3539
- code: -32602,
3540
- message: "Missing method"
3541
- }
3542
- });
3543
- return;
3544
- }
3545
- const method = coreBody.method;
3546
- const result = await handleCoreMethod(method, coreBody.params);
3547
- sendCoreResult(result);
3548
- return;
3549
- }
3550
- if (pathname === "/core/webhook" && req.method === "POST") {
3551
- let rawWebhookBody;
3552
- try {
3553
- rawWebhookBody = await readRawRequestBody(req);
3554
- } catch {
3555
- sendJSON(res, 400, { status: "parse-error" });
3556
- return;
3557
- }
3558
- let webhookBody;
3559
- try {
3560
- webhookBody = rawWebhookBody ? JSON.parse(rawWebhookBody) : {};
3561
- } catch {
3562
- sendJSON(res, 400, { status: "parse-error" });
3563
- return;
3564
- }
3565
- const normalizedHeaders = Object.fromEntries(
3566
- Object.entries(req.headers).map(([key, value]) => [
3567
- key,
3568
- typeof value === "string" ? value : value?.[0] ?? ""
3569
- ])
3570
- );
3571
- const coreWebhookRequest = {
3572
- method: req.method ?? "POST",
3573
- headers: normalizedHeaders,
3574
- body: webhookBody,
3575
- query: Object.fromEntries(url.searchParams.entries()),
3576
- url: url.toString(),
3577
- path: url.pathname,
3578
- rawBody: rawWebhookBody ? Buffer.from(rawWebhookBody, "utf-8") : void 0
3579
- };
3580
- const webhookResponse = await coreApiService.dispatchWebhook(
3581
- coreWebhookRequest
3582
- );
3583
- res.writeHead(webhookResponse.status, {
3584
- "Content-Type": "application/json"
3585
- });
3586
- res.end(JSON.stringify(webhookResponse.body ?? {}));
3924
+ if (pathname === "/mcp" && req.method === "POST") {
3925
+ await handleMcpWithSdkTransport(req, res, url, ctx, mcpServer);
3587
3926
  return;
3588
3927
  }
3589
- if (pathname === "/mcp" && req.method === "POST") {
3590
- try {
3591
- const body = await parseJSONBody(req);
3592
- if (body?.method === "tools/call") {
3593
- console.log("[dedicated.ts /mcp] Received tools/call request:", JSON.stringify({
3594
- method: body.method,
3595
- toolName: body.params?.name,
3596
- hasArguments: !!body.params?.arguments,
3597
- argumentKeys: body.params?.arguments ? Object.keys(body.params.arguments) : [],
3598
- hasEnv: !!body.params?.arguments?.env,
3599
- envKeys: body.params?.arguments?.env ? Object.keys(body.params.arguments.env) : [],
3600
- hasApiToken: !!body.params?.arguments?.env?.SKEDYUL_API_TOKEN
3601
- }, null, 2));
3602
- }
3603
- if (body?.method === "tools/list") {
3604
- sendJSON(res, 200, {
3605
- jsonrpc: "2.0",
3606
- id: body.id ?? null,
3607
- result: { tools }
3608
- });
3609
- return;
3610
- }
3611
- if (body?.method === "webhooks/list") {
3612
- const webhooks = webhookRegistry ? Object.values(webhookRegistry).map((w) => ({
3613
- name: w.name,
3614
- description: w.description,
3615
- methods: w.methods ?? ["POST"],
3616
- type: w.type ?? "WEBHOOK"
3617
- })) : [];
3618
- sendJSON(res, 200, {
3619
- jsonrpc: "2.0",
3620
- id: body.id ?? null,
3621
- result: { webhooks }
3622
- });
3623
- return;
3624
- }
3625
- const transport = new import_streamableHttp.StreamableHTTPServerTransport({
3626
- sessionIdGenerator: void 0,
3627
- enableJsonResponse: true
3628
- });
3629
- res.on("close", () => {
3630
- transport.close();
3631
- });
3632
- await mcpServer.connect(transport);
3633
- await transport.handleRequest(req, res, body);
3634
- } catch (err) {
3635
- sendJSON(res, 500, {
3636
- jsonrpc: "2.0",
3637
- id: null,
3638
- error: {
3639
- code: -32603,
3640
- message: err instanceof Error ? err.message : String(err ?? "")
3641
- }
3642
- });
3643
- }
3928
+ let rawBody;
3929
+ try {
3930
+ rawBody = await readRawRequestBody(req);
3931
+ } catch {
3932
+ sendJSON(res, 400, { error: "Failed to read request body" });
3644
3933
  return;
3645
3934
  }
3646
- sendJSON(res, 404, {
3647
- jsonrpc: "2.0",
3648
- id: null,
3649
- error: {
3650
- code: -32601,
3651
- message: "Not Found"
3652
- }
3653
- });
3935
+ const unifiedReq = fromHttpRequest(req, url, rawBody);
3936
+ const response = await routeRequest(unifiedReq, ctx);
3937
+ sendUnifiedResponse(res, response, defaultHeaders);
3654
3938
  } catch (err) {
3655
3939
  sendJSON(res, 500, {
3656
3940
  jsonrpc: "2.0",
@@ -3677,485 +3961,95 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
3677
3961
  getHealthStatus: () => state.getHealthStatus()
3678
3962
  };
3679
3963
  }
3964
+ async function handleMcpWithSdkTransport(req, res, url, ctx, mcpServer) {
3965
+ try {
3966
+ const body = await parseJSONBody(req);
3967
+ if (body?.method === "tools/call") {
3968
+ console.log(
3969
+ "[dedicated.ts /mcp] Received tools/call request:",
3970
+ JSON.stringify(
3971
+ {
3972
+ method: body.method,
3973
+ toolName: body.params?.name,
3974
+ hasArguments: !!body.params?.arguments,
3975
+ argumentKeys: body.params?.arguments ? Object.keys(body.params.arguments) : [],
3976
+ hasEnv: !!body.params?.arguments?.env,
3977
+ envKeys: body.params?.arguments?.env ? Object.keys(body.params.arguments.env) : [],
3978
+ hasApiToken: !!body.params?.arguments?.env?.SKEDYUL_API_TOKEN
3979
+ },
3980
+ null,
3981
+ 2
3982
+ )
3983
+ );
3984
+ }
3985
+ if (body?.method === "tools/list") {
3986
+ sendJSON(res, 200, {
3987
+ jsonrpc: "2.0",
3988
+ id: body.id ?? null,
3989
+ result: { tools: ctx.tools }
3990
+ });
3991
+ return;
3992
+ }
3993
+ if (body?.method === "webhooks/list") {
3994
+ const webhooks = ctx.webhookRegistry ? Object.values(ctx.webhookRegistry).map((w) => ({
3995
+ name: w.name,
3996
+ description: w.description,
3997
+ methods: w.methods ?? ["POST"],
3998
+ type: w.type ?? "WEBHOOK"
3999
+ })) : [];
4000
+ sendJSON(res, 200, {
4001
+ jsonrpc: "2.0",
4002
+ id: body.id ?? null,
4003
+ result: { webhooks }
4004
+ });
4005
+ return;
4006
+ }
4007
+ const transport = new import_streamableHttp.StreamableHTTPServerTransport({
4008
+ sessionIdGenerator: void 0,
4009
+ enableJsonResponse: true
4010
+ });
4011
+ res.on("close", () => {
4012
+ transport.close();
4013
+ });
4014
+ await mcpServer.connect(transport);
4015
+ await transport.handleRequest(req, res, body);
4016
+ } catch (err) {
4017
+ sendJSON(res, 500, {
4018
+ jsonrpc: "2.0",
4019
+ id: null,
4020
+ error: {
4021
+ code: -32603,
4022
+ message: err instanceof Error ? err.message : String(err ?? "")
4023
+ }
4024
+ });
4025
+ }
4026
+ }
3680
4027
 
3681
4028
  // src/server/serverless.ts
3682
- var fs8 = __toESM(require("fs"));
3683
- var CONFIG_FILE_PATH2 = ".skedyul/config.json";
3684
4029
  function createServerlessInstance(config, tools, callTool, state, mcpServer) {
3685
- const headers = getDefaultHeaders(config.cors);
4030
+ const defaultHeaders = getDefaultHeaders(config.cors);
3686
4031
  const registry = config.tools;
3687
4032
  const webhookRegistry = config.webhooks;
3688
4033
  let hasLoggedStartup = false;
4034
+ const ctx = {
4035
+ config,
4036
+ tools,
4037
+ registry,
4038
+ webhookRegistry,
4039
+ callTool,
4040
+ state,
4041
+ mcpServer,
4042
+ defaultHeaders
4043
+ };
3689
4044
  return {
3690
4045
  async handler(event) {
3691
4046
  if (!hasLoggedStartup) {
3692
4047
  printStartupLog(config, tools);
3693
4048
  hasLoggedStartup = true;
3694
4049
  }
3695
- try {
3696
- const path16 = event.path || event.rawPath || "/";
3697
- const method = event.httpMethod || event.requestContext?.http?.method || "POST";
3698
- if (method === "OPTIONS") {
3699
- return createResponse(200, { message: "OK" }, headers);
3700
- }
3701
- if (path16.startsWith("/webhooks/") && webhookRegistry) {
3702
- const handle = path16.slice("/webhooks/".length);
3703
- if (!webhookRegistry[handle]) {
3704
- return createResponse(404, { error: `Webhook handler '${handle}' not found` }, headers);
3705
- }
3706
- if (!isMethodAllowed(webhookRegistry, handle, method)) {
3707
- return createResponse(405, { error: `Method ${method} not allowed` }, headers);
3708
- }
3709
- const rawBody = event.body ?? "";
3710
- let parsedBody;
3711
- const contentType = event.headers?.["content-type"] ?? event.headers?.["Content-Type"] ?? "";
3712
- if (contentType.includes("application/json")) {
3713
- try {
3714
- parsedBody = rawBody ? JSON.parse(rawBody) : {};
3715
- } catch {
3716
- parsedBody = rawBody;
3717
- }
3718
- } else {
3719
- parsedBody = rawBody;
3720
- }
3721
- const forwardedProto = event.headers?.["x-forwarded-proto"] ?? event.headers?.["X-Forwarded-Proto"];
3722
- const protocol = forwardedProto ?? "https";
3723
- const host = event.headers?.host ?? event.headers?.Host ?? "localhost";
3724
- const queryString = event.queryStringParameters ? "?" + new URLSearchParams(event.queryStringParameters).toString() : "";
3725
- const webhookUrl = `${protocol}://${host}${path16}${queryString}`;
3726
- const parseResult = parseWebhookRequest(
3727
- parsedBody,
3728
- method,
3729
- webhookUrl,
3730
- path16,
3731
- event.headers,
3732
- event.queryStringParameters ?? {},
3733
- rawBody,
3734
- event.headers?.["x-skedyul-app-id"] ?? event.headers?.["X-Skedyul-App-Id"],
3735
- event.headers?.["x-skedyul-app-version-id"] ?? event.headers?.["X-Skedyul-App-Version-Id"]
3736
- );
3737
- if ("error" in parseResult) {
3738
- return createResponse(400, { error: parseResult.error }, headers);
3739
- }
3740
- const result = await executeWebhookHandler(handle, webhookRegistry, parseResult);
3741
- const responseHeaders = {
3742
- ...headers,
3743
- ...result.headers
3744
- };
3745
- return {
3746
- statusCode: result.status,
3747
- headers: responseHeaders,
3748
- body: result.body !== void 0 ? typeof result.body === "string" ? result.body : JSON.stringify(result.body) : ""
3749
- };
3750
- }
3751
- if (path16 === "/core" && method === "POST") {
3752
- let coreBody;
3753
- try {
3754
- coreBody = event.body ? JSON.parse(event.body) : {};
3755
- } catch {
3756
- return createResponse(
3757
- 400,
3758
- {
3759
- error: {
3760
- code: -32700,
3761
- message: "Parse error"
3762
- }
3763
- },
3764
- headers
3765
- );
3766
- }
3767
- if (!coreBody?.method) {
3768
- return createResponse(
3769
- 400,
3770
- {
3771
- error: {
3772
- code: -32602,
3773
- message: "Missing method"
3774
- }
3775
- },
3776
- headers
3777
- );
3778
- }
3779
- const coreMethod = coreBody.method;
3780
- const result = await handleCoreMethod(coreMethod, coreBody.params);
3781
- return createResponse(result.status, result.payload, headers);
3782
- }
3783
- if (path16 === "/core/webhook" && method === "POST") {
3784
- const rawWebhookBody = event.body ?? "";
3785
- let webhookBody;
3786
- try {
3787
- webhookBody = rawWebhookBody ? JSON.parse(rawWebhookBody) : {};
3788
- } catch {
3789
- return createResponse(
3790
- 400,
3791
- { status: "parse-error" },
3792
- headers
3793
- );
3794
- }
3795
- const forwardedProto = event.headers?.["x-forwarded-proto"] ?? event.headers?.["X-Forwarded-Proto"];
3796
- const protocol = forwardedProto ?? "https";
3797
- const host = event.headers?.host ?? event.headers?.Host ?? "localhost";
3798
- const webhookUrl = `${protocol}://${host}${path16}`;
3799
- const coreWebhookRequest = {
3800
- method,
3801
- headers: event.headers ?? {},
3802
- body: webhookBody,
3803
- query: event.queryStringParameters ?? {},
3804
- url: webhookUrl,
3805
- path: path16,
3806
- rawBody: rawWebhookBody ? Buffer.from(rawWebhookBody, "utf-8") : void 0
3807
- };
3808
- const webhookResponse = await coreApiService.dispatchWebhook(
3809
- coreWebhookRequest
3810
- );
3811
- return createResponse(
3812
- webhookResponse.status,
3813
- webhookResponse.body ?? {},
3814
- headers
3815
- );
3816
- }
3817
- if (path16 === "/estimate" && method === "POST") {
3818
- let estimateBody;
3819
- try {
3820
- estimateBody = event.body ? JSON.parse(event.body) : {};
3821
- } catch {
3822
- return createResponse(
3823
- 400,
3824
- {
3825
- error: {
3826
- code: -32700,
3827
- message: "Parse error"
3828
- }
3829
- },
3830
- headers
3831
- );
3832
- }
3833
- try {
3834
- const toolName = estimateBody.name;
3835
- const toolArgs = estimateBody.inputs ?? {};
3836
- let toolKey = null;
3837
- let tool = null;
3838
- for (const [key, t] of Object.entries(registry)) {
3839
- if (t.name === toolName || key === toolName) {
3840
- toolKey = key;
3841
- tool = t;
3842
- break;
3843
- }
3844
- }
3845
- if (!tool || !toolKey) {
3846
- return createResponse(
3847
- 400,
3848
- {
3849
- error: {
3850
- code: -32602,
3851
- message: `Tool "${toolName}" not found`
3852
- }
3853
- },
3854
- headers
3855
- );
3856
- }
3857
- const inputSchema = getZodSchema3(tool.inputSchema);
3858
- const validatedArgs = inputSchema ? inputSchema.parse(toolArgs) : toolArgs;
3859
- const estimateResponse = await callTool(toolKey, {
3860
- inputs: validatedArgs,
3861
- estimate: true
3862
- });
3863
- return createResponse(
3864
- 200,
3865
- {
3866
- billing: estimateResponse.billing ?? { credits: 0 }
3867
- },
3868
- headers
3869
- );
3870
- } catch (err) {
3871
- return createResponse(
3872
- 500,
3873
- {
3874
- error: {
3875
- code: -32603,
3876
- message: err instanceof Error ? err.message : String(err ?? "")
3877
- }
3878
- },
3879
- headers
3880
- );
3881
- }
3882
- }
3883
- if (path16 === "/install" && method === "POST") {
3884
- let installBody;
3885
- try {
3886
- installBody = event.body ? JSON.parse(event.body) : {};
3887
- } catch {
3888
- return createResponse(
3889
- 400,
3890
- { error: { code: -32700, message: "Parse error" } },
3891
- headers
3892
- );
3893
- }
3894
- const result = await handleInstall(installBody, config.hooks);
3895
- return createResponse(result.status, result.body, headers);
3896
- }
3897
- if (path16 === "/uninstall" && method === "POST") {
3898
- let uninstallBody;
3899
- try {
3900
- uninstallBody = event.body ? JSON.parse(event.body) : {};
3901
- } catch {
3902
- return createResponse(
3903
- 400,
3904
- { error: { code: -32700, message: "Parse error" } },
3905
- headers
3906
- );
3907
- }
3908
- const result = await handleUninstall(uninstallBody, config.hooks);
3909
- return createResponse(result.status, result.body, headers);
3910
- }
3911
- if (path16 === "/provision" && method === "POST") {
3912
- let provisionBody;
3913
- try {
3914
- provisionBody = event.body ? JSON.parse(event.body) : {};
3915
- } catch {
3916
- return createResponse(
3917
- 400,
3918
- { error: { code: -32700, message: "Parse error" } },
3919
- headers
3920
- );
3921
- }
3922
- const result = await handleProvision(provisionBody, config.hooks);
3923
- return createResponse(result.status, result.body, headers);
3924
- }
3925
- if (path16 === "/oauth_callback" && method === "POST") {
3926
- let parsedBody;
3927
- try {
3928
- parsedBody = event.body ? JSON.parse(event.body) : {};
3929
- } catch (err) {
3930
- console.error("[OAuth Callback] Failed to parse JSON body:", err);
3931
- return createResponse(
3932
- 400,
3933
- { error: { code: -32700, message: "Parse error" } },
3934
- headers
3935
- );
3936
- }
3937
- const result = await handleOAuthCallback(parsedBody, config.hooks);
3938
- return createResponse(result.status, result.body, headers);
3939
- }
3940
- if (path16 === "/health" && method === "GET") {
3941
- return createResponse(200, state.getHealthStatus(), headers);
3942
- }
3943
- if (path16 === "/config" && method === "GET") {
3944
- try {
3945
- if (fs8.existsSync(CONFIG_FILE_PATH2)) {
3946
- const fileConfig = JSON.parse(fs8.readFileSync(CONFIG_FILE_PATH2, "utf-8"));
3947
- return createResponse(200, fileConfig, headers);
3948
- }
3949
- } catch (err) {
3950
- console.warn("[/config] Failed to read config file, falling back to runtime serialization:", err);
3951
- }
3952
- return createResponse(200, serializeConfig(config), headers);
3953
- }
3954
- if (path16 === "/mcp" && method === "POST") {
3955
- let body;
3956
- try {
3957
- body = event.body ? JSON.parse(event.body) : {};
3958
- } catch {
3959
- return createResponse(
3960
- 400,
3961
- {
3962
- jsonrpc: "2.0",
3963
- id: null,
3964
- error: {
3965
- code: -32700,
3966
- message: "Parse error"
3967
- }
3968
- },
3969
- headers
3970
- );
3971
- }
3972
- try {
3973
- const { jsonrpc, id, method: rpcMethod, params } = body;
3974
- if (jsonrpc !== "2.0") {
3975
- return createResponse(
3976
- 400,
3977
- {
3978
- jsonrpc: "2.0",
3979
- id,
3980
- error: {
3981
- code: -32600,
3982
- message: "Invalid Request"
3983
- }
3984
- },
3985
- headers
3986
- );
3987
- }
3988
- let result;
3989
- if (rpcMethod === "tools/list") {
3990
- result = { tools };
3991
- } else if (rpcMethod === "tools/call") {
3992
- const toolName = params?.name;
3993
- const rawArgs = params?.arguments ?? {};
3994
- console.log("[serverless.ts /mcp] Received tools/call request:", JSON.stringify({
3995
- toolName,
3996
- hasArguments: !!params?.arguments,
3997
- argumentKeys: rawArgs ? Object.keys(rawArgs) : [],
3998
- hasEnv: "env" in rawArgs,
3999
- envKeys: rawArgs.env ? Object.keys(rawArgs.env) : [],
4000
- hasApiToken: !!rawArgs.env?.SKEDYUL_API_TOKEN
4001
- }, null, 2));
4002
- const hasSkedyulFormat = "inputs" in rawArgs || "env" in rawArgs || "context" in rawArgs || "invocation" in rawArgs;
4003
- const toolInputs = hasSkedyulFormat ? rawArgs.inputs ?? {} : rawArgs;
4004
- const toolContext = hasSkedyulFormat ? rawArgs.context : void 0;
4005
- const toolEnv = hasSkedyulFormat ? rawArgs.env : void 0;
4006
- const toolInvocation = hasSkedyulFormat ? rawArgs.invocation : void 0;
4007
- console.log("[serverless.ts /mcp] Extracted env:", JSON.stringify({
4008
- hasSkedyulFormat,
4009
- hasToolEnv: !!toolEnv,
4010
- toolEnvKeys: toolEnv ? Object.keys(toolEnv) : [],
4011
- hasApiToken: toolEnv?.SKEDYUL_API_TOKEN ? `yes (${toolEnv.SKEDYUL_API_TOKEN.length} chars)` : "no"
4012
- }, null, 2));
4013
- let toolKey = null;
4014
- let tool = null;
4015
- for (const [key, t] of Object.entries(registry)) {
4016
- if (t.name === toolName || key === toolName) {
4017
- toolKey = key;
4018
- tool = t;
4019
- break;
4020
- }
4021
- }
4022
- if (!tool || !toolKey) {
4023
- return createResponse(
4024
- 200,
4025
- {
4026
- jsonrpc: "2.0",
4027
- id,
4028
- error: {
4029
- code: -32602,
4030
- message: `Tool "${toolName}" not found`
4031
- }
4032
- },
4033
- headers
4034
- );
4035
- }
4036
- try {
4037
- const inputSchema = getZodSchema3(tool.inputSchema);
4038
- const outputSchema = getZodSchema3(tool.outputSchema);
4039
- const hasOutputSchema = Boolean(outputSchema);
4040
- const validatedInputs = inputSchema ? inputSchema.parse(toolInputs) : toolInputs;
4041
- const toolResult = await callTool(toolKey, {
4042
- inputs: validatedInputs,
4043
- context: toolContext,
4044
- env: toolEnv,
4045
- invocation: toolInvocation
4046
- });
4047
- if (toolResult.error) {
4048
- const errorOutput = { error: toolResult.error };
4049
- result = {
4050
- content: [{ type: "text", text: JSON.stringify(errorOutput) }],
4051
- // Don't provide structuredContent for error responses when tool has outputSchema
4052
- // because the error response won't match the success schema and MCP SDK validates it
4053
- structuredContent: hasOutputSchema ? void 0 : errorOutput,
4054
- isError: true,
4055
- billing: toolResult.billing
4056
- };
4057
- } else {
4058
- const outputData = toolResult.output;
4059
- let structuredContent;
4060
- if (outputData) {
4061
- structuredContent = { ...outputData, __effect: toolResult.effect };
4062
- } else if (toolResult.effect) {
4063
- structuredContent = { __effect: toolResult.effect };
4064
- } else if (hasOutputSchema) {
4065
- structuredContent = {};
4066
- }
4067
- result = {
4068
- content: [{ type: "text", text: JSON.stringify(toolResult.output) }],
4069
- structuredContent,
4070
- billing: toolResult.billing
4071
- };
4072
- }
4073
- } catch (validationError) {
4074
- return createResponse(
4075
- 200,
4076
- {
4077
- jsonrpc: "2.0",
4078
- id,
4079
- error: {
4080
- code: -32602,
4081
- message: validationError instanceof Error ? validationError.message : "Invalid arguments"
4082
- }
4083
- },
4084
- headers
4085
- );
4086
- }
4087
- } else if (rpcMethod === "webhooks/list") {
4088
- const webhooks = webhookRegistry ? Object.values(webhookRegistry).map((w) => ({
4089
- name: w.name,
4090
- description: w.description,
4091
- methods: w.methods ?? ["POST"],
4092
- type: w.type ?? "WEBHOOK"
4093
- })) : [];
4094
- result = { webhooks };
4095
- } else {
4096
- return createResponse(
4097
- 200,
4098
- {
4099
- jsonrpc: "2.0",
4100
- id,
4101
- error: {
4102
- code: -32601,
4103
- message: `Method not found: ${rpcMethod}`
4104
- }
4105
- },
4106
- headers
4107
- );
4108
- }
4109
- return createResponse(
4110
- 200,
4111
- {
4112
- jsonrpc: "2.0",
4113
- id,
4114
- result
4115
- },
4116
- headers
4117
- );
4118
- } catch (err) {
4119
- return createResponse(
4120
- 500,
4121
- {
4122
- jsonrpc: "2.0",
4123
- id: body?.id ?? null,
4124
- error: {
4125
- code: -32603,
4126
- message: err instanceof Error ? err.message : String(err ?? "")
4127
- }
4128
- },
4129
- headers
4130
- );
4131
- }
4132
- }
4133
- return createResponse(
4134
- 404,
4135
- {
4136
- jsonrpc: "2.0",
4137
- id: null,
4138
- error: {
4139
- code: -32601,
4140
- message: "Not Found"
4141
- }
4142
- },
4143
- headers
4144
- );
4145
- } catch (err) {
4146
- return createResponse(
4147
- 500,
4148
- {
4149
- jsonrpc: "2.0",
4150
- id: null,
4151
- error: {
4152
- code: -32603,
4153
- message: err instanceof Error ? err.message : String(err ?? "")
4154
- }
4155
- },
4156
- headers
4157
- );
4158
- }
4050
+ const req = fromLambdaEvent(event);
4051
+ const response = await routeRequest(req, ctx);
4052
+ return toLambdaResponse(response, defaultHeaders);
4159
4053
  },
4160
4054
  getHealthStatus: () => state.getHealthStatus()
4161
4055
  };
@@ -4983,13 +4877,13 @@ Press Ctrl+C to stop`);
4983
4877
  }
4984
4878
 
4985
4879
  // src/cli/commands/validate.ts
4986
- var fs10 = __toESM(require("fs"));
4987
- var path9 = __toESM(require("path"));
4880
+ var fs9 = __toESM(require("fs"));
4881
+ var path10 = __toESM(require("path"));
4988
4882
  init_utils();
4989
4883
 
4990
4884
  // src/config/loader.ts
4991
- var fs9 = __toESM(require("fs"));
4992
- var path7 = __toESM(require("path"));
4885
+ var fs8 = __toESM(require("fs"));
4886
+ var path8 = __toESM(require("path"));
4993
4887
  var os2 = __toESM(require("os"));
4994
4888
  var CONFIG_FILE_NAMES = [
4995
4889
  "skedyul.config.ts",
@@ -4998,13 +4892,13 @@ var CONFIG_FILE_NAMES = [
4998
4892
  "skedyul.config.cjs"
4999
4893
  ];
5000
4894
  async function transpileTypeScript(filePath) {
5001
- const content = fs9.readFileSync(filePath, "utf-8");
5002
- const configDir = path7.dirname(path7.resolve(filePath));
4895
+ const content = fs8.readFileSync(filePath, "utf-8");
4896
+ const configDir = path8.dirname(path8.resolve(filePath));
5003
4897
  let transpiled = content.replace(/import\s+type\s+\{[^}]+\}\s+from\s+['"][^'"]+['"]\s*;?\n?/g, "").replace(/import\s+\{\s*defineConfig\s*\}\s+from\s+['"]skedyul['"]\s*;?\n?/g, "").replace(/:\s*SkedyulConfig/g, "").replace(/export\s+default\s+/, "module.exports = ").replace(/defineConfig\s*\(\s*\{/, "{").replace(/\}\s*\)\s*;?\s*$/, "}");
5004
4898
  transpiled = transpiled.replace(
5005
4899
  /import\s+(\w+)\s+from\s+['"](\.[^'"]+)['"]\s*(?:with\s*\{[^}]*\})?/g,
5006
4900
  (match, varName, relativePath) => {
5007
- const absolutePath = path7.resolve(configDir, relativePath);
4901
+ const absolutePath = path8.resolve(configDir, relativePath);
5008
4902
  return `const ${varName} = require('${absolutePath.replace(/\\/g, "/")}')`;
5009
4903
  }
5010
4904
  );
@@ -5012,8 +4906,8 @@ async function transpileTypeScript(filePath) {
5012
4906
  return transpiled;
5013
4907
  }
5014
4908
  async function loadConfig(configPath) {
5015
- const absolutePath = path7.resolve(configPath);
5016
- if (!fs9.existsSync(absolutePath)) {
4909
+ const absolutePath = path8.resolve(configPath);
4910
+ if (!fs8.existsSync(absolutePath)) {
5017
4911
  throw new Error(`Config file not found: ${absolutePath}`);
5018
4912
  }
5019
4913
  const isTypeScript = absolutePath.endsWith(".ts");
@@ -5022,8 +4916,8 @@ async function loadConfig(configPath) {
5022
4916
  if (isTypeScript) {
5023
4917
  const transpiled = await transpileTypeScript(absolutePath);
5024
4918
  const tempDir = os2.tmpdir();
5025
- const tempFile = path7.join(tempDir, `skedyul-config-${Date.now()}.cjs`);
5026
- fs9.writeFileSync(tempFile, transpiled);
4919
+ const tempFile = path8.join(tempDir, `skedyul-config-${Date.now()}.cjs`);
4920
+ fs8.writeFileSync(tempFile, transpiled);
5027
4921
  moduleToLoad = tempFile;
5028
4922
  try {
5029
4923
  const module3 = require(moduleToLoad);
@@ -5037,7 +4931,7 @@ async function loadConfig(configPath) {
5037
4931
  return config2;
5038
4932
  } finally {
5039
4933
  try {
5040
- fs9.unlinkSync(tempFile);
4934
+ fs8.unlinkSync(tempFile);
5041
4935
  } catch {
5042
4936
  }
5043
4937
  }
@@ -5069,9 +4963,9 @@ function validateConfig(config) {
5069
4963
  }
5070
4964
 
5071
4965
  // src/config/resolver.ts
5072
- var path8 = __toESM(require("path"));
4966
+ var path9 = __toESM(require("path"));
5073
4967
  async function loadAndResolveConfig(configPath) {
5074
- const absolutePath = path8.resolve(configPath);
4968
+ const absolutePath = path9.resolve(configPath);
5075
4969
  const module2 = await import(absolutePath);
5076
4970
  const config = module2.default;
5077
4971
  if (!config || typeof config !== "object") {
@@ -5174,8 +5068,8 @@ Examples:
5174
5068
  }
5175
5069
  function findConfigFile2(startDir) {
5176
5070
  for (const fileName of CONFIG_FILE_NAMES) {
5177
- const filePath = path9.join(startDir, fileName);
5178
- if (fs10.existsSync(filePath)) {
5071
+ const filePath = path10.join(startDir, fileName);
5072
+ if (fs9.existsSync(filePath)) {
5179
5073
  return filePath;
5180
5074
  }
5181
5075
  }
@@ -5209,9 +5103,9 @@ async function validateCommand(args2) {
5209
5103
  }
5210
5104
  configPath = foundConfig;
5211
5105
  } else {
5212
- configPath = path9.resolve(process.cwd(), configPath);
5106
+ configPath = path10.resolve(process.cwd(), configPath);
5213
5107
  }
5214
- if (!fs10.existsSync(configPath)) {
5108
+ if (!fs9.existsSync(configPath)) {
5215
5109
  const result2 = {
5216
5110
  valid: false,
5217
5111
  configPath,
@@ -5256,8 +5150,8 @@ async function validateCommand(args2) {
5256
5150
  if (provision?.workflows) {
5257
5151
  for (const workflow of provision.workflows) {
5258
5152
  if (workflow.path) {
5259
- const absoluteWorkflowPath = path9.resolve(path9.dirname(configPath), workflow.path);
5260
- if (!fs10.existsSync(absoluteWorkflowPath)) {
5153
+ const absoluteWorkflowPath = path10.resolve(path10.dirname(configPath), workflow.path);
5154
+ if (!fs9.existsSync(absoluteWorkflowPath)) {
5261
5155
  warnings.push(`Workflow file not found: ${workflow.path}`);
5262
5156
  }
5263
5157
  }
@@ -5352,8 +5246,8 @@ async function validateCommand(args2) {
5352
5246
  }
5353
5247
 
5354
5248
  // src/cli/commands/diff.ts
5355
- var fs11 = __toESM(require("fs"));
5356
- var path10 = __toESM(require("path"));
5249
+ var fs10 = __toESM(require("fs"));
5250
+ var path11 = __toESM(require("path"));
5357
5251
  init_utils();
5358
5252
  function printHelp6() {
5359
5253
  console.log(`
@@ -5386,8 +5280,8 @@ Examples:
5386
5280
  }
5387
5281
  function findConfigFile3(startDir) {
5388
5282
  for (const fileName of CONFIG_FILE_NAMES) {
5389
- const filePath = path10.join(startDir, fileName);
5390
- if (fs11.existsSync(filePath)) {
5283
+ const filePath = path11.join(startDir, fileName);
5284
+ if (fs10.existsSync(filePath)) {
5391
5285
  return filePath;
5392
5286
  }
5393
5287
  }
@@ -5443,9 +5337,9 @@ async function diffCommand(args2) {
5443
5337
  }
5444
5338
  configPath = foundConfig;
5445
5339
  } else {
5446
- configPath = path10.resolve(process.cwd(), configPath);
5340
+ configPath = path11.resolve(process.cwd(), configPath);
5447
5341
  }
5448
- if (!fs11.existsSync(configPath)) {
5342
+ if (!fs10.existsSync(configPath)) {
5449
5343
  if (jsonOutput) {
5450
5344
  console.log(JSON.stringify({ error: `Config file not found: ${configPath}` }));
5451
5345
  } else {
@@ -5487,7 +5381,7 @@ async function diffCommand(args2) {
5487
5381
  const registryPath = flags.registry || flags.r;
5488
5382
  if (registryPath) {
5489
5383
  try {
5490
- const registry = await loadRegistry(path10.resolve(process.cwd(), registryPath));
5384
+ const registry = await loadRegistry(path11.resolve(process.cwd(), registryPath));
5491
5385
  const toolNames = Object.values(registry).map((t) => t.name);
5492
5386
  toolsDiff = {
5493
5387
  added: toolNames,
@@ -5560,8 +5454,8 @@ async function diffCommand(args2) {
5560
5454
  }
5561
5455
 
5562
5456
  // src/cli/commands/deploy.ts
5563
- var fs12 = __toESM(require("fs"));
5564
- var path11 = __toESM(require("path"));
5457
+ var fs11 = __toESM(require("fs"));
5458
+ var path12 = __toESM(require("path"));
5565
5459
  var readline2 = __toESM(require("readline"));
5566
5460
  init_utils();
5567
5461
  function printHelp7() {
@@ -5597,8 +5491,8 @@ Examples:
5597
5491
  }
5598
5492
  function findConfigFile4(startDir) {
5599
5493
  for (const fileName of CONFIG_FILE_NAMES) {
5600
- const filePath = path11.join(startDir, fileName);
5601
- if (fs12.existsSync(filePath)) {
5494
+ const filePath = path12.join(startDir, fileName);
5495
+ if (fs11.existsSync(filePath)) {
5602
5496
  return filePath;
5603
5497
  }
5604
5498
  }
@@ -5712,9 +5606,9 @@ async function deployCommand(args2) {
5712
5606
  }
5713
5607
  configPath = foundConfig;
5714
5608
  } else {
5715
- configPath = path11.resolve(process.cwd(), configPath);
5609
+ configPath = path12.resolve(process.cwd(), configPath);
5716
5610
  }
5717
- if (!fs12.existsSync(configPath)) {
5611
+ if (!fs11.existsSync(configPath)) {
5718
5612
  if (jsonOutput) {
5719
5613
  console.log(JSON.stringify({ error: `Config file not found: ${configPath}` }));
5720
5614
  } else {
@@ -6031,8 +5925,8 @@ async function logoutCommand(args2) {
6031
5925
  }
6032
5926
 
6033
5927
  // src/cli/commands/auth/status.ts
6034
- var fs13 = __toESM(require("fs"));
6035
- var path12 = __toESM(require("path"));
5928
+ var fs12 = __toESM(require("fs"));
5929
+ var path13 = __toESM(require("path"));
6036
5930
  init_utils();
6037
5931
  function printHelp10() {
6038
5932
  console.log(`
@@ -6106,17 +6000,17 @@ async function statusCommand(args2) {
6106
6000
  console.log("");
6107
6001
  console.log(" * = active profile");
6108
6002
  }
6109
- const linksDir = path12.join(process.cwd(), ".skedyul", "links");
6003
+ const linksDir = path13.join(process.cwd(), ".skedyul", "links");
6110
6004
  console.log("");
6111
6005
  console.log("LINKED WORKPLACES (this project)");
6112
6006
  console.log("\u2500".repeat(60));
6113
- if (fs13.existsSync(linksDir)) {
6114
- const linkFiles = fs13.readdirSync(linksDir).filter((f) => f.endsWith(".json"));
6007
+ if (fs12.existsSync(linksDir)) {
6008
+ const linkFiles = fs12.readdirSync(linksDir).filter((f) => f.endsWith(".json"));
6115
6009
  if (linkFiles.length > 0) {
6116
6010
  for (const file2 of linkFiles) {
6117
6011
  const subdomain = file2.replace(".json", "");
6118
6012
  try {
6119
- const content = fs13.readFileSync(path12.join(linksDir, file2), "utf-8");
6013
+ const content = fs12.readFileSync(path13.join(linksDir, file2), "utf-8");
6120
6014
  const link = JSON.parse(content);
6121
6015
  console.log(` - ${subdomain} (${link.appHandle})`);
6122
6016
  } catch {
@@ -6473,8 +6367,8 @@ EXAMPLES
6473
6367
  }
6474
6368
 
6475
6369
  // src/cli/commands/config-export.ts
6476
- var fs14 = __toESM(require("fs"));
6477
- var path13 = __toESM(require("path"));
6370
+ var fs13 = __toESM(require("fs"));
6371
+ var path14 = __toESM(require("path"));
6478
6372
  function printHelp13() {
6479
6373
  console.log(`
6480
6374
  SKEDYUL CONFIG:EXPORT - Export resolved config to JSON
@@ -6520,8 +6414,8 @@ async function configExportCommand(args2) {
6520
6414
  const cwd = process.cwd();
6521
6415
  let configPath = null;
6522
6416
  for (const name of CONFIG_FILE_NAMES) {
6523
- const testPath = path13.join(cwd, name);
6524
- if (fs14.existsSync(testPath)) {
6417
+ const testPath = path14.join(cwd, name);
6418
+ if (fs13.existsSync(testPath)) {
6525
6419
  configPath = testPath;
6526
6420
  break;
6527
6421
  }
@@ -6531,16 +6425,16 @@ async function configExportCommand(args2) {
6531
6425
  console.error("Make sure you are in the root of your integration project.");
6532
6426
  process.exit(1);
6533
6427
  }
6534
- console.log(`Loading config from ${path13.basename(configPath)}...`);
6428
+ console.log(`Loading config from ${path14.basename(configPath)}...`);
6535
6429
  try {
6536
6430
  const resolvedConfig = await loadAndResolveConfig(configPath);
6537
6431
  const serialized = serializeResolvedConfig(resolvedConfig);
6538
- const outputDir = path13.dirname(path13.resolve(cwd, outputPath));
6539
- if (!fs14.existsSync(outputDir)) {
6540
- fs14.mkdirSync(outputDir, { recursive: true });
6432
+ const outputDir = path14.dirname(path14.resolve(cwd, outputPath));
6433
+ if (!fs13.existsSync(outputDir)) {
6434
+ fs13.mkdirSync(outputDir, { recursive: true });
6541
6435
  }
6542
- const fullOutputPath = path13.resolve(cwd, outputPath);
6543
- fs14.writeFileSync(fullOutputPath, JSON.stringify(serialized, null, 2), "utf-8");
6436
+ const fullOutputPath = path14.resolve(cwd, outputPath);
6437
+ fs13.writeFileSync(fullOutputPath, JSON.stringify(serialized, null, 2), "utf-8");
6544
6438
  console.log(``);
6545
6439
  console.log(`Config exported successfully!`);
6546
6440
  console.log(` Output: ${outputPath}`);
@@ -7123,8 +7017,8 @@ async function handleCreateMany(modelHandle, flags) {
7123
7017
  console.error("Usage: skedyul instances create-many <model> --file data.json --workplace <subdomain>");
7124
7018
  process.exit(1);
7125
7019
  }
7126
- const fs17 = await import("fs");
7127
- const fileContent = fs17.readFileSync(filePath, "utf-8");
7020
+ const fs16 = await import("fs");
7021
+ const fileContent = fs16.readFileSync(filePath, "utf-8");
7128
7022
  const items = JSON.parse(fileContent);
7129
7023
  if (!Array.isArray(items)) {
7130
7024
  console.error("Error: File must contain a JSON array of items");
@@ -7151,8 +7045,8 @@ async function handleUpsertMany(modelHandle, flags) {
7151
7045
  console.error("Usage: skedyul instances upsert-many <model> --file data.json --match-field <field> --workplace <subdomain>");
7152
7046
  process.exit(1);
7153
7047
  }
7154
- const fs17 = await import("fs");
7155
- const fileContent = fs17.readFileSync(filePath, "utf-8");
7048
+ const fs16 = await import("fs");
7049
+ const fileContent = fs16.readFileSync(filePath, "utf-8");
7156
7050
  const items = JSON.parse(fileContent);
7157
7051
  if (!Array.isArray(items)) {
7158
7052
  console.error("Error: File must contain a JSON array of items");
@@ -7164,8 +7058,8 @@ async function handleUpsertMany(modelHandle, flags) {
7164
7058
 
7165
7059
  // src/cli/commands/build.ts
7166
7060
  var import_child_process = require("child_process");
7167
- var fs15 = __toESM(require("fs"));
7168
- var path14 = __toESM(require("path"));
7061
+ var fs14 = __toESM(require("fs"));
7062
+ var path15 = __toESM(require("path"));
7169
7063
  function printBuildHelp() {
7170
7064
  console.log(`
7171
7065
  SKEDYUL BUILD - Build your integration
@@ -7234,8 +7128,8 @@ async function buildCommand(args2) {
7234
7128
  const cwd = process.cwd();
7235
7129
  let configPath = null;
7236
7130
  for (const name of CONFIG_FILE_NAMES) {
7237
- const testPath = path14.join(cwd, name);
7238
- if (fs15.existsSync(testPath)) {
7131
+ const testPath = path15.join(cwd, name);
7132
+ if (fs14.existsSync(testPath)) {
7239
7133
  configPath = testPath;
7240
7134
  break;
7241
7135
  }
@@ -7245,8 +7139,8 @@ async function buildCommand(args2) {
7245
7139
  console.error("Make sure you are in the root of your integration project.");
7246
7140
  process.exit(1);
7247
7141
  }
7248
- console.log(`Loading config from ${path14.basename(configPath)}...`);
7249
- const tempConfigPath = path14.join(cwd, ".skedyul-tsup.config.mjs");
7142
+ console.log(`Loading config from ${path15.basename(configPath)}...`);
7143
+ const tempConfigPath = path15.join(cwd, ".skedyul-tsup.config.mjs");
7250
7144
  let createdTempConfig = false;
7251
7145
  try {
7252
7146
  const config = await loadConfig(configPath);
@@ -7255,8 +7149,8 @@ async function buildCommand(args2) {
7255
7149
  const baseExternals = ["skedyul", `skedyul/${computeLayer}`, "zod"];
7256
7150
  const userExternals = config.build && "external" in config.build ? config.build.external ?? [] : [];
7257
7151
  const allExternals = [...baseExternals, ...userExternals];
7258
- const userTsupConfig = path14.join(cwd, "tsup.config.ts");
7259
- const hasUserConfig = fs15.existsSync(userTsupConfig);
7152
+ const userTsupConfig = path15.join(cwd, "tsup.config.ts");
7153
+ const hasUserConfig = fs14.existsSync(userTsupConfig);
7260
7154
  console.log(``);
7261
7155
  console.log(`Building ${config.name ?? "integration"}...`);
7262
7156
  console.log(` Compute layer: ${computeLayer}`);
@@ -7276,7 +7170,7 @@ async function buildCommand(args2) {
7276
7170
  }
7277
7171
  } else {
7278
7172
  const tsupConfigContent = generateTsupConfig(format, allExternals);
7279
- fs15.writeFileSync(tempConfigPath, tsupConfigContent, "utf-8");
7173
+ fs14.writeFileSync(tempConfigPath, tsupConfigContent, "utf-8");
7280
7174
  createdTempConfig = true;
7281
7175
  tsupArgs = [
7282
7176
  "tsup",
@@ -7294,14 +7188,14 @@ async function buildCommand(args2) {
7294
7188
  });
7295
7189
  tsup.on("error", (error) => {
7296
7190
  console.error("Failed to start tsup:", error.message);
7297
- if (createdTempConfig && fs15.existsSync(tempConfigPath)) {
7298
- fs15.unlinkSync(tempConfigPath);
7191
+ if (createdTempConfig && fs14.existsSync(tempConfigPath)) {
7192
+ fs14.unlinkSync(tempConfigPath);
7299
7193
  }
7300
7194
  process.exit(1);
7301
7195
  });
7302
7196
  tsup.on("close", (code) => {
7303
- if (createdTempConfig && fs15.existsSync(tempConfigPath)) {
7304
- fs15.unlinkSync(tempConfigPath);
7197
+ if (createdTempConfig && fs14.existsSync(tempConfigPath)) {
7198
+ fs14.unlinkSync(tempConfigPath);
7305
7199
  }
7306
7200
  if (code === 0) {
7307
7201
  console.log(``);
@@ -7310,8 +7204,8 @@ async function buildCommand(args2) {
7310
7204
  process.exit(code ?? 0);
7311
7205
  });
7312
7206
  } catch (error) {
7313
- if (createdTempConfig && fs15.existsSync(tempConfigPath)) {
7314
- fs15.unlinkSync(tempConfigPath);
7207
+ if (createdTempConfig && fs14.existsSync(tempConfigPath)) {
7208
+ fs14.unlinkSync(tempConfigPath);
7315
7209
  }
7316
7210
  console.error(
7317
7211
  "Error loading config:",
@@ -7324,8 +7218,8 @@ async function buildCommand(args2) {
7324
7218
  // src/cli/commands/smoke-test.ts
7325
7219
  var import_child_process2 = require("child_process");
7326
7220
  var http3 = __toESM(require("http"));
7327
- var fs16 = __toESM(require("fs"));
7328
- var path15 = __toESM(require("path"));
7221
+ var fs15 = __toESM(require("fs"));
7222
+ var path16 = __toESM(require("path"));
7329
7223
  var SMOKE_TEST_PORT = 3456;
7330
7224
  var HEALTH_CHECK_INTERVAL_MS = 500;
7331
7225
  var HEALTH_CHECK_MAX_RETRIES = 30;
@@ -7356,13 +7250,13 @@ WHAT IT DOES
7356
7250
  6. Exits with code 0 (success) or 1 (failure)
7357
7251
  `);
7358
7252
  }
7359
- function makeRequest(port, path16, method, body) {
7253
+ function makeRequest(port, path17, method, body) {
7360
7254
  return new Promise((resolve10, reject) => {
7361
7255
  const postData = body ? JSON.stringify(body) : void 0;
7362
7256
  const options = {
7363
7257
  hostname: "localhost",
7364
7258
  port,
7365
- path: path16,
7259
+ path: path17,
7366
7260
  method,
7367
7261
  headers: {
7368
7262
  "Content-Type": "application/json",
@@ -7450,8 +7344,8 @@ async function smokeTestCommand(args2) {
7450
7344
  const cwd = process.cwd();
7451
7345
  let configPath = null;
7452
7346
  for (const name of CONFIG_FILE_NAMES) {
7453
- const testPath = path15.join(cwd, name);
7454
- if (fs16.existsSync(testPath)) {
7347
+ const testPath = path16.join(cwd, name);
7348
+ if (fs15.existsSync(testPath)) {
7455
7349
  configPath = testPath;
7456
7350
  break;
7457
7351
  }
@@ -7467,10 +7361,10 @@ async function smokeTestCommand(args2) {
7467
7361
  }
7468
7362
  const serverExt = computeLayer === "serverless" ? "mjs" : "js";
7469
7363
  let serverPath = `dist/server/mcp_server.${serverExt}`;
7470
- if (!fs16.existsSync(serverPath)) {
7364
+ if (!fs15.existsSync(serverPath)) {
7471
7365
  const fallbackExt = serverExt === "mjs" ? "js" : "mjs";
7472
7366
  const fallbackPath = `dist/server/mcp_server.${fallbackExt}`;
7473
- if (fs16.existsSync(fallbackPath)) {
7367
+ if (fs15.existsSync(fallbackPath)) {
7474
7368
  console.warn(`[SmokeTest] Warning: Expected ${serverPath} but found ${fallbackPath}`);
7475
7369
  console.warn(`[SmokeTest] Using ${fallbackPath} instead`);
7476
7370
  serverPath = fallbackPath;