@insforge/mcp 1.2.6 → 1.2.7
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/README.md +21 -0
- package/dist/{chunk-3S2HFIGS.js → chunk-Z3FXBI3Z.js} +1324 -691
- package/dist/http-server.js +2087 -130
- package/dist/index.js +3 -2
- package/package.json +32 -7
- package/server.json +29 -6
|
@@ -1,29 +1,37 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
// src/shared/tools.ts
|
|
4
|
-
import
|
|
5
|
-
import fetch2 from "node-fetch";
|
|
6
|
-
import { promises as fs } from "fs";
|
|
7
|
-
import { exec } from "child_process";
|
|
8
|
-
import { promisify } from "util";
|
|
9
|
-
import { tmpdir } from "os";
|
|
10
|
-
import archiver from "archiver";
|
|
3
|
+
// src/shared/tools/index.ts
|
|
4
|
+
import fetch7 from "node-fetch";
|
|
11
5
|
|
|
12
6
|
// src/shared/response-handler.ts
|
|
7
|
+
function isErrorResponse(value) {
|
|
8
|
+
if (typeof value !== "object" || value === null) return false;
|
|
9
|
+
const v = value;
|
|
10
|
+
const hasMessage = typeof v.message === "string";
|
|
11
|
+
const hasError = typeof v.error === "string";
|
|
12
|
+
const hasStatusCode = typeof v.statusCode === "number";
|
|
13
|
+
const hasNextAction = !("nextAction" in v) || typeof v.nextAction === "string";
|
|
14
|
+
return (hasMessage || hasError || hasStatusCode) && hasNextAction;
|
|
15
|
+
}
|
|
13
16
|
async function handleApiResponse(response) {
|
|
14
17
|
const responseData = await response.json();
|
|
15
18
|
if (!response.ok) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
if (isErrorResponse(responseData)) {
|
|
20
|
+
let fullMessage = responseData.message ?? responseData.error ?? "Unknown error";
|
|
21
|
+
if (typeof responseData.nextAction === "string" && responseData.nextAction.length > 0) {
|
|
22
|
+
fullMessage += `. ${responseData.nextAction}`;
|
|
23
|
+
}
|
|
24
|
+
throw new Error(fullMessage);
|
|
20
25
|
}
|
|
21
|
-
throw new Error(
|
|
26
|
+
throw new Error("Unknown error");
|
|
22
27
|
}
|
|
23
28
|
return responseData;
|
|
24
29
|
}
|
|
30
|
+
function hasMessageProperty(value) {
|
|
31
|
+
return typeof value === "object" && value !== null && "message" in value && typeof value.message === "string";
|
|
32
|
+
}
|
|
25
33
|
function formatSuccessMessage(operation, data) {
|
|
26
|
-
if (data
|
|
34
|
+
if (hasMessageProperty(data)) {
|
|
27
35
|
return `${data.message}
|
|
28
36
|
${JSON.stringify(data, null, 2)}`;
|
|
29
37
|
}
|
|
@@ -64,6 +72,10 @@ var UsageTracker = class {
|
|
|
64
72
|
}
|
|
65
73
|
};
|
|
66
74
|
|
|
75
|
+
// src/shared/tools/docs.ts
|
|
76
|
+
import { z as z25 } from "zod";
|
|
77
|
+
import fetch2 from "node-fetch";
|
|
78
|
+
|
|
67
79
|
// node_modules/@insforge/shared-schemas/dist/database.schema.js
|
|
68
80
|
import { z } from "zod";
|
|
69
81
|
var ColumnType;
|
|
@@ -382,6 +394,12 @@ var storageBucketSchema = z5.object({
|
|
|
382
394
|
public: z5.boolean(),
|
|
383
395
|
createdAt: z5.string()
|
|
384
396
|
});
|
|
397
|
+
var storageConfigSchema = z5.object({
|
|
398
|
+
id: z5.string().uuid(),
|
|
399
|
+
maxFileSizeMb: z5.number().int().positive(),
|
|
400
|
+
createdAt: z5.string(),
|
|
401
|
+
updatedAt: z5.string()
|
|
402
|
+
});
|
|
385
403
|
|
|
386
404
|
// node_modules/@insforge/shared-schemas/dist/storage-api.schema.js
|
|
387
405
|
import { z as z6 } from "zod";
|
|
@@ -428,6 +446,9 @@ var confirmUploadRequestSchema = z6.object({
|
|
|
428
446
|
contentType: z6.string().optional(),
|
|
429
447
|
etag: z6.string().optional()
|
|
430
448
|
});
|
|
449
|
+
var updateStorageConfigRequestSchema = z6.object({
|
|
450
|
+
maxFileSizeMb: z6.number().int().min(1, "Must be at least 1 MB").max(200, "Must be at most 200 MB")
|
|
451
|
+
});
|
|
431
452
|
|
|
432
453
|
// node_modules/@insforge/shared-schemas/dist/auth.schema.js
|
|
433
454
|
import { z as z7 } from "zod";
|
|
@@ -485,6 +506,7 @@ var oAuthConfigSchema = z7.object({
|
|
|
485
506
|
updatedAt: z7.string()
|
|
486
507
|
// PostgreSQL timestamp
|
|
487
508
|
});
|
|
509
|
+
var allowedRedirectUrlsRegex = /^(?:(?:https?:\/\/)(?:(?:\*\.)?[^\s/:?#]+|\[[0-9A-Fa-f:.]+\])(?::\d+)?(?:\/[^\s]*)?|(?!(?:https?|javascript|data|file|vbscript):)[a-zA-Z][a-zA-Z0-9+.-]*:(?:\/\/[^\s/]+(?:\/[^\s]*)?|\/[^\s]*))$/i;
|
|
488
510
|
var authConfigSchema = z7.object({
|
|
489
511
|
id: z7.string().uuid(),
|
|
490
512
|
requireEmailVerification: z7.boolean(),
|
|
@@ -495,7 +517,7 @@ var authConfigSchema = z7.object({
|
|
|
495
517
|
requireSpecialChar: z7.boolean(),
|
|
496
518
|
verifyEmailMethod: verificationMethodSchema,
|
|
497
519
|
resetPasswordMethod: verificationMethodSchema,
|
|
498
|
-
|
|
520
|
+
allowedRedirectUrls: z7.array(z7.string().regex(allowedRedirectUrlsRegex, { message: "Invalid URL or wildcard URL" })).optional().nullable(),
|
|
499
521
|
createdAt: z7.string(),
|
|
500
522
|
// PostgreSQL timestamp
|
|
501
523
|
updatedAt: z7.string()
|
|
@@ -511,6 +533,16 @@ var tokenPayloadSchema = z7.object({
|
|
|
511
533
|
exp: z7.number().optional()
|
|
512
534
|
// Expiration
|
|
513
535
|
});
|
|
536
|
+
var customOAuthKeySchema = z7.string().min(1).max(64).regex(/^[a-z0-9_-]+$/, "Key must contain only lowercase letters, numbers, hyphens, and underscores");
|
|
537
|
+
var customOAuthConfigSchema = z7.object({
|
|
538
|
+
id: z7.string().uuid(),
|
|
539
|
+
key: customOAuthKeySchema,
|
|
540
|
+
name: z7.string().min(1),
|
|
541
|
+
discoveryEndpoint: z7.string().url(),
|
|
542
|
+
clientId: z7.string().min(1),
|
|
543
|
+
createdAt: z7.string(),
|
|
544
|
+
updatedAt: z7.string()
|
|
545
|
+
});
|
|
514
546
|
|
|
515
547
|
// node_modules/@insforge/shared-schemas/dist/auth-api.schema.js
|
|
516
548
|
import { z as z8 } from "zod";
|
|
@@ -521,12 +553,16 @@ var paginationSchema = z8.object({
|
|
|
521
553
|
var createUserRequestSchema = z8.object({
|
|
522
554
|
email: emailSchema,
|
|
523
555
|
password: passwordSchema,
|
|
524
|
-
name: nameSchema.optional()
|
|
556
|
+
name: nameSchema.optional(),
|
|
557
|
+
redirectTo: z8.string().url().optional()
|
|
525
558
|
});
|
|
526
559
|
var createSessionRequestSchema = z8.object({
|
|
527
560
|
email: emailSchema,
|
|
528
561
|
password: passwordSchema
|
|
529
562
|
});
|
|
563
|
+
var refreshSessionRequestSchema = z8.object({
|
|
564
|
+
refreshToken: z8.string().min(1, "refreshToken is required")
|
|
565
|
+
});
|
|
530
566
|
var exchangeAdminSessionRequestSchema = z8.object({
|
|
531
567
|
code: z8.string()
|
|
532
568
|
});
|
|
@@ -540,20 +576,20 @@ var updateProfileRequestSchema = z8.object({
|
|
|
540
576
|
profile: z8.record(z8.unknown())
|
|
541
577
|
});
|
|
542
578
|
var sendVerificationEmailRequestSchema = z8.object({
|
|
543
|
-
email: emailSchema
|
|
579
|
+
email: emailSchema,
|
|
580
|
+
redirectTo: z8.string().url().optional()
|
|
544
581
|
});
|
|
545
582
|
var verifyEmailRequestSchema = z8.object({
|
|
546
|
-
email: emailSchema
|
|
547
|
-
otp: z8.string().
|
|
548
|
-
}).refine((data) => data.email || data.otp, {
|
|
549
|
-
message: "Either email or otp must be provided"
|
|
583
|
+
email: emailSchema,
|
|
584
|
+
otp: z8.string().regex(/^\d{6}$/, "OTP code must be a 6-digit numeric code")
|
|
550
585
|
});
|
|
551
586
|
var sendResetPasswordEmailRequestSchema = z8.object({
|
|
552
|
-
email: emailSchema
|
|
587
|
+
email: emailSchema,
|
|
588
|
+
redirectTo: z8.string().url().optional()
|
|
553
589
|
});
|
|
554
590
|
var exchangeResetPasswordTokenRequestSchema = z8.object({
|
|
555
591
|
email: emailSchema,
|
|
556
|
-
code: z8.string().
|
|
592
|
+
code: z8.string().regex(/^\d{6}$/, "Reset password code must be a 6-digit numeric code")
|
|
557
593
|
});
|
|
558
594
|
var resetPasswordRequestSchema = z8.object({
|
|
559
595
|
newPassword: passwordSchema,
|
|
@@ -563,25 +599,31 @@ var createUserResponseSchema = z8.object({
|
|
|
563
599
|
user: userSchema.optional(),
|
|
564
600
|
accessToken: z8.string().nullable(),
|
|
565
601
|
requireEmailVerification: z8.boolean().optional(),
|
|
566
|
-
|
|
567
|
-
|
|
602
|
+
csrfToken: z8.string().nullable().optional(),
|
|
603
|
+
refreshToken: z8.string().optional()
|
|
604
|
+
// For mobile/desktop clients (no cookies)
|
|
568
605
|
});
|
|
569
606
|
var createSessionResponseSchema = z8.object({
|
|
570
607
|
user: userSchema,
|
|
571
608
|
accessToken: z8.string(),
|
|
572
|
-
|
|
573
|
-
|
|
609
|
+
csrfToken: z8.string().nullable().optional(),
|
|
610
|
+
refreshToken: z8.string().optional()
|
|
611
|
+
// For mobile/desktop clients (no cookies)
|
|
574
612
|
});
|
|
575
613
|
var verifyEmailResponseSchema = z8.object({
|
|
576
614
|
user: userSchema,
|
|
577
615
|
accessToken: z8.string(),
|
|
578
|
-
|
|
579
|
-
|
|
616
|
+
csrfToken: z8.string().nullable().optional(),
|
|
617
|
+
refreshToken: z8.string().optional()
|
|
618
|
+
// For mobile/desktop clients (no cookies)
|
|
580
619
|
});
|
|
581
620
|
var refreshSessionResponseSchema = z8.object({
|
|
582
621
|
accessToken: z8.string(),
|
|
583
622
|
user: userSchema,
|
|
584
|
-
csrfToken: z8.string()
|
|
623
|
+
csrfToken: z8.string().optional(),
|
|
624
|
+
// For web clients (cookie-based)
|
|
625
|
+
refreshToken: z8.string().optional()
|
|
626
|
+
// For mobile/desktop clients (no cookies)
|
|
585
627
|
});
|
|
586
628
|
var exchangeResetPasswordTokenResponseSchema = z8.object({
|
|
587
629
|
token: z8.string(),
|
|
@@ -627,6 +669,18 @@ var updateOAuthConfigRequestSchema = oAuthConfigSchema.omit({
|
|
|
627
669
|
}).extend({
|
|
628
670
|
clientSecret: z8.string().optional()
|
|
629
671
|
}).partial();
|
|
672
|
+
var pkceRegex = /^[A-Za-z0-9._~-]+$/;
|
|
673
|
+
var oAuthInitRequestSchema = z8.object({
|
|
674
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
675
|
+
redirect_uri: z8.string().url().optional(),
|
|
676
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
677
|
+
code_challenge: z8.string().min(43, "Code challenge must be at least 43 characters").max(128, "Code challenge must be at most 128 characters").regex(pkceRegex, "Code challenge must be base64url encoded")
|
|
678
|
+
});
|
|
679
|
+
var oAuthCodeExchangeRequestSchema = z8.object({
|
|
680
|
+
code: z8.string().min(1, "Exchange code is required"),
|
|
681
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
682
|
+
code_verifier: z8.string().min(43, "Code verifier must be at least 43 characters").max(128, "Code verifier must be at most 128 characters").regex(pkceRegex, "Code verifier must be base64url encoded")
|
|
683
|
+
});
|
|
630
684
|
var listOAuthConfigsResponseSchema = z8.object({
|
|
631
685
|
data: z8.array(oAuthConfigSchema),
|
|
632
686
|
count: z8.number()
|
|
@@ -638,11 +692,12 @@ var updateAuthConfigRequestSchema = authConfigSchema.omit({
|
|
|
638
692
|
}).partial();
|
|
639
693
|
var getPublicAuthConfigResponseSchema = z8.object({
|
|
640
694
|
oAuthProviders: z8.array(oAuthProvidersSchema),
|
|
695
|
+
customOAuthProviders: z8.array(customOAuthKeySchema),
|
|
641
696
|
...authConfigSchema.omit({
|
|
642
697
|
id: true,
|
|
643
698
|
updatedAt: true,
|
|
644
699
|
createdAt: true,
|
|
645
|
-
|
|
700
|
+
allowedRedirectUrls: true
|
|
646
701
|
}).shape
|
|
647
702
|
});
|
|
648
703
|
var authErrorResponseSchema = z8.object({
|
|
@@ -651,6 +706,16 @@ var authErrorResponseSchema = z8.object({
|
|
|
651
706
|
statusCode: z8.number().int(),
|
|
652
707
|
nextActions: z8.string().optional()
|
|
653
708
|
});
|
|
709
|
+
var createCustomOAuthConfigRequestSchema = customOAuthConfigSchema.omit({ id: true, createdAt: true, updatedAt: true }).extend({
|
|
710
|
+
clientSecret: z8.string().min(1, "Client secret is required")
|
|
711
|
+
});
|
|
712
|
+
var updateCustomOAuthConfigRequestSchema = customOAuthConfigSchema.omit({ id: true, key: true, createdAt: true, updatedAt: true }).extend({
|
|
713
|
+
clientSecret: z8.string().min(1).optional()
|
|
714
|
+
}).partial();
|
|
715
|
+
var listCustomOAuthConfigsResponseSchema = z8.object({
|
|
716
|
+
data: z8.array(customOAuthConfigSchema),
|
|
717
|
+
count: z8.number()
|
|
718
|
+
});
|
|
654
719
|
|
|
655
720
|
// node_modules/@insforge/shared-schemas/dist/metadata.schema.js
|
|
656
721
|
import { z as z11 } from "zod";
|
|
@@ -680,6 +745,9 @@ var realtimeMessageSchema = z9.object({
|
|
|
680
745
|
whDeliveredCount: z9.number().int().min(0),
|
|
681
746
|
createdAt: z9.string().datetime()
|
|
682
747
|
});
|
|
748
|
+
var realtimeConfigSchema = z9.object({
|
|
749
|
+
retentionDays: z9.number().int().positive().nullable()
|
|
750
|
+
});
|
|
683
751
|
var subscribeChannelPayloadSchema = z9.object({
|
|
684
752
|
channel: z9.string().min(1)
|
|
685
753
|
// The resolved channel instance, e.g., "order:123"
|
|
@@ -765,7 +833,8 @@ var messageStatsResponseSchema = z10.object({
|
|
|
765
833
|
topEvents: z10.array(z10.object({
|
|
766
834
|
eventName: z10.string(),
|
|
767
835
|
count: z10.number().int().min(0)
|
|
768
|
-
}))
|
|
836
|
+
})),
|
|
837
|
+
retentionDays: realtimeConfigSchema.shape.retentionDays
|
|
769
838
|
});
|
|
770
839
|
var rlsPolicySchema = z10.object({
|
|
771
840
|
policyName: z10.string(),
|
|
@@ -845,6 +914,9 @@ var databasePasswordInfoSchema = z11.object({
|
|
|
845
914
|
var apiKeyResponseSchema = z11.object({
|
|
846
915
|
apiKey: z11.string()
|
|
847
916
|
});
|
|
917
|
+
var projectIdResponseSchema = z11.object({
|
|
918
|
+
projectId: z11.string().nullable()
|
|
919
|
+
});
|
|
848
920
|
|
|
849
921
|
// node_modules/@insforge/shared-schemas/dist/ai.schema.js
|
|
850
922
|
import { z as z12 } from "zod";
|
|
@@ -919,13 +991,83 @@ var audioContentSchema = z13.object({
|
|
|
919
991
|
format: z13.enum(["wav", "mp3", "aiff", "aac", "ogg", "flac", "m4a"])
|
|
920
992
|
})
|
|
921
993
|
});
|
|
922
|
-
var
|
|
994
|
+
var fileContentSchema = z13.object({
|
|
995
|
+
type: z13.literal("file"),
|
|
996
|
+
file: z13.object({
|
|
997
|
+
// Filename with extension (e.g., "document.pdf")
|
|
998
|
+
filename: z13.string(),
|
|
999
|
+
// File data can be:
|
|
1000
|
+
// - Public URL: "https://example.com/document.pdf"
|
|
1001
|
+
// - Base64 data URL: "data:application/pdf;base64,..."
|
|
1002
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1003
|
+
file_data: z13.string()
|
|
1004
|
+
})
|
|
1005
|
+
});
|
|
1006
|
+
var contentSchema = z13.union([
|
|
1007
|
+
textContentSchema,
|
|
1008
|
+
imageContentSchema,
|
|
1009
|
+
audioContentSchema,
|
|
1010
|
+
fileContentSchema
|
|
1011
|
+
]);
|
|
1012
|
+
var toolFunctionSchema = z13.object({
|
|
1013
|
+
name: z13.string(),
|
|
1014
|
+
description: z13.string().optional(),
|
|
1015
|
+
parameters: z13.record(z13.unknown()).optional()
|
|
1016
|
+
});
|
|
1017
|
+
var toolSchema = z13.object({
|
|
1018
|
+
type: z13.literal("function"),
|
|
1019
|
+
function: toolFunctionSchema
|
|
1020
|
+
});
|
|
1021
|
+
var toolChoiceSchema = z13.union([
|
|
1022
|
+
z13.enum(["auto", "none", "required"]),
|
|
1023
|
+
z13.object({
|
|
1024
|
+
type: z13.literal("function"),
|
|
1025
|
+
function: z13.object({ name: z13.string() })
|
|
1026
|
+
})
|
|
1027
|
+
]);
|
|
1028
|
+
var toolCallSchema = z13.object({
|
|
1029
|
+
id: z13.string(),
|
|
1030
|
+
type: z13.literal("function"),
|
|
1031
|
+
function: z13.object({
|
|
1032
|
+
name: z13.string(),
|
|
1033
|
+
arguments: z13.string()
|
|
1034
|
+
})
|
|
1035
|
+
});
|
|
923
1036
|
var chatMessageSchema = z13.object({
|
|
924
|
-
role: z13.enum(["user", "assistant", "system"]),
|
|
1037
|
+
role: z13.enum(["user", "assistant", "system", "tool"]),
|
|
925
1038
|
// New format: content can be string or array of content parts (OpenAI-compatible)
|
|
926
|
-
content: z13.union([z13.string(), z13.array(contentSchema)]),
|
|
1039
|
+
content: z13.union([z13.string(), z13.array(contentSchema)]).nullable(),
|
|
927
1040
|
// Legacy format: separate images field (deprecated but supported for backward compatibility)
|
|
928
|
-
images: z13.array(z13.object({ url: z13.string() })).optional()
|
|
1041
|
+
images: z13.array(z13.object({ url: z13.string() })).optional(),
|
|
1042
|
+
// Tool calls made by the assistant
|
|
1043
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1044
|
+
tool_calls: z13.array(toolCallSchema).optional(),
|
|
1045
|
+
// Tool call ID for tool response messages
|
|
1046
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1047
|
+
tool_call_id: z13.string().optional()
|
|
1048
|
+
});
|
|
1049
|
+
var webSearchPluginSchema = z13.object({
|
|
1050
|
+
enabled: z13.boolean(),
|
|
1051
|
+
// Engine selection:
|
|
1052
|
+
// - "native": Always use provider's built-in web search (OpenAI, Anthropic, Perplexity, xAI)
|
|
1053
|
+
// - "exa": Use Exa's search API
|
|
1054
|
+
// - undefined: Auto-select (native if available, otherwise Exa)
|
|
1055
|
+
engine: z13.enum(["native", "exa"]).optional(),
|
|
1056
|
+
// Maximum number of search results (1-10, default: 5)
|
|
1057
|
+
maxResults: z13.number().min(1).max(10).optional(),
|
|
1058
|
+
// Custom prompt for attaching search results to the message
|
|
1059
|
+
searchPrompt: z13.string().optional()
|
|
1060
|
+
});
|
|
1061
|
+
var fileParserPluginSchema = z13.object({
|
|
1062
|
+
enabled: z13.boolean(),
|
|
1063
|
+
pdf: z13.object({
|
|
1064
|
+
// PDF processing engine:
|
|
1065
|
+
// - "pdf-text": Best for well-structured PDFs with clear text content (Free)
|
|
1066
|
+
// - "mistral-ocr": Best for scanned documents or PDFs with images ($2 per 1,000 pages)
|
|
1067
|
+
// - "native": Only available for models that support file input natively (charged as input tokens)
|
|
1068
|
+
// If not specified, defaults to native if available, otherwise mistral-ocr
|
|
1069
|
+
engine: z13.enum(["pdf-text", "mistral-ocr", "native"]).optional()
|
|
1070
|
+
}).optional()
|
|
929
1071
|
});
|
|
930
1072
|
var chatCompletionRequestSchema = z13.object({
|
|
931
1073
|
model: z13.string(),
|
|
@@ -933,10 +1075,52 @@ var chatCompletionRequestSchema = z13.object({
|
|
|
933
1075
|
temperature: z13.number().min(0).max(2).optional(),
|
|
934
1076
|
maxTokens: z13.number().positive().optional(),
|
|
935
1077
|
topP: z13.number().min(0).max(1).optional(),
|
|
936
|
-
stream: z13.boolean().optional()
|
|
1078
|
+
stream: z13.boolean().optional(),
|
|
1079
|
+
// Web Search: Incorporate relevant web search results into the response
|
|
1080
|
+
// Results are returned in the annotations field
|
|
1081
|
+
webSearch: webSearchPluginSchema.optional(),
|
|
1082
|
+
// File Parser: Configure PDF processing for file content in messages
|
|
1083
|
+
// When files are included in messages, this controls how PDFs are parsed
|
|
1084
|
+
fileParser: fileParserPluginSchema.optional(),
|
|
1085
|
+
// Thinking/Reasoning mode: Enable extended reasoning capabilities
|
|
1086
|
+
// Appends ":thinking" to the model ID for chain-of-thought reasoning
|
|
1087
|
+
thinking: z13.boolean().optional(),
|
|
1088
|
+
// Tool calling: Define functions the AI can call
|
|
1089
|
+
tools: z13.array(toolSchema).optional(),
|
|
1090
|
+
// Tool choice: Control whether/which tool is called ('auto', 'none', 'required', or specific function)
|
|
1091
|
+
toolChoice: toolChoiceSchema.optional(),
|
|
1092
|
+
// Parallel tool calls: Allow the model to call multiple tools in parallel
|
|
1093
|
+
parallelToolCalls: z13.boolean().optional()
|
|
1094
|
+
});
|
|
1095
|
+
var urlCitationAnnotationSchema = z13.object({
|
|
1096
|
+
type: z13.literal("url_citation"),
|
|
1097
|
+
urlCitation: z13.object({
|
|
1098
|
+
url: z13.string(),
|
|
1099
|
+
title: z13.string().optional(),
|
|
1100
|
+
content: z13.string().optional(),
|
|
1101
|
+
// Character indices in the response text where this citation applies
|
|
1102
|
+
startIndex: z13.number().optional(),
|
|
1103
|
+
endIndex: z13.number().optional()
|
|
1104
|
+
})
|
|
1105
|
+
});
|
|
1106
|
+
var fileAnnotationSchema = z13.object({
|
|
1107
|
+
type: z13.literal("file"),
|
|
1108
|
+
file: z13.object({
|
|
1109
|
+
filename: z13.string(),
|
|
1110
|
+
// Parsed content from the PDF (used for caching)
|
|
1111
|
+
parsedContent: z13.string().optional(),
|
|
1112
|
+
// Additional metadata from the parser
|
|
1113
|
+
metadata: z13.record(z13.unknown()).optional()
|
|
1114
|
+
})
|
|
937
1115
|
});
|
|
1116
|
+
var annotationSchema = z13.union([urlCitationAnnotationSchema, fileAnnotationSchema]);
|
|
938
1117
|
var chatCompletionResponseSchema = z13.object({
|
|
939
1118
|
text: z13.string(),
|
|
1119
|
+
// Tool calls from the assistant (present when the model invokes tools)
|
|
1120
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1121
|
+
tool_calls: z13.array(toolCallSchema).optional(),
|
|
1122
|
+
// Annotations from web search or file parsing (can be URL citations or file annotations)
|
|
1123
|
+
annotations: z13.array(annotationSchema).optional(),
|
|
940
1124
|
metadata: z13.object({
|
|
941
1125
|
model: z13.string(),
|
|
942
1126
|
usage: z13.object({
|
|
@@ -946,6 +1130,30 @@ var chatCompletionResponseSchema = z13.object({
|
|
|
946
1130
|
}).optional()
|
|
947
1131
|
}).optional()
|
|
948
1132
|
});
|
|
1133
|
+
var embeddingsRequestSchema = z13.object({
|
|
1134
|
+
model: z13.string(),
|
|
1135
|
+
input: z13.union([z13.string(), z13.array(z13.string())]),
|
|
1136
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1137
|
+
encoding_format: z13.enum(["float", "base64"]).optional(),
|
|
1138
|
+
dimensions: z13.number().int().min(0).optional()
|
|
1139
|
+
});
|
|
1140
|
+
var embeddingObjectSchema = z13.object({
|
|
1141
|
+
object: z13.literal("embedding"),
|
|
1142
|
+
// Embedding can be number[] (float format) or string (base64 format)
|
|
1143
|
+
embedding: z13.union([z13.array(z13.number()), z13.string()]),
|
|
1144
|
+
index: z13.number()
|
|
1145
|
+
});
|
|
1146
|
+
var embeddingsResponseSchema = z13.object({
|
|
1147
|
+
object: z13.literal("list"),
|
|
1148
|
+
data: z13.array(embeddingObjectSchema),
|
|
1149
|
+
metadata: z13.object({
|
|
1150
|
+
model: z13.string(),
|
|
1151
|
+
usage: z13.object({
|
|
1152
|
+
promptTokens: z13.number().optional(),
|
|
1153
|
+
totalTokens: z13.number().optional()
|
|
1154
|
+
}).optional()
|
|
1155
|
+
}).optional()
|
|
1156
|
+
});
|
|
949
1157
|
var imageGenerationRequestSchema = z13.object({
|
|
950
1158
|
model: z13.string(),
|
|
951
1159
|
prompt: z13.string(),
|
|
@@ -974,7 +1182,10 @@ var aiModelSchema = z13.object({
|
|
|
974
1182
|
outputModality: z13.array(modalitySchema).min(1),
|
|
975
1183
|
provider: z13.string(),
|
|
976
1184
|
modelId: z13.string(),
|
|
977
|
-
|
|
1185
|
+
inputPrice: z13.number().min(0).optional(),
|
|
1186
|
+
// Price per million tokens in USD
|
|
1187
|
+
outputPrice: z13.number().min(0).optional()
|
|
1188
|
+
// Price per million tokens in USD
|
|
978
1189
|
});
|
|
979
1190
|
var createAIConfigurationRequestSchema = aiConfigurationSchema.omit({
|
|
980
1191
|
id: true
|
|
@@ -997,6 +1208,15 @@ var getAIUsageSummaryRequestSchema = z13.object({
|
|
|
997
1208
|
startDate: z13.string().datetime().optional(),
|
|
998
1209
|
endDate: z13.string().datetime().optional()
|
|
999
1210
|
});
|
|
1211
|
+
var keySourceSchema = z13.enum(["byok", "cloud", "env", "unconfigured"]);
|
|
1212
|
+
var gatewayConfigResponseSchema = z13.object({
|
|
1213
|
+
keySource: keySourceSchema,
|
|
1214
|
+
hasByokKey: z13.boolean(),
|
|
1215
|
+
maskedKey: z13.string().optional()
|
|
1216
|
+
});
|
|
1217
|
+
var setGatewayBYOKKeyRequestSchema = z13.object({
|
|
1218
|
+
apiKey: z13.string().min(1, "API key is required")
|
|
1219
|
+
});
|
|
1000
1220
|
|
|
1001
1221
|
// node_modules/@insforge/shared-schemas/dist/logs.schema.js
|
|
1002
1222
|
import { z as z14 } from "zod";
|
|
@@ -1027,6 +1247,16 @@ var logStatsSchema = z14.object({
|
|
|
1027
1247
|
count: z14.number(),
|
|
1028
1248
|
lastActivity: z14.string()
|
|
1029
1249
|
});
|
|
1250
|
+
var buildLogEntrySchema = z14.object({
|
|
1251
|
+
level: z14.string(),
|
|
1252
|
+
message: z14.string()
|
|
1253
|
+
});
|
|
1254
|
+
var getBuildLogsResponseSchema = z14.object({
|
|
1255
|
+
deploymentId: z14.string(),
|
|
1256
|
+
status: z14.enum(["pending", "success", "failed"]),
|
|
1257
|
+
logs: z14.array(buildLogEntrySchema),
|
|
1258
|
+
createdAt: z14.string()
|
|
1259
|
+
});
|
|
1030
1260
|
|
|
1031
1261
|
// node_modules/@insforge/shared-schemas/dist/logs-api.schema.js
|
|
1032
1262
|
import { z as z15 } from "zod";
|
|
@@ -1102,7 +1332,19 @@ var listFunctionsResponseSchema = z17.object({
|
|
|
1102
1332
|
functions: z17.array(functionSchema),
|
|
1103
1333
|
runtime: z17.object({
|
|
1104
1334
|
status: z17.enum(["running", "unavailable"])
|
|
1105
|
-
})
|
|
1335
|
+
}),
|
|
1336
|
+
deploymentUrl: z17.string().nullable().optional()
|
|
1337
|
+
});
|
|
1338
|
+
var deploymentResultSchema = z17.object({
|
|
1339
|
+
id: z17.string(),
|
|
1340
|
+
status: z17.enum(["success", "failed"]),
|
|
1341
|
+
url: z17.string().nullable(),
|
|
1342
|
+
buildLogs: z17.array(z17.string()).optional()
|
|
1343
|
+
});
|
|
1344
|
+
var functionResponseSchema = z17.object({
|
|
1345
|
+
success: z17.boolean(),
|
|
1346
|
+
function: functionSchema,
|
|
1347
|
+
deployment: deploymentResultSchema.nullable().optional()
|
|
1106
1348
|
});
|
|
1107
1349
|
|
|
1108
1350
|
// node_modules/@insforge/shared-schemas/dist/cloud-events.schema.js
|
|
@@ -1142,6 +1384,9 @@ var showContactModalEventSchema = z18.object({
|
|
|
1142
1384
|
var showConnectOverlayEventSchema = z18.object({
|
|
1143
1385
|
type: z18.literal("SHOW_CONNECT_OVERLAY")
|
|
1144
1386
|
});
|
|
1387
|
+
var showPlanModalEventSchema = z18.object({
|
|
1388
|
+
type: z18.literal("SHOW_PLAN_MODAL")
|
|
1389
|
+
});
|
|
1145
1390
|
var authorizationCodeEventSchema = z18.object({
|
|
1146
1391
|
type: z18.literal("AUTHORIZATION_CODE"),
|
|
1147
1392
|
code: z18.string()
|
|
@@ -1150,6 +1395,51 @@ var routeChangeEventSchema = z18.object({
|
|
|
1150
1395
|
type: z18.literal("ROUTE_CHANGE"),
|
|
1151
1396
|
path: z18.string()
|
|
1152
1397
|
});
|
|
1398
|
+
var requestProjectInfoEventSchema = z18.object({
|
|
1399
|
+
type: z18.literal("REQUEST_PROJECT_INFO")
|
|
1400
|
+
});
|
|
1401
|
+
var projectInfoEventSchema = z18.object({
|
|
1402
|
+
type: z18.literal("PROJECT_INFO"),
|
|
1403
|
+
name: z18.string(),
|
|
1404
|
+
instanceType: z18.string(),
|
|
1405
|
+
region: z18.string(),
|
|
1406
|
+
latestVersion: z18.string().optional()
|
|
1407
|
+
});
|
|
1408
|
+
var requestInstanceInfoEventSchema = z18.object({
|
|
1409
|
+
type: z18.literal("REQUEST_INSTANCE_INFO")
|
|
1410
|
+
});
|
|
1411
|
+
var instanceInfoEventSchema = z18.object({
|
|
1412
|
+
type: z18.literal("INSTANCE_INFO"),
|
|
1413
|
+
currentInstanceType: z18.string(),
|
|
1414
|
+
planName: z18.string(),
|
|
1415
|
+
computeCredits: z18.number(),
|
|
1416
|
+
currentOrgComputeCost: z18.number(),
|
|
1417
|
+
instanceTypes: z18.array(z18.object({
|
|
1418
|
+
id: z18.string(),
|
|
1419
|
+
name: z18.string(),
|
|
1420
|
+
cpu: z18.string(),
|
|
1421
|
+
ram: z18.string(),
|
|
1422
|
+
pricePerHour: z18.number(),
|
|
1423
|
+
pricePerMonth: z18.number()
|
|
1424
|
+
})),
|
|
1425
|
+
projects: z18.array(z18.object({
|
|
1426
|
+
name: z18.string(),
|
|
1427
|
+
instanceType: z18.string(),
|
|
1428
|
+
monthlyCost: z18.number(),
|
|
1429
|
+
isCurrent: z18.boolean(),
|
|
1430
|
+
status: z18.string()
|
|
1431
|
+
}))
|
|
1432
|
+
});
|
|
1433
|
+
var requestInstanceTypeChangeEventSchema = z18.object({
|
|
1434
|
+
type: z18.literal("REQUEST_INSTANCE_TYPE_CHANGE"),
|
|
1435
|
+
instanceType: z18.string()
|
|
1436
|
+
});
|
|
1437
|
+
var instanceTypeChangeResultEventSchema = z18.object({
|
|
1438
|
+
type: z18.literal("INSTANCE_TYPE_CHANGE_RESULT"),
|
|
1439
|
+
success: z18.boolean(),
|
|
1440
|
+
instanceType: z18.string().optional(),
|
|
1441
|
+
error: z18.string().optional()
|
|
1442
|
+
});
|
|
1153
1443
|
var cloudEventSchema = z18.discriminatedUnion("type", [
|
|
1154
1444
|
appRouteChangeEventSchema,
|
|
1155
1445
|
authSuccessEventSchema,
|
|
@@ -1161,8 +1451,15 @@ var cloudEventSchema = z18.discriminatedUnion("type", [
|
|
|
1161
1451
|
navigateToUsageSchema,
|
|
1162
1452
|
showContactModalEventSchema,
|
|
1163
1453
|
showConnectOverlayEventSchema,
|
|
1454
|
+
showPlanModalEventSchema,
|
|
1164
1455
|
authorizationCodeEventSchema,
|
|
1165
|
-
routeChangeEventSchema
|
|
1456
|
+
routeChangeEventSchema,
|
|
1457
|
+
requestProjectInfoEventSchema,
|
|
1458
|
+
projectInfoEventSchema,
|
|
1459
|
+
requestInstanceInfoEventSchema,
|
|
1460
|
+
instanceInfoEventSchema,
|
|
1461
|
+
requestInstanceTypeChangeEventSchema,
|
|
1462
|
+
instanceTypeChangeResultEventSchema
|
|
1166
1463
|
]);
|
|
1167
1464
|
|
|
1168
1465
|
// node_modules/@insforge/shared-schemas/dist/docs.schema.js
|
|
@@ -1198,8 +1495,6 @@ var docTypeSchema = z19.enum([
|
|
|
1198
1495
|
"storage-sdk",
|
|
1199
1496
|
"functions-sdk",
|
|
1200
1497
|
"ai-integration-sdk",
|
|
1201
|
-
"auth-components-react",
|
|
1202
|
-
"auth-components-nextjs",
|
|
1203
1498
|
"real-time",
|
|
1204
1499
|
"deployment"
|
|
1205
1500
|
]).describe(`
|
|
@@ -1209,8 +1504,6 @@ var docTypeSchema = z19.enum([
|
|
|
1209
1504
|
"storage-sdk" (file storage),
|
|
1210
1505
|
"functions-sdk" (edge functions),
|
|
1211
1506
|
"auth-sdk" (direct SDK methods for custom auth flows),
|
|
1212
|
-
"auth-components-react" (authentication components for React+Vite applications),
|
|
1213
|
-
"auth-components-nextjs" (authentication components for Next.js applications),
|
|
1214
1507
|
"ai-integration-sdk" (AI features),
|
|
1215
1508
|
"real-time" (real-time pub/sub through WebSockets),
|
|
1216
1509
|
"deployment" (deploy frontend applications via MCP tool)
|
|
@@ -1295,110 +1588,182 @@ var listDeploymentsResponseSchema = z22.object({
|
|
|
1295
1588
|
total: z22.number()
|
|
1296
1589
|
})
|
|
1297
1590
|
});
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
//
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
};
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
}
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
return false;
|
|
1337
|
-
}
|
|
1338
|
-
return true;
|
|
1339
|
-
}
|
|
1340
|
-
async function fetchBackendVersion(apiBaseUrl) {
|
|
1341
|
-
const response = await fetch2(`${apiBaseUrl}/api/health`, {
|
|
1342
|
-
method: "GET",
|
|
1343
|
-
headers: {
|
|
1344
|
-
"Content-Type": "application/json"
|
|
1591
|
+
var deploymentEnvVarSchema = z22.object({
|
|
1592
|
+
id: z22.string(),
|
|
1593
|
+
// Vercel env var ID (needed for delete/get)
|
|
1594
|
+
key: z22.string(),
|
|
1595
|
+
type: z22.enum(["plain", "encrypted", "secret", "sensitive", "system"]),
|
|
1596
|
+
updatedAt: z22.number().optional()
|
|
1597
|
+
// Unix timestamp (milliseconds)
|
|
1598
|
+
});
|
|
1599
|
+
var deploymentEnvVarWithValueSchema = z22.object({
|
|
1600
|
+
id: z22.string(),
|
|
1601
|
+
key: z22.string(),
|
|
1602
|
+
value: z22.string(),
|
|
1603
|
+
type: z22.enum(["plain", "encrypted", "secret", "sensitive", "system"]),
|
|
1604
|
+
updatedAt: z22.number().optional()
|
|
1605
|
+
});
|
|
1606
|
+
var listEnvVarsResponseSchema = z22.object({
|
|
1607
|
+
envVars: z22.array(deploymentEnvVarSchema)
|
|
1608
|
+
});
|
|
1609
|
+
var getEnvVarResponseSchema = z22.object({
|
|
1610
|
+
envVar: deploymentEnvVarWithValueSchema
|
|
1611
|
+
});
|
|
1612
|
+
var upsertEnvVarRequestSchema = z22.object({
|
|
1613
|
+
key: z22.string().trim().min(1, "key is required"),
|
|
1614
|
+
value: z22.string()
|
|
1615
|
+
});
|
|
1616
|
+
var upsertEnvVarsRequestSchema = z22.object({
|
|
1617
|
+
envVars: z22.array(upsertEnvVarRequestSchema).min(1)
|
|
1618
|
+
}).superRefine(({ envVars }, ctx) => {
|
|
1619
|
+
const firstSeenByKey = /* @__PURE__ */ new Map();
|
|
1620
|
+
envVars.forEach((envVar, index) => {
|
|
1621
|
+
const existingIndex = firstSeenByKey.get(envVar.key);
|
|
1622
|
+
if (existingIndex !== void 0) {
|
|
1623
|
+
ctx.addIssue({
|
|
1624
|
+
code: z22.ZodIssueCode.custom,
|
|
1625
|
+
message: "duplicate environment variable key",
|
|
1626
|
+
path: ["envVars", index, "key"]
|
|
1627
|
+
});
|
|
1628
|
+
return;
|
|
1345
1629
|
}
|
|
1630
|
+
firstSeenByKey.set(envVar.key, index);
|
|
1346
1631
|
});
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1632
|
+
});
|
|
1633
|
+
var upsertEnvVarResponseSchema = z22.object({
|
|
1634
|
+
success: z22.literal(true),
|
|
1635
|
+
message: z22.string()
|
|
1636
|
+
});
|
|
1637
|
+
var upsertEnvVarsResponseSchema = z22.object({
|
|
1638
|
+
success: z22.literal(true),
|
|
1639
|
+
message: z22.string(),
|
|
1640
|
+
count: z22.number().int().positive()
|
|
1641
|
+
});
|
|
1642
|
+
var deleteEnvVarResponseSchema = z22.object({
|
|
1643
|
+
success: z22.literal(true),
|
|
1644
|
+
message: z22.string()
|
|
1645
|
+
});
|
|
1646
|
+
var updateSlugRequestSchema = z22.object({
|
|
1647
|
+
slug: z22.string().trim().min(3, "slug must be at least 3 characters").max(63, "slug must be at most 63 characters").regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/, "slug must be lowercase alphanumeric with hyphens, not starting or ending with hyphen").nullable()
|
|
1648
|
+
});
|
|
1649
|
+
var updateSlugResponseSchema = z22.object({
|
|
1650
|
+
success: z22.boolean(),
|
|
1651
|
+
slug: z22.string().nullable(),
|
|
1652
|
+
domain: z22.string().nullable()
|
|
1653
|
+
});
|
|
1654
|
+
var deploymentMetadataResponseSchema = z22.object({
|
|
1655
|
+
currentDeploymentId: z22.string().uuid().nullable(),
|
|
1656
|
+
defaultDomainUrl: z22.string().nullable(),
|
|
1657
|
+
customDomainUrl: z22.string().nullable()
|
|
1658
|
+
});
|
|
1659
|
+
var domainVerificationRecordSchema = z22.object({
|
|
1660
|
+
type: z22.string(),
|
|
1661
|
+
domain: z22.string(),
|
|
1662
|
+
value: z22.string()
|
|
1663
|
+
});
|
|
1664
|
+
var customDomainSchema = z22.object({
|
|
1665
|
+
domain: z22.string(),
|
|
1666
|
+
apexDomain: z22.string(),
|
|
1667
|
+
verified: z22.boolean(),
|
|
1668
|
+
misconfigured: z22.boolean(),
|
|
1669
|
+
verification: z22.array(domainVerificationRecordSchema),
|
|
1670
|
+
cnameTarget: z22.string().nullable(),
|
|
1671
|
+
aRecordValue: z22.string().nullable()
|
|
1672
|
+
});
|
|
1673
|
+
var addCustomDomainRequestSchema = z22.object({
|
|
1674
|
+
domain: z22.string().trim().min(1, "Domain is required").regex(/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,}$/i, "Invalid domain format (e.g. myapp.com or www.myapp.com)").refine((domain) => !domain.toLowerCase().endsWith(".insforge.site"), {
|
|
1675
|
+
message: "Domains ending with .insforge.site are reserved by InsForge"
|
|
1676
|
+
})
|
|
1677
|
+
});
|
|
1678
|
+
var listCustomDomainsResponseSchema = z22.object({
|
|
1679
|
+
domains: z22.array(customDomainSchema)
|
|
1680
|
+
});
|
|
1681
|
+
|
|
1682
|
+
// node_modules/@insforge/shared-schemas/dist/schedules.schema.js
|
|
1683
|
+
import { z as z23 } from "zod";
|
|
1684
|
+
var scheduleSchema = z23.object({
|
|
1685
|
+
id: z23.string().uuid(),
|
|
1686
|
+
name: z23.string(),
|
|
1687
|
+
cronSchedule: z23.string(),
|
|
1688
|
+
functionUrl: z23.string().url(),
|
|
1689
|
+
httpMethod: z23.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]),
|
|
1690
|
+
// Optional HTTP headers to include when invoking the scheduled function
|
|
1691
|
+
headers: z23.record(z23.string()).nullable(),
|
|
1692
|
+
// Body payload for the scheduled invocation. Can be a JSON object or a raw string.
|
|
1693
|
+
body: z23.union([z23.string(), z23.record(z23.unknown())]).nullable(),
|
|
1694
|
+
// cron_job_id is a BIGINT in postgres, which node-pg returns as a string.
|
|
1695
|
+
cronJobId: z23.string().nullable(),
|
|
1696
|
+
lastExecutedAt: z23.string().datetime().nullable(),
|
|
1697
|
+
// Whether the cron job is currently active (has a scheduled cron job)
|
|
1698
|
+
isActive: z23.boolean().default(true),
|
|
1699
|
+
// Next scheduled run time in ISO format (nullable if cron expression invalid)
|
|
1700
|
+
nextRun: z23.string().datetime().nullable(),
|
|
1701
|
+
createdAt: z23.string().datetime(),
|
|
1702
|
+
updatedAt: z23.string().datetime()
|
|
1703
|
+
});
|
|
1704
|
+
var scheduleLogSchema = z23.object({
|
|
1705
|
+
id: z23.string().uuid(),
|
|
1706
|
+
scheduleId: z23.string().uuid(),
|
|
1707
|
+
executedAt: z23.string().datetime(),
|
|
1708
|
+
statusCode: z23.number().int(),
|
|
1709
|
+
success: z23.boolean(),
|
|
1710
|
+
durationMs: z23.number().int(),
|
|
1711
|
+
message: z23.string().nullable()
|
|
1712
|
+
});
|
|
1713
|
+
|
|
1714
|
+
// node_modules/@insforge/shared-schemas/dist/schedules-api.schema.js
|
|
1715
|
+
import { z as z24 } from "zod";
|
|
1716
|
+
var cronScheduleSchema = z24.string().refine((value) => {
|
|
1717
|
+
const parts = value.split(" ");
|
|
1718
|
+
return parts.length === 5 || parts.length === 6;
|
|
1719
|
+
}, { message: 'Invalid cron schedule format. Use 5 or 6 parts (e.g., "* * * * *").' });
|
|
1720
|
+
var createScheduleRequestSchema = z24.object({
|
|
1721
|
+
name: z24.string().min(3, "Schedule name must be at least 3 characters long"),
|
|
1722
|
+
cronSchedule: cronScheduleSchema,
|
|
1723
|
+
functionUrl: z24.string().url("The function URL must be a valid URL."),
|
|
1724
|
+
httpMethod: z24.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]),
|
|
1725
|
+
headers: z24.record(z24.string()).optional().describe("Header values can reference secrets using ${{secrets.KEY_NAME}} syntax."),
|
|
1726
|
+
body: z24.record(z24.unknown()).optional().describe("The JSON body to send with the request.")
|
|
1727
|
+
});
|
|
1728
|
+
var updateScheduleRequestSchema = z24.object({
|
|
1729
|
+
name: z24.string().min(3, "Schedule name must be at least 3 characters long").optional(),
|
|
1730
|
+
cronSchedule: cronScheduleSchema.optional(),
|
|
1731
|
+
functionUrl: z24.string().url("The function URL must be a valid URL.").optional(),
|
|
1732
|
+
httpMethod: z24.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]).optional(),
|
|
1733
|
+
headers: z24.record(z24.string()).optional().describe("Header values can reference secrets using ${{secrets.KEY_NAME}} syntax."),
|
|
1734
|
+
body: z24.record(z24.unknown()).optional().describe("The JSON body to send with the request."),
|
|
1735
|
+
isActive: z24.boolean().optional().describe("Enable or disable the schedule.")
|
|
1736
|
+
});
|
|
1737
|
+
var listSchedulesResponseSchema = z24.array(scheduleSchema);
|
|
1738
|
+
var executionLogResponseSchema = scheduleLogSchema;
|
|
1739
|
+
var listExecutionLogsResponseSchema = z24.object({
|
|
1740
|
+
logs: z24.array(executionLogResponseSchema),
|
|
1741
|
+
totalCount: z24.number().int().nonnegative(),
|
|
1742
|
+
limit: z24.number().int().positive(),
|
|
1743
|
+
offset: z24.number().int().nonnegative()
|
|
1744
|
+
});
|
|
1745
|
+
var createScheduleResponseSchema = z24.object({
|
|
1746
|
+
id: z24.string().uuid(),
|
|
1747
|
+
cronJobId: z24.string(),
|
|
1748
|
+
message: z24.string()
|
|
1749
|
+
});
|
|
1750
|
+
var updateScheduleResponseSchema = z24.object({
|
|
1751
|
+
id: z24.string().uuid(),
|
|
1752
|
+
cronJobId: z24.string().optional(),
|
|
1753
|
+
message: z24.string()
|
|
1754
|
+
});
|
|
1755
|
+
var deleteScheduleResponseSchema = z24.object({
|
|
1756
|
+
message: z24.string()
|
|
1757
|
+
});
|
|
1758
|
+
|
|
1759
|
+
// src/shared/tools/docs.ts
|
|
1760
|
+
function registerDocsTools(ctx) {
|
|
1761
|
+
const { API_BASE_URL, registerTool, withUsageTracking, getApiKey, addBackgroundContext } = ctx;
|
|
1395
1762
|
const fetchDocumentation = async (docType) => {
|
|
1396
1763
|
try {
|
|
1397
1764
|
const response = await fetch2(`${API_BASE_URL}/api/docs/${docType}`, {
|
|
1398
1765
|
method: "GET",
|
|
1399
|
-
headers: {
|
|
1400
|
-
"Content-Type": "application/json"
|
|
1401
|
-
}
|
|
1766
|
+
headers: { "Content-Type": "application/json" }
|
|
1402
1767
|
});
|
|
1403
1768
|
if (response.status === 404) {
|
|
1404
1769
|
throw new Error("Documentation not found. This feature may not be supported in your project version. Please contact the Insforge team for assistance.");
|
|
@@ -1414,16 +1779,14 @@ async function registerInsforgeTools(server, config = {}) {
|
|
|
1414
1779
|
throw new Error("Invalid response format from documentation endpoint");
|
|
1415
1780
|
} catch (error) {
|
|
1416
1781
|
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
1417
|
-
throw new Error(`Unable to retrieve ${docType} documentation: ${errMsg}
|
|
1782
|
+
throw new Error(`Unable to retrieve ${docType} documentation: ${errMsg}`, { cause: error });
|
|
1418
1783
|
}
|
|
1419
1784
|
};
|
|
1420
1785
|
const fetchSDKDocumentation = async (feature, language) => {
|
|
1421
1786
|
try {
|
|
1422
1787
|
const response = await fetch2(`${API_BASE_URL}/api/docs/${feature}/${language}`, {
|
|
1423
1788
|
method: "GET",
|
|
1424
|
-
headers: {
|
|
1425
|
-
"Content-Type": "application/json"
|
|
1426
|
-
}
|
|
1789
|
+
headers: { "Content-Type": "application/json" }
|
|
1427
1790
|
});
|
|
1428
1791
|
if (response.status === 404) {
|
|
1429
1792
|
throw new Error("Documentation not found. This feature may not be supported in your project version. Please contact the Insforge team for assistance.");
|
|
@@ -1439,50 +1802,18 @@ async function registerInsforgeTools(server, config = {}) {
|
|
|
1439
1802
|
throw new Error("Invalid response format from documentation endpoint");
|
|
1440
1803
|
} catch (error) {
|
|
1441
1804
|
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
1442
|
-
throw new Error(`Unable to retrieve ${feature}-${language} documentation: ${errMsg}
|
|
1443
|
-
}
|
|
1444
|
-
};
|
|
1445
|
-
const fetchInsforgeInstructionsContext = async () => {
|
|
1446
|
-
try {
|
|
1447
|
-
return await fetchDocumentation("instructions");
|
|
1448
|
-
} catch (error) {
|
|
1449
|
-
console.error("Failed to fetch insforge-instructions.md:", error);
|
|
1450
|
-
return null;
|
|
1451
|
-
}
|
|
1452
|
-
};
|
|
1453
|
-
const addBackgroundContext = async (response) => {
|
|
1454
|
-
const isLegacyVersion = compareVersions(backendVersion, "1.1.7") < 0;
|
|
1455
|
-
if (isLegacyVersion) {
|
|
1456
|
-
const context = await fetchInsforgeInstructionsContext();
|
|
1457
|
-
if (context && response.content && Array.isArray(response.content)) {
|
|
1458
|
-
response.content.push({
|
|
1459
|
-
type: "text",
|
|
1460
|
-
text: `
|
|
1461
|
-
|
|
1462
|
-
---
|
|
1463
|
-
\u{1F527} INSFORGE DEVELOPMENT RULES (Auto-loaded):
|
|
1464
|
-
${context}`
|
|
1465
|
-
});
|
|
1466
|
-
}
|
|
1805
|
+
throw new Error(`Unable to retrieve ${feature}-${language} documentation: ${errMsg}`, { cause: error });
|
|
1467
1806
|
}
|
|
1468
|
-
return response;
|
|
1469
1807
|
};
|
|
1470
1808
|
registerTool(
|
|
1471
1809
|
"fetch-docs",
|
|
1472
1810
|
'Fetch Insforge documentation. Use "instructions" for essential backend setup (MANDATORY FIRST), or select specific SDK docs for database, auth, storage, functions, or AI integration.',
|
|
1473
|
-
{
|
|
1474
|
-
docType: docTypeSchema
|
|
1475
|
-
},
|
|
1811
|
+
{ docType: docTypeSchema },
|
|
1476
1812
|
withUsageTracking("fetch-docs", async ({ docType }) => {
|
|
1477
1813
|
try {
|
|
1478
1814
|
const content = await fetchDocumentation(docType);
|
|
1479
1815
|
return await addBackgroundContext({
|
|
1480
|
-
content: [
|
|
1481
|
-
{
|
|
1482
|
-
type: "text",
|
|
1483
|
-
text: content
|
|
1484
|
-
}
|
|
1485
|
-
]
|
|
1816
|
+
content: [{ type: "text", text: content }]
|
|
1486
1817
|
});
|
|
1487
1818
|
} catch (error) {
|
|
1488
1819
|
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
@@ -1495,7 +1826,8 @@ ${context}`
|
|
|
1495
1826
|
};
|
|
1496
1827
|
}
|
|
1497
1828
|
return {
|
|
1498
|
-
content: [{ type: "text", text: `Error fetching ${docType} documentation: ${errMsg}` }]
|
|
1829
|
+
content: [{ type: "text", text: `Error fetching ${docType} documentation: ${errMsg}` }],
|
|
1830
|
+
isError: true
|
|
1499
1831
|
};
|
|
1500
1832
|
}
|
|
1501
1833
|
})
|
|
@@ -1506,20 +1838,12 @@ ${context}`
|
|
|
1506
1838
|
|
|
1507
1839
|
Supported features: ${sdkFeatureSchema.options.join(", ")}
|
|
1508
1840
|
Supported languages: ${sdkLanguageSchema.options.join(", ")}`,
|
|
1509
|
-
{
|
|
1510
|
-
sdkFeature: sdkFeatureSchema,
|
|
1511
|
-
sdkLanguage: sdkLanguageSchema
|
|
1512
|
-
},
|
|
1841
|
+
{ sdkFeature: sdkFeatureSchema, sdkLanguage: sdkLanguageSchema },
|
|
1513
1842
|
withUsageTracking("fetch-sdk-docs", async ({ sdkFeature, sdkLanguage }) => {
|
|
1514
1843
|
try {
|
|
1515
1844
|
const content = await fetchSDKDocumentation(sdkFeature, sdkLanguage);
|
|
1516
1845
|
return await addBackgroundContext({
|
|
1517
|
-
content: [
|
|
1518
|
-
{
|
|
1519
|
-
type: "text",
|
|
1520
|
-
text: content
|
|
1521
|
-
}
|
|
1522
|
-
]
|
|
1846
|
+
content: [{ type: "text", text: content }]
|
|
1523
1847
|
});
|
|
1524
1848
|
} catch (error) {
|
|
1525
1849
|
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
@@ -1532,7 +1856,8 @@ Supported languages: ${sdkLanguageSchema.options.join(", ")}`,
|
|
|
1532
1856
|
};
|
|
1533
1857
|
}
|
|
1534
1858
|
return {
|
|
1535
|
-
content: [{ type: "text", text: `Error fetching ${sdkFeature}-${sdkLanguage} documentation: ${errMsg}` }]
|
|
1859
|
+
content: [{ type: "text", text: `Error fetching ${sdkFeature}-${sdkLanguage} documentation: ${errMsg}` }],
|
|
1860
|
+
isError: true
|
|
1536
1861
|
};
|
|
1537
1862
|
}
|
|
1538
1863
|
})
|
|
@@ -1541,7 +1866,7 @@ Supported languages: ${sdkLanguageSchema.options.join(", ")}`,
|
|
|
1541
1866
|
"get-anon-key",
|
|
1542
1867
|
"Generate an anonymous JWT token that never expires. Requires admin API key. Use this for client-side applications that need public access.",
|
|
1543
1868
|
{
|
|
1544
|
-
apiKey:
|
|
1869
|
+
apiKey: z25.string().optional().describe("API key for authentication (optional if provided via --api_key)")
|
|
1545
1870
|
},
|
|
1546
1871
|
withUsageTracking("get-anon-key", async ({ apiKey }) => {
|
|
1547
1872
|
try {
|
|
@@ -1555,61 +1880,74 @@ Supported languages: ${sdkLanguageSchema.options.join(", ")}`,
|
|
|
1555
1880
|
});
|
|
1556
1881
|
const result = await handleApiResponse(response);
|
|
1557
1882
|
return await addBackgroundContext({
|
|
1558
|
-
content: [
|
|
1559
|
-
{
|
|
1560
|
-
type: "text",
|
|
1561
|
-
text: formatSuccessMessage("Anonymous token generated", result)
|
|
1562
|
-
}
|
|
1563
|
-
]
|
|
1883
|
+
content: [{ type: "text", text: formatSuccessMessage("Anonymous token generated", result) }]
|
|
1564
1884
|
});
|
|
1565
1885
|
} catch (error) {
|
|
1566
1886
|
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
1567
1887
|
return {
|
|
1568
|
-
content: [
|
|
1569
|
-
{
|
|
1570
|
-
type: "text",
|
|
1571
|
-
text: `Error generating anonymous token: ${errMsg}`
|
|
1572
|
-
}
|
|
1573
|
-
],
|
|
1888
|
+
content: [{ type: "text", text: `Error generating anonymous token: ${errMsg}` }],
|
|
1574
1889
|
isError: true
|
|
1575
1890
|
};
|
|
1576
1891
|
}
|
|
1577
1892
|
})
|
|
1578
1893
|
);
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1896
|
+
// src/shared/tools/database.ts
|
|
1897
|
+
import { z as z26 } from "zod";
|
|
1898
|
+
import fetch3 from "node-fetch";
|
|
1899
|
+
import { promises as fs } from "fs";
|
|
1900
|
+
import { execFile } from "child_process";
|
|
1901
|
+
import { promisify } from "util";
|
|
1902
|
+
import { tmpdir } from "os";
|
|
1903
|
+
import { join, basename } from "path";
|
|
1904
|
+
import FormData from "form-data";
|
|
1905
|
+
|
|
1906
|
+
// src/shared/tools/utils.ts
|
|
1907
|
+
var shellEsc = (s) => `'${s.replace(/'/g, "'\\''")}'`;
|
|
1908
|
+
|
|
1909
|
+
// src/shared/tools/database.ts
|
|
1910
|
+
var execFileAsync = promisify(execFile);
|
|
1911
|
+
function isAnonTokenResponse(obj) {
|
|
1912
|
+
return typeof obj === "object" && obj !== null && "accessToken" in obj && typeof obj.accessToken === "string" && obj.accessToken.length > 0;
|
|
1913
|
+
}
|
|
1914
|
+
function isBulkUpsertApiResult(obj) {
|
|
1915
|
+
if (typeof obj !== "object" || obj === null || !("success" in obj) || !("rowsAffected" in obj) || !("totalRecords" in obj) || !("table" in obj)) {
|
|
1916
|
+
return false;
|
|
1917
|
+
}
|
|
1918
|
+
const value = obj;
|
|
1919
|
+
if (typeof value.success !== "boolean" || typeof value.rowsAffected !== "number" || typeof value.totalRecords !== "number" || typeof value.table !== "string" || value.table.length === 0) {
|
|
1920
|
+
return false;
|
|
1921
|
+
}
|
|
1922
|
+
if (value.message !== void 0 && typeof value.message !== "string") {
|
|
1923
|
+
return false;
|
|
1924
|
+
}
|
|
1925
|
+
return true;
|
|
1926
|
+
}
|
|
1927
|
+
function registerDatabaseTools(ctx) {
|
|
1928
|
+
const { API_BASE_URL, isRemote, registerTool, withUsageTracking, getApiKey, addBackgroundContext } = ctx;
|
|
1579
1929
|
registerTool(
|
|
1580
1930
|
"get-table-schema",
|
|
1581
1931
|
"Returns the detailed schema(including RLS, indexes, constraints, etc.) of a specific table",
|
|
1582
1932
|
{
|
|
1583
|
-
apiKey:
|
|
1584
|
-
tableName:
|
|
1933
|
+
apiKey: z26.string().optional().describe("API key for authentication (optional if provided via --api_key)"),
|
|
1934
|
+
tableName: z26.string().describe("Name of the table")
|
|
1585
1935
|
},
|
|
1586
1936
|
withUsageTracking("get-table-schema", async ({ apiKey, tableName }) => {
|
|
1587
1937
|
try {
|
|
1588
1938
|
const actualApiKey = getApiKey(apiKey);
|
|
1589
|
-
const response = await
|
|
1939
|
+
const response = await fetch3(`${API_BASE_URL}/api/metadata/${encodeURIComponent(tableName)}`, {
|
|
1590
1940
|
method: "GET",
|
|
1591
|
-
headers: {
|
|
1592
|
-
"x-api-key": actualApiKey
|
|
1593
|
-
}
|
|
1941
|
+
headers: { "x-api-key": actualApiKey }
|
|
1594
1942
|
});
|
|
1595
1943
|
const result = await handleApiResponse(response);
|
|
1596
1944
|
return await addBackgroundContext({
|
|
1597
|
-
content: [
|
|
1598
|
-
{
|
|
1599
|
-
type: "text",
|
|
1600
|
-
text: formatSuccessMessage("Schema retrieved", result)
|
|
1601
|
-
}
|
|
1602
|
-
]
|
|
1945
|
+
content: [{ type: "text", text: formatSuccessMessage("Schema retrieved", result) }]
|
|
1603
1946
|
});
|
|
1604
1947
|
} catch (error) {
|
|
1605
1948
|
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
1606
1949
|
return {
|
|
1607
|
-
content: [
|
|
1608
|
-
{
|
|
1609
|
-
type: "text",
|
|
1610
|
-
text: `Error getting table schema: ${errMsg}`
|
|
1611
|
-
}
|
|
1612
|
-
],
|
|
1950
|
+
content: [{ type: "text", text: `Error getting table schema: ${errMsg}` }],
|
|
1613
1951
|
isError: true
|
|
1614
1952
|
};
|
|
1615
1953
|
}
|
|
@@ -1619,37 +1957,25 @@ Supported languages: ${sdkLanguageSchema.options.join(", ")}`,
|
|
|
1619
1957
|
"get-backend-metadata",
|
|
1620
1958
|
"Index all backend metadata",
|
|
1621
1959
|
{
|
|
1622
|
-
apiKey:
|
|
1960
|
+
apiKey: z26.string().optional().describe("API key for authentication (optional if provided via --api_key)")
|
|
1623
1961
|
},
|
|
1624
1962
|
withUsageTracking("get-backend-metadata", async ({ apiKey }) => {
|
|
1625
1963
|
try {
|
|
1626
1964
|
const actualApiKey = getApiKey(apiKey);
|
|
1627
|
-
const response = await
|
|
1965
|
+
const response = await fetch3(`${API_BASE_URL}/api/metadata?mcp=true`, {
|
|
1628
1966
|
method: "GET",
|
|
1629
|
-
headers: {
|
|
1630
|
-
"x-api-key": actualApiKey
|
|
1631
|
-
}
|
|
1967
|
+
headers: { "x-api-key": actualApiKey }
|
|
1632
1968
|
});
|
|
1633
1969
|
const metadata = await handleApiResponse(response);
|
|
1634
1970
|
return await addBackgroundContext({
|
|
1635
|
-
content: [
|
|
1636
|
-
{
|
|
1637
|
-
type: "text",
|
|
1638
|
-
text: `Backend metadata:
|
|
1971
|
+
content: [{ type: "text", text: `Backend metadata:
|
|
1639
1972
|
|
|
1640
|
-
${JSON.stringify(metadata, null, 2)}`
|
|
1641
|
-
}
|
|
1642
|
-
]
|
|
1973
|
+
${JSON.stringify(metadata, null, 2)}` }]
|
|
1643
1974
|
});
|
|
1644
1975
|
} catch (error) {
|
|
1645
1976
|
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
1646
1977
|
return {
|
|
1647
|
-
content: [
|
|
1648
|
-
{
|
|
1649
|
-
type: "text",
|
|
1650
|
-
text: `Error retrieving backend metadata: ${errMsg}`
|
|
1651
|
-
}
|
|
1652
|
-
],
|
|
1978
|
+
content: [{ type: "text", text: `Error retrieving backend metadata: ${errMsg}` }],
|
|
1653
1979
|
isError: true
|
|
1654
1980
|
};
|
|
1655
1981
|
}
|
|
@@ -1659,17 +1985,14 @@ ${JSON.stringify(metadata, null, 2)}`
|
|
|
1659
1985
|
"run-raw-sql",
|
|
1660
1986
|
"Execute raw SQL query with optional parameters. Admin access required. Use with caution as it can modify data directly.",
|
|
1661
1987
|
{
|
|
1662
|
-
apiKey:
|
|
1988
|
+
apiKey: z26.string().optional().describe("API key for authentication (optional if provided via --api_key)"),
|
|
1663
1989
|
...rawSQLRequestSchema.shape
|
|
1664
1990
|
},
|
|
1665
1991
|
withUsageTracking("run-raw-sql", async ({ apiKey, query, params }) => {
|
|
1666
1992
|
try {
|
|
1667
1993
|
const actualApiKey = getApiKey(apiKey);
|
|
1668
|
-
const requestBody = {
|
|
1669
|
-
|
|
1670
|
-
params: params || []
|
|
1671
|
-
};
|
|
1672
|
-
const response = await fetch2(`${API_BASE_URL}/api/database/advance/rawsql`, {
|
|
1994
|
+
const requestBody = { query, params: params || [] };
|
|
1995
|
+
const response = await fetch3(`${API_BASE_URL}/api/database/advance/rawsql`, {
|
|
1673
1996
|
method: "POST",
|
|
1674
1997
|
headers: {
|
|
1675
1998
|
"x-api-key": actualApiKey,
|
|
@@ -1679,75 +2002,103 @@ ${JSON.stringify(metadata, null, 2)}`
|
|
|
1679
2002
|
});
|
|
1680
2003
|
const result = await handleApiResponse(response);
|
|
1681
2004
|
return await addBackgroundContext({
|
|
1682
|
-
content: [
|
|
1683
|
-
{
|
|
1684
|
-
type: "text",
|
|
1685
|
-
text: formatSuccessMessage("SQL query executed", result)
|
|
1686
|
-
}
|
|
1687
|
-
]
|
|
2005
|
+
content: [{ type: "text", text: formatSuccessMessage("SQL query executed", result) }]
|
|
1688
2006
|
});
|
|
1689
2007
|
} catch (error) {
|
|
1690
2008
|
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
1691
2009
|
return {
|
|
1692
|
-
content: [
|
|
1693
|
-
{
|
|
1694
|
-
type: "text",
|
|
1695
|
-
text: `Error executing SQL query: ${errMsg}`
|
|
1696
|
-
}
|
|
1697
|
-
],
|
|
2010
|
+
content: [{ type: "text", text: `Error executing SQL query: ${errMsg}` }],
|
|
1698
2011
|
isError: true
|
|
1699
2012
|
};
|
|
1700
2013
|
}
|
|
1701
2014
|
})
|
|
1702
2015
|
);
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
const response = await fetch2(`${API_BASE_URL}/api/auth/tokens/anon`, {
|
|
1713
|
-
method: "POST",
|
|
1714
|
-
headers: {
|
|
1715
|
-
"x-api-key": getApiKey(),
|
|
1716
|
-
"Content-Type": "application/json"
|
|
1717
|
-
}
|
|
1718
|
-
});
|
|
1719
|
-
const result = await handleApiResponse(response);
|
|
1720
|
-
const anonKey = result.accessToken;
|
|
1721
|
-
if (!anonKey) {
|
|
1722
|
-
throw new Error("Failed to retrieve anon key from backend");
|
|
1723
|
-
}
|
|
1724
|
-
const tempDir = tmpdir();
|
|
1725
|
-
const targetDir = projectName || `insforge-${frame}`;
|
|
1726
|
-
const templatePath = `${tempDir}/${targetDir}`;
|
|
1727
|
-
console.error(`[download-template] Target path: ${templatePath}`);
|
|
2016
|
+
if (isRemote) {
|
|
2017
|
+
registerTool(
|
|
2018
|
+
"download-template",
|
|
2019
|
+
"CRITICAL: MANDATORY FIRST STEP for all new InsForge projects. Fetches configuration and returns a command for you to run locally to scaffold a starter template.",
|
|
2020
|
+
{
|
|
2021
|
+
frame: z26.enum(["react", "nextjs"]).describe("Framework to use for the template (support React and Next.js)"),
|
|
2022
|
+
projectName: z26.string().optional().describe('Name for the project directory (optional, defaults to "insforge-{frame}")')
|
|
2023
|
+
},
|
|
2024
|
+
withUsageTracking("download-template", async ({ frame, projectName }) => {
|
|
1728
2025
|
try {
|
|
1729
|
-
const
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
2026
|
+
const response = await fetch3(`${API_BASE_URL}/api/auth/tokens/anon`, {
|
|
2027
|
+
method: "POST",
|
|
2028
|
+
headers: {
|
|
2029
|
+
"x-api-key": getApiKey(),
|
|
2030
|
+
"Content-Type": "application/json"
|
|
2031
|
+
}
|
|
2032
|
+
});
|
|
2033
|
+
const anonResult = await handleApiResponse(response);
|
|
2034
|
+
if (!isAnonTokenResponse(anonResult)) {
|
|
2035
|
+
throw new Error("Failed to retrieve anon key from backend");
|
|
2036
|
+
}
|
|
2037
|
+
const anonKey = anonResult.accessToken;
|
|
2038
|
+
const rawDir = projectName || `insforge-${frame}`;
|
|
2039
|
+
if (!rawDir || rawDir === "." || rawDir === ".." || /[/\\]/.test(rawDir) || !/^[\w.-]+$/.test(rawDir)) {
|
|
2040
|
+
throw new Error("projectName must be a single directory name using only letters, numbers, hyphens, underscores, and dots");
|
|
2041
|
+
}
|
|
2042
|
+
const targetDir = rawDir;
|
|
2043
|
+
const instructions = `Template configuration ready. Please run the following command in your project's parent directory:
|
|
2044
|
+
|
|
2045
|
+
\`\`\`bash
|
|
2046
|
+
npx create-insforge-app ${shellEsc(targetDir)} --frame ${frame} --base-url ${shellEsc(API_BASE_URL)} --anon-key ${shellEsc(anonKey)}
|
|
2047
|
+
\`\`\`
|
|
2048
|
+
|
|
2049
|
+
After the command completes, \`cd ${shellEsc(targetDir)}\` and start developing.`;
|
|
2050
|
+
return {
|
|
2051
|
+
content: [{ type: "text", text: instructions }]
|
|
2052
|
+
};
|
|
2053
|
+
} catch (error) {
|
|
2054
|
+
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
2055
|
+
return {
|
|
2056
|
+
content: [{ type: "text", text: `Error preparing template: ${errMsg}` }],
|
|
2057
|
+
isError: true
|
|
2058
|
+
};
|
|
1745
2059
|
}
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
2060
|
+
})
|
|
2061
|
+
);
|
|
2062
|
+
} else {
|
|
2063
|
+
registerTool(
|
|
2064
|
+
"download-template",
|
|
2065
|
+
"CRITICAL: MANDATORY FIRST STEP for all new InsForge projects. Download pre-configured starter template to a temporary directory. After download, you MUST copy files to current directory using the provided command.",
|
|
2066
|
+
{
|
|
2067
|
+
frame: z26.enum(["react", "nextjs"]).describe("Framework to use for the template (support React and Next.js)"),
|
|
2068
|
+
projectName: z26.string().optional().describe('Name for the project directory (optional, defaults to "insforge-{frame}")')
|
|
2069
|
+
},
|
|
2070
|
+
withUsageTracking("download-template", async ({ frame, projectName }) => {
|
|
2071
|
+
try {
|
|
2072
|
+
const response = await fetch3(`${API_BASE_URL}/api/auth/tokens/anon`, {
|
|
2073
|
+
method: "POST",
|
|
2074
|
+
headers: {
|
|
2075
|
+
"x-api-key": getApiKey(),
|
|
2076
|
+
"Content-Type": "application/json"
|
|
2077
|
+
}
|
|
2078
|
+
});
|
|
2079
|
+
const anonResult = await handleApiResponse(response);
|
|
2080
|
+
if (!isAnonTokenResponse(anonResult)) {
|
|
2081
|
+
throw new Error("Failed to retrieve anon key from backend");
|
|
2082
|
+
}
|
|
2083
|
+
const anonKey = anonResult.accessToken;
|
|
2084
|
+
const rawDir = projectName || `insforge-${frame}`;
|
|
2085
|
+
if (!rawDir || rawDir === "." || rawDir === ".." || /[/\\]/.test(rawDir) || !/^[\w.-]+$/.test(rawDir)) {
|
|
2086
|
+
throw new Error("projectName must be a single directory name using only letters, numbers, hyphens, underscores, and dots");
|
|
2087
|
+
}
|
|
2088
|
+
const targetDir = rawDir;
|
|
2089
|
+
const workspaceBase = await fs.mkdtemp(join(tmpdir(), "insforge-template-"));
|
|
2090
|
+
const templatePath = join(workspaceBase, targetDir);
|
|
2091
|
+
console.error(`[download-template] Target path: ${templatePath}`);
|
|
2092
|
+
await execFileAsync(
|
|
2093
|
+
"npx",
|
|
2094
|
+
["create-insforge-app", targetDir, "--frame", frame, "--base-url", API_BASE_URL, "--anon-key", anonKey, "--skip-install"],
|
|
2095
|
+
{ maxBuffer: 10 * 1024 * 1024, cwd: workspaceBase }
|
|
2096
|
+
);
|
|
2097
|
+
const frameName = frame === "nextjs" ? "Next.js" : "React";
|
|
2098
|
+
return await addBackgroundContext({
|
|
2099
|
+
content: [{
|
|
1749
2100
|
type: "text",
|
|
1750
|
-
text: `\u2705
|
|
2101
|
+
text: `\u2705 ${frameName} template downloaded successfully
|
|
1751
2102
|
|
|
1752
2103
|
\u{1F4C1} Template Location: ${templatePath}
|
|
1753
2104
|
|
|
@@ -1759,43 +2110,38 @@ You MUST copy ALL files (INCLUDING HIDDEN FILES like .env, .gitignore, etc.) fro
|
|
|
1759
2110
|
Copy all files from: ${templatePath}
|
|
1760
2111
|
To: Your current project directory
|
|
1761
2112
|
`
|
|
1762
|
-
}
|
|
1763
|
-
|
|
1764
|
-
})
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
isError: true
|
|
1775
|
-
};
|
|
1776
|
-
}
|
|
1777
|
-
})
|
|
1778
|
-
);
|
|
2113
|
+
}]
|
|
2114
|
+
});
|
|
2115
|
+
} catch (error) {
|
|
2116
|
+
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
2117
|
+
return {
|
|
2118
|
+
content: [{ type: "text", text: `Error downloading template: ${errMsg}` }],
|
|
2119
|
+
isError: true
|
|
2120
|
+
};
|
|
2121
|
+
}
|
|
2122
|
+
})
|
|
2123
|
+
);
|
|
2124
|
+
}
|
|
1779
2125
|
registerTool(
|
|
1780
2126
|
"bulk-upsert",
|
|
1781
2127
|
"Bulk insert or update data from CSV or JSON file. Supports upsert operations with a unique key.",
|
|
1782
2128
|
{
|
|
1783
|
-
apiKey:
|
|
2129
|
+
apiKey: z26.string().optional().describe("API key for authentication (optional if provided via --api_key)"),
|
|
1784
2130
|
...bulkUpsertRequestSchema.shape,
|
|
1785
|
-
filePath:
|
|
2131
|
+
filePath: z26.string().describe("Path to CSV or JSON file containing data to import")
|
|
1786
2132
|
},
|
|
1787
2133
|
withUsageTracking("bulk-upsert", async ({ apiKey, table, filePath, upsertKey }) => {
|
|
1788
2134
|
try {
|
|
1789
2135
|
const actualApiKey = getApiKey(apiKey);
|
|
1790
2136
|
const fileBuffer = await fs.readFile(filePath);
|
|
1791
|
-
const fileName = filePath
|
|
2137
|
+
const fileName = basename(filePath) || "data.csv";
|
|
1792
2138
|
const formData = new FormData();
|
|
1793
2139
|
formData.append("file", fileBuffer, fileName);
|
|
1794
2140
|
formData.append("table", table);
|
|
1795
2141
|
if (upsertKey) {
|
|
1796
2142
|
formData.append("upsertKey", upsertKey);
|
|
1797
2143
|
}
|
|
1798
|
-
const response = await
|
|
2144
|
+
const response = await fetch3(`${API_BASE_URL}/api/database/advance/bulk-upsert`, {
|
|
1799
2145
|
method: "POST",
|
|
1800
2146
|
headers: {
|
|
1801
2147
|
"x-api-key": actualApiKey,
|
|
@@ -1803,47 +2149,50 @@ To: Your current project directory
|
|
|
1803
2149
|
},
|
|
1804
2150
|
body: formData
|
|
1805
2151
|
});
|
|
1806
|
-
const
|
|
1807
|
-
|
|
2152
|
+
const rawResult = await handleApiResponse(response);
|
|
2153
|
+
if (!isBulkUpsertApiResult(rawResult)) {
|
|
2154
|
+
throw new Error("Unexpected response format from bulk-upsert endpoint");
|
|
2155
|
+
}
|
|
2156
|
+
const message = rawResult.success ? `Successfully processed ${rawResult.rowsAffected} of ${rawResult.totalRecords} records into table "${rawResult.table}"` : rawResult.message || "Bulk upsert operation completed";
|
|
1808
2157
|
return await addBackgroundContext({
|
|
1809
|
-
content: [
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
}
|
|
1820
|
-
]
|
|
2158
|
+
content: [{
|
|
2159
|
+
type: "text",
|
|
2160
|
+
text: formatSuccessMessage("Bulk upsert completed", {
|
|
2161
|
+
message,
|
|
2162
|
+
table: rawResult.table,
|
|
2163
|
+
rowsAffected: rawResult.rowsAffected,
|
|
2164
|
+
totalRecords: rawResult.totalRecords,
|
|
2165
|
+
errors: rawResult.errors
|
|
2166
|
+
})
|
|
2167
|
+
}]
|
|
1821
2168
|
});
|
|
1822
2169
|
} catch (error) {
|
|
1823
2170
|
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
1824
2171
|
return {
|
|
1825
|
-
content: [
|
|
1826
|
-
{
|
|
1827
|
-
type: "text",
|
|
1828
|
-
text: `Error performing bulk upsert: ${errMsg}`
|
|
1829
|
-
}
|
|
1830
|
-
],
|
|
2172
|
+
content: [{ type: "text", text: `Error performing bulk upsert: ${errMsg}` }],
|
|
1831
2173
|
isError: true
|
|
1832
2174
|
};
|
|
1833
2175
|
}
|
|
1834
2176
|
})
|
|
1835
2177
|
);
|
|
2178
|
+
}
|
|
2179
|
+
|
|
2180
|
+
// src/shared/tools/storage.ts
|
|
2181
|
+
import { z as z27 } from "zod";
|
|
2182
|
+
import fetch4 from "node-fetch";
|
|
2183
|
+
function registerStorageTools(ctx) {
|
|
2184
|
+
const { API_BASE_URL, registerTool, withUsageTracking, getApiKey, addBackgroundContext } = ctx;
|
|
1836
2185
|
registerTool(
|
|
1837
2186
|
"create-bucket",
|
|
1838
2187
|
"Create new storage bucket",
|
|
1839
2188
|
{
|
|
1840
|
-
apiKey:
|
|
2189
|
+
apiKey: z27.string().optional().describe("API key for authentication (optional if provided via --api_key)"),
|
|
1841
2190
|
...createBucketRequestSchema.shape
|
|
1842
2191
|
},
|
|
1843
2192
|
withUsageTracking("create-bucket", async ({ apiKey, bucketName, isPublic }) => {
|
|
1844
2193
|
try {
|
|
1845
2194
|
const actualApiKey = getApiKey(apiKey);
|
|
1846
|
-
const response = await
|
|
2195
|
+
const response = await fetch4(`${API_BASE_URL}/api/storage/buckets`, {
|
|
1847
2196
|
method: "POST",
|
|
1848
2197
|
headers: {
|
|
1849
2198
|
"x-api-key": actualApiKey,
|
|
@@ -1853,22 +2202,12 @@ To: Your current project directory
|
|
|
1853
2202
|
});
|
|
1854
2203
|
const result = await handleApiResponse(response);
|
|
1855
2204
|
return await addBackgroundContext({
|
|
1856
|
-
content: [
|
|
1857
|
-
{
|
|
1858
|
-
type: "text",
|
|
1859
|
-
text: formatSuccessMessage("Bucket created", result)
|
|
1860
|
-
}
|
|
1861
|
-
]
|
|
2205
|
+
content: [{ type: "text", text: formatSuccessMessage("Bucket created", result) }]
|
|
1862
2206
|
});
|
|
1863
2207
|
} catch (error) {
|
|
1864
2208
|
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
1865
2209
|
return {
|
|
1866
|
-
content: [
|
|
1867
|
-
{
|
|
1868
|
-
type: "text",
|
|
1869
|
-
text: `Error creating bucket: ${errMsg}`
|
|
1870
|
-
}
|
|
1871
|
-
],
|
|
2210
|
+
content: [{ type: "text", text: `Error creating bucket: ${errMsg}` }],
|
|
1872
2211
|
isError: true
|
|
1873
2212
|
};
|
|
1874
2213
|
}
|
|
@@ -1877,33 +2216,23 @@ To: Your current project directory
|
|
|
1877
2216
|
registerTool(
|
|
1878
2217
|
"list-buckets",
|
|
1879
2218
|
"Lists all storage buckets",
|
|
1880
|
-
{
|
|
1881
|
-
|
|
2219
|
+
{
|
|
2220
|
+
apiKey: z27.string().optional().describe("API key for authentication (optional if provided via --api_key)")
|
|
2221
|
+
},
|
|
2222
|
+
withUsageTracking("list-buckets", async ({ apiKey }) => {
|
|
1882
2223
|
try {
|
|
1883
|
-
const response = await
|
|
2224
|
+
const response = await fetch4(`${API_BASE_URL}/api/storage/buckets`, {
|
|
1884
2225
|
method: "GET",
|
|
1885
|
-
headers: {
|
|
1886
|
-
"x-api-key": getApiKey()
|
|
1887
|
-
}
|
|
2226
|
+
headers: { "x-api-key": getApiKey(apiKey) }
|
|
1888
2227
|
});
|
|
1889
2228
|
const result = await handleApiResponse(response);
|
|
1890
2229
|
return await addBackgroundContext({
|
|
1891
|
-
content: [
|
|
1892
|
-
{
|
|
1893
|
-
type: "text",
|
|
1894
|
-
text: formatSuccessMessage("Buckets retrieved", result)
|
|
1895
|
-
}
|
|
1896
|
-
]
|
|
2230
|
+
content: [{ type: "text", text: formatSuccessMessage("Buckets retrieved", result) }]
|
|
1897
2231
|
});
|
|
1898
2232
|
} catch (error) {
|
|
1899
2233
|
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
1900
2234
|
return {
|
|
1901
|
-
content: [
|
|
1902
|
-
{
|
|
1903
|
-
type: "text",
|
|
1904
|
-
text: `Error listing buckets: ${errMsg}`
|
|
1905
|
-
}
|
|
1906
|
-
],
|
|
2235
|
+
content: [{ type: "text", text: `Error listing buckets: ${errMsg}` }],
|
|
1907
2236
|
isError: true
|
|
1908
2237
|
};
|
|
1909
2238
|
}
|
|
@@ -1913,432 +2242,736 @@ To: Your current project directory
|
|
|
1913
2242
|
"delete-bucket",
|
|
1914
2243
|
"Deletes a storage bucket",
|
|
1915
2244
|
{
|
|
1916
|
-
apiKey:
|
|
1917
|
-
|
|
2245
|
+
apiKey: z27.string().optional().describe("API key for authentication (optional if provided via --api_key)"),
|
|
2246
|
+
// Reuse the same bucket name validation as create-bucket
|
|
2247
|
+
bucketName: createBucketRequestSchema.shape.bucketName
|
|
1918
2248
|
},
|
|
1919
2249
|
withUsageTracking("delete-bucket", async ({ apiKey, bucketName }) => {
|
|
1920
2250
|
try {
|
|
1921
2251
|
const actualApiKey = getApiKey(apiKey);
|
|
1922
|
-
const response = await
|
|
2252
|
+
const response = await fetch4(`${API_BASE_URL}/api/storage/buckets/${encodeURIComponent(bucketName)}`, {
|
|
1923
2253
|
method: "DELETE",
|
|
1924
|
-
headers: {
|
|
1925
|
-
"x-api-key": actualApiKey
|
|
1926
|
-
}
|
|
2254
|
+
headers: { "x-api-key": actualApiKey }
|
|
1927
2255
|
});
|
|
1928
2256
|
const result = await handleApiResponse(response);
|
|
1929
2257
|
return await addBackgroundContext({
|
|
1930
|
-
content: [
|
|
1931
|
-
{
|
|
1932
|
-
type: "text",
|
|
1933
|
-
text: formatSuccessMessage("Bucket deleted", result)
|
|
1934
|
-
}
|
|
1935
|
-
]
|
|
2258
|
+
content: [{ type: "text", text: formatSuccessMessage("Bucket deleted", result) }]
|
|
1936
2259
|
});
|
|
1937
2260
|
} catch (error) {
|
|
1938
2261
|
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
1939
2262
|
return {
|
|
1940
|
-
content: [
|
|
1941
|
-
{
|
|
1942
|
-
type: "text",
|
|
1943
|
-
text: `Error deleting bucket: ${errMsg}`
|
|
1944
|
-
}
|
|
1945
|
-
],
|
|
2263
|
+
content: [{ type: "text", text: `Error deleting bucket: ${errMsg}` }],
|
|
1946
2264
|
isError: true
|
|
1947
2265
|
};
|
|
1948
2266
|
}
|
|
1949
2267
|
})
|
|
1950
2268
|
);
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
2269
|
+
}
|
|
2270
|
+
|
|
2271
|
+
// src/shared/tools/functions.ts
|
|
2272
|
+
import { z as z28 } from "zod";
|
|
2273
|
+
import fetch5 from "node-fetch";
|
|
2274
|
+
import { promises as fs2 } from "fs";
|
|
2275
|
+
function registerFunctionTools(ctx) {
|
|
2276
|
+
const { API_BASE_URL, isRemote, registerTool, withUsageTracking, getApiKey, addBackgroundContext } = ctx;
|
|
2277
|
+
if (isRemote) {
|
|
2278
|
+
registerTool(
|
|
2279
|
+
"create-function",
|
|
2280
|
+
"Create a new edge function that runs in Deno runtime",
|
|
2281
|
+
{
|
|
2282
|
+
apiKey: z28.string().optional().describe("API key for authentication (optional if provided via --api_key)"),
|
|
2283
|
+
...uploadFunctionRequestSchema.omit({ code: true }).shape,
|
|
2284
|
+
code: z28.string().describe(
|
|
2285
|
+
"The function code as a string. Must export: module.exports = async function(request) { return new Response(...) }"
|
|
2286
|
+
)
|
|
2287
|
+
},
|
|
2288
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2289
|
+
withUsageTracking("create-function", async (args) => {
|
|
1963
2290
|
try {
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
2291
|
+
const response = await fetch5(`${API_BASE_URL}/api/functions`, {
|
|
2292
|
+
method: "POST",
|
|
2293
|
+
headers: {
|
|
2294
|
+
"Content-Type": "application/json",
|
|
2295
|
+
"x-api-key": getApiKey(args.apiKey)
|
|
2296
|
+
},
|
|
2297
|
+
body: JSON.stringify({
|
|
2298
|
+
slug: args.slug,
|
|
2299
|
+
name: args.name,
|
|
2300
|
+
code: args.code,
|
|
2301
|
+
description: args.description,
|
|
2302
|
+
status: args.status
|
|
2303
|
+
})
|
|
2304
|
+
});
|
|
2305
|
+
const result = await handleApiResponse(response);
|
|
2306
|
+
return await addBackgroundContext({
|
|
2307
|
+
content: [{ type: "text", text: formatSuccessMessage(`Edge function '${args.slug}' created successfully`, result) }]
|
|
2308
|
+
});
|
|
2309
|
+
} catch (error) {
|
|
2310
|
+
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
2311
|
+
return {
|
|
2312
|
+
content: [{ type: "text", text: `Error creating function: ${errMsg}` }],
|
|
2313
|
+
isError: true
|
|
2314
|
+
};
|
|
1969
2315
|
}
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2316
|
+
})
|
|
2317
|
+
);
|
|
2318
|
+
} else {
|
|
2319
|
+
registerTool(
|
|
2320
|
+
"create-function",
|
|
2321
|
+
"Create a new edge function that runs in Deno runtime. The code must be written to a file first for version control",
|
|
2322
|
+
{
|
|
2323
|
+
apiKey: z28.string().optional().describe("API key for authentication (optional if provided via --api_key)"),
|
|
2324
|
+
...uploadFunctionRequestSchema.omit({ code: true }).shape,
|
|
2325
|
+
codeFile: z28.string().describe(
|
|
2326
|
+
"Path to JavaScript file containing the function code. Must export: module.exports = async function(request) { return new Response(...) }"
|
|
2327
|
+
)
|
|
2328
|
+
},
|
|
2329
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2330
|
+
withUsageTracking("create-function", async (args) => {
|
|
2331
|
+
try {
|
|
2332
|
+
let code;
|
|
2333
|
+
try {
|
|
2334
|
+
code = await fs2.readFile(args.codeFile, "utf-8");
|
|
2335
|
+
} catch (fileError) {
|
|
2336
|
+
throw new Error(
|
|
2337
|
+
`Failed to read code file '${args.codeFile}': ${fileError instanceof Error ? fileError.message : "Unknown error"}`,
|
|
2338
|
+
{ cause: fileError }
|
|
2339
|
+
);
|
|
2340
|
+
}
|
|
2341
|
+
const response = await fetch5(`${API_BASE_URL}/api/functions`, {
|
|
2342
|
+
method: "POST",
|
|
2343
|
+
headers: {
|
|
2344
|
+
"Content-Type": "application/json",
|
|
2345
|
+
"x-api-key": getApiKey(args.apiKey)
|
|
2346
|
+
},
|
|
2347
|
+
body: JSON.stringify({
|
|
2348
|
+
slug: args.slug,
|
|
2349
|
+
name: args.name,
|
|
2350
|
+
code,
|
|
2351
|
+
description: args.description,
|
|
2352
|
+
status: args.status
|
|
2353
|
+
})
|
|
2354
|
+
});
|
|
2355
|
+
const result = await handleApiResponse(response);
|
|
2356
|
+
return await addBackgroundContext({
|
|
2357
|
+
content: [{ type: "text", text: formatSuccessMessage(`Edge function '${args.slug}' created successfully from ${args.codeFile}`, result) }]
|
|
2358
|
+
});
|
|
2359
|
+
} catch (error) {
|
|
2360
|
+
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
2361
|
+
return {
|
|
2362
|
+
content: [{ type: "text", text: `Error creating function: ${errMsg}` }],
|
|
2363
|
+
isError: true
|
|
2364
|
+
};
|
|
2365
|
+
}
|
|
2366
|
+
})
|
|
2367
|
+
);
|
|
2368
|
+
}
|
|
2010
2369
|
registerTool(
|
|
2011
2370
|
"get-function",
|
|
2012
2371
|
"Get details of a specific edge function including its code",
|
|
2013
2372
|
{
|
|
2014
|
-
|
|
2373
|
+
apiKey: z28.string().optional().describe("API key for authentication (optional if provided via --api_key)"),
|
|
2374
|
+
slug: functionSchema.shape.slug.describe("The slug identifier of the function")
|
|
2015
2375
|
},
|
|
2376
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2016
2377
|
withUsageTracking("get-function", async (args) => {
|
|
2017
2378
|
try {
|
|
2018
|
-
const response = await
|
|
2379
|
+
const response = await fetch5(`${API_BASE_URL}/api/functions/${encodeURIComponent(args.slug)}`, {
|
|
2019
2380
|
method: "GET",
|
|
2020
|
-
headers: {
|
|
2021
|
-
"x-api-key": getApiKey()
|
|
2022
|
-
}
|
|
2381
|
+
headers: { "x-api-key": getApiKey(args.apiKey) }
|
|
2023
2382
|
});
|
|
2024
2383
|
const result = await handleApiResponse(response);
|
|
2025
2384
|
return await addBackgroundContext({
|
|
2026
|
-
content: [
|
|
2027
|
-
{
|
|
2028
|
-
type: "text",
|
|
2029
|
-
text: formatSuccessMessage(`Edge function '${args.slug}' details`, result)
|
|
2030
|
-
}
|
|
2031
|
-
]
|
|
2385
|
+
content: [{ type: "text", text: formatSuccessMessage(`Edge function '${args.slug}' details`, result) }]
|
|
2032
2386
|
});
|
|
2033
2387
|
} catch (error) {
|
|
2034
2388
|
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
2035
2389
|
return {
|
|
2036
|
-
content: [
|
|
2037
|
-
{
|
|
2038
|
-
type: "text",
|
|
2039
|
-
text: `Error getting function: ${errMsg}`
|
|
2040
|
-
}
|
|
2041
|
-
],
|
|
2390
|
+
content: [{ type: "text", text: `Error getting function: ${errMsg}` }],
|
|
2042
2391
|
isError: true
|
|
2043
2392
|
};
|
|
2044
2393
|
}
|
|
2045
2394
|
})
|
|
2046
2395
|
);
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2396
|
+
if (isRemote) {
|
|
2397
|
+
registerTool(
|
|
2398
|
+
"update-function",
|
|
2399
|
+
"Update an existing edge function code or metadata",
|
|
2400
|
+
{
|
|
2401
|
+
apiKey: z28.string().optional().describe("API key for authentication (optional if provided via --api_key)"),
|
|
2402
|
+
slug: functionSchema.shape.slug.describe("The slug identifier of the function to update"),
|
|
2403
|
+
...updateFunctionRequestSchema.omit({ code: true }).shape,
|
|
2404
|
+
code: z28.string().optional().describe(
|
|
2405
|
+
"The new function code as a string. Must export: module.exports = async function(request) { return new Response(...) }"
|
|
2406
|
+
)
|
|
2407
|
+
},
|
|
2408
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2409
|
+
withUsageTracking("update-function", async (args) => {
|
|
2410
|
+
try {
|
|
2411
|
+
const updateData = {};
|
|
2412
|
+
if (args.name) updateData.name = args.name;
|
|
2413
|
+
if (args.code) updateData.code = args.code;
|
|
2414
|
+
if (args.description !== void 0) updateData.description = args.description;
|
|
2415
|
+
if (args.status) updateData.status = args.status;
|
|
2416
|
+
const response = await fetch5(`${API_BASE_URL}/api/functions/${encodeURIComponent(args.slug)}`, {
|
|
2417
|
+
method: "PUT",
|
|
2418
|
+
headers: {
|
|
2419
|
+
"Content-Type": "application/json",
|
|
2420
|
+
"x-api-key": getApiKey(args.apiKey)
|
|
2421
|
+
},
|
|
2422
|
+
body: JSON.stringify(updateData)
|
|
2423
|
+
});
|
|
2424
|
+
const result = await handleApiResponse(response);
|
|
2425
|
+
return await addBackgroundContext({
|
|
2426
|
+
content: [{ type: "text", text: formatSuccessMessage(`Edge function '${args.slug}' updated successfully`, result) }]
|
|
2427
|
+
});
|
|
2428
|
+
} catch (error) {
|
|
2429
|
+
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
2430
|
+
return {
|
|
2431
|
+
content: [{ type: "text", text: `Error updating function: ${errMsg}` }],
|
|
2432
|
+
isError: true
|
|
2433
|
+
};
|
|
2062
2434
|
}
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2435
|
+
})
|
|
2436
|
+
);
|
|
2437
|
+
} else {
|
|
2438
|
+
registerTool(
|
|
2439
|
+
"update-function",
|
|
2440
|
+
"Update an existing edge function code or metadata",
|
|
2441
|
+
{
|
|
2442
|
+
apiKey: z28.string().optional().describe("API key for authentication (optional if provided via --api_key)"),
|
|
2443
|
+
slug: functionSchema.shape.slug.describe("The slug identifier of the function to update"),
|
|
2444
|
+
...updateFunctionRequestSchema.omit({ code: true }).shape,
|
|
2445
|
+
codeFile: z28.string().optional().describe(
|
|
2446
|
+
"Path to JavaScript file containing the new function code. Must export: module.exports = async function(request) { return new Response(...) }"
|
|
2447
|
+
)
|
|
2448
|
+
},
|
|
2449
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2450
|
+
withUsageTracking("update-function", async (args) => {
|
|
2451
|
+
try {
|
|
2452
|
+
const updateData = {};
|
|
2453
|
+
if (args.name) updateData.name = args.name;
|
|
2454
|
+
if (args.codeFile) {
|
|
2455
|
+
try {
|
|
2456
|
+
updateData.code = await fs2.readFile(args.codeFile, "utf-8");
|
|
2457
|
+
} catch (fileError) {
|
|
2458
|
+
throw new Error(
|
|
2459
|
+
`Failed to read code file '${args.codeFile}': ${fileError instanceof Error ? fileError.message : "Unknown error"}`,
|
|
2460
|
+
{ cause: fileError }
|
|
2461
|
+
);
|
|
2462
|
+
}
|
|
2070
2463
|
}
|
|
2464
|
+
if (args.description !== void 0) updateData.description = args.description;
|
|
2465
|
+
if (args.status) updateData.status = args.status;
|
|
2466
|
+
const response = await fetch5(`${API_BASE_URL}/api/functions/${encodeURIComponent(args.slug)}`, {
|
|
2467
|
+
method: "PUT",
|
|
2468
|
+
headers: {
|
|
2469
|
+
"Content-Type": "application/json",
|
|
2470
|
+
"x-api-key": getApiKey(args.apiKey)
|
|
2471
|
+
},
|
|
2472
|
+
body: JSON.stringify(updateData)
|
|
2473
|
+
});
|
|
2474
|
+
const result = await handleApiResponse(response);
|
|
2475
|
+
const fileInfo = args.codeFile ? ` from ${args.codeFile}` : "";
|
|
2476
|
+
return await addBackgroundContext({
|
|
2477
|
+
content: [{ type: "text", text: formatSuccessMessage(`Edge function '${args.slug}' updated successfully${fileInfo}`, result) }]
|
|
2478
|
+
});
|
|
2479
|
+
} catch (error) {
|
|
2480
|
+
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
2481
|
+
return {
|
|
2482
|
+
content: [{ type: "text", text: `Error updating function: ${errMsg}` }],
|
|
2483
|
+
isError: true
|
|
2484
|
+
};
|
|
2071
2485
|
}
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
if (args.status) {
|
|
2076
|
-
updateData.status = args.status;
|
|
2077
|
-
}
|
|
2078
|
-
const response = await fetch2(`${API_BASE_URL}/api/functions/${args.slug}`, {
|
|
2079
|
-
method: "PUT",
|
|
2080
|
-
headers: {
|
|
2081
|
-
"Content-Type": "application/json",
|
|
2082
|
-
"x-api-key": getApiKey()
|
|
2083
|
-
},
|
|
2084
|
-
body: JSON.stringify(updateData)
|
|
2085
|
-
});
|
|
2086
|
-
const result = await handleApiResponse(response);
|
|
2087
|
-
const fileInfo = args.codeFile ? ` from ${args.codeFile}` : "";
|
|
2088
|
-
return await addBackgroundContext({
|
|
2089
|
-
content: [
|
|
2090
|
-
{
|
|
2091
|
-
type: "text",
|
|
2092
|
-
text: formatSuccessMessage(
|
|
2093
|
-
`Edge function '${args.slug}' updated successfully${fileInfo}`,
|
|
2094
|
-
result
|
|
2095
|
-
)
|
|
2096
|
-
}
|
|
2097
|
-
]
|
|
2098
|
-
});
|
|
2099
|
-
} catch (error) {
|
|
2100
|
-
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
2101
|
-
return {
|
|
2102
|
-
content: [
|
|
2103
|
-
{
|
|
2104
|
-
type: "text",
|
|
2105
|
-
text: `Error updating function: ${errMsg}`
|
|
2106
|
-
}
|
|
2107
|
-
],
|
|
2108
|
-
isError: true
|
|
2109
|
-
};
|
|
2110
|
-
}
|
|
2111
|
-
})
|
|
2112
|
-
);
|
|
2486
|
+
})
|
|
2487
|
+
);
|
|
2488
|
+
}
|
|
2113
2489
|
registerTool(
|
|
2114
2490
|
"delete-function",
|
|
2115
2491
|
"Delete an edge function permanently",
|
|
2116
2492
|
{
|
|
2117
|
-
|
|
2493
|
+
apiKey: z28.string().optional().describe("API key for authentication (optional if provided via --api_key)"),
|
|
2494
|
+
slug: functionSchema.shape.slug.describe("The slug identifier of the function to delete")
|
|
2118
2495
|
},
|
|
2496
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2119
2497
|
withUsageTracking("delete-function", async (args) => {
|
|
2120
2498
|
try {
|
|
2121
|
-
const response = await
|
|
2499
|
+
const response = await fetch5(`${API_BASE_URL}/api/functions/${encodeURIComponent(args.slug)}`, {
|
|
2122
2500
|
method: "DELETE",
|
|
2123
|
-
headers: {
|
|
2124
|
-
"x-api-key": getApiKey()
|
|
2125
|
-
}
|
|
2501
|
+
headers: { "x-api-key": getApiKey(args.apiKey) }
|
|
2126
2502
|
});
|
|
2127
2503
|
const result = await handleApiResponse(response);
|
|
2128
2504
|
return await addBackgroundContext({
|
|
2129
|
-
content: [
|
|
2130
|
-
{
|
|
2131
|
-
type: "text",
|
|
2132
|
-
text: formatSuccessMessage(`Edge function '${args.slug}' deleted successfully`, result)
|
|
2133
|
-
}
|
|
2134
|
-
]
|
|
2505
|
+
content: [{ type: "text", text: formatSuccessMessage(`Edge function '${args.slug}' deleted successfully`, result) }]
|
|
2135
2506
|
});
|
|
2136
2507
|
} catch (error) {
|
|
2137
2508
|
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
2138
2509
|
return {
|
|
2139
|
-
content: [
|
|
2140
|
-
{
|
|
2141
|
-
type: "text",
|
|
2142
|
-
text: `Error deleting function: ${errMsg}`
|
|
2143
|
-
}
|
|
2144
|
-
],
|
|
2510
|
+
content: [{ type: "text", text: `Error deleting function: ${errMsg}` }],
|
|
2145
2511
|
isError: true
|
|
2146
2512
|
};
|
|
2147
2513
|
}
|
|
2148
2514
|
})
|
|
2149
2515
|
);
|
|
2516
|
+
}
|
|
2517
|
+
|
|
2518
|
+
// src/shared/tools/deployment.ts
|
|
2519
|
+
import { z as z29 } from "zod";
|
|
2520
|
+
import fetch6 from "node-fetch";
|
|
2521
|
+
import { promises as fs3, createWriteStream, createReadStream } from "fs";
|
|
2522
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
2523
|
+
import { join as join2 } from "path";
|
|
2524
|
+
import archiver from "archiver";
|
|
2525
|
+
import FormData2 from "form-data";
|
|
2526
|
+
function isCreateDeploymentResponse(obj) {
|
|
2527
|
+
if (typeof obj !== "object" || obj === null) {
|
|
2528
|
+
return false;
|
|
2529
|
+
}
|
|
2530
|
+
const value = obj;
|
|
2531
|
+
const idOk = "id" in value && (typeof value.id === "string" || typeof value.id === "number");
|
|
2532
|
+
const urlOk = "uploadUrl" in value && typeof value.uploadUrl === "string" && value.uploadUrl.length > 0;
|
|
2533
|
+
const fieldsOk = "uploadFields" in value && typeof value.uploadFields === "object" && value.uploadFields !== null;
|
|
2534
|
+
return idOk && urlOk && fieldsOk;
|
|
2535
|
+
}
|
|
2536
|
+
function registerDeploymentTools(ctx) {
|
|
2537
|
+
const { API_BASE_URL, isRemote, registerTool, withUsageTracking, getApiKey, addBackgroundContext } = ctx;
|
|
2150
2538
|
registerTool(
|
|
2151
2539
|
"get-container-logs",
|
|
2152
2540
|
"Get latest logs from a specific container/service. Use this to help debug problems with your app.",
|
|
2153
2541
|
{
|
|
2154
|
-
apiKey:
|
|
2155
|
-
source:
|
|
2156
|
-
limit:
|
|
2542
|
+
apiKey: z29.string().optional().describe("API key for authentication (optional if provided via --api_key)"),
|
|
2543
|
+
source: z29.enum(["insforge.logs", "postgREST.logs", "postgres.logs", "function.logs"]).describe("Log source to retrieve"),
|
|
2544
|
+
limit: z29.number().optional().default(20).describe("Number of logs to return (default: 20)")
|
|
2157
2545
|
},
|
|
2158
2546
|
withUsageTracking("get-container-logs", async ({ apiKey, source, limit }) => {
|
|
2159
2547
|
try {
|
|
2160
2548
|
const actualApiKey = getApiKey(apiKey);
|
|
2161
2549
|
const queryParams = new URLSearchParams();
|
|
2162
2550
|
if (limit) queryParams.append("limit", limit.toString());
|
|
2163
|
-
let response = await
|
|
2551
|
+
let response = await fetch6(`${API_BASE_URL}/api/logs/${source}?${queryParams}`, {
|
|
2164
2552
|
method: "GET",
|
|
2165
|
-
headers: {
|
|
2166
|
-
"x-api-key": actualApiKey
|
|
2167
|
-
}
|
|
2553
|
+
headers: { "x-api-key": actualApiKey }
|
|
2168
2554
|
});
|
|
2169
2555
|
if (response.status === 404) {
|
|
2170
|
-
response = await
|
|
2556
|
+
response = await fetch6(`${API_BASE_URL}/api/logs/analytics/${source}?${queryParams}`, {
|
|
2171
2557
|
method: "GET",
|
|
2172
|
-
headers: {
|
|
2173
|
-
"x-api-key": actualApiKey
|
|
2174
|
-
}
|
|
2558
|
+
headers: { "x-api-key": actualApiKey }
|
|
2175
2559
|
});
|
|
2176
2560
|
}
|
|
2177
2561
|
const result = await handleApiResponse(response);
|
|
2178
2562
|
return await addBackgroundContext({
|
|
2179
|
-
content: [
|
|
2180
|
-
{
|
|
2181
|
-
type: "text",
|
|
2182
|
-
text: formatSuccessMessage(`Latest logs from ${source}`, result)
|
|
2183
|
-
}
|
|
2184
|
-
]
|
|
2563
|
+
content: [{ type: "text", text: formatSuccessMessage(`Latest logs from ${source}`, result) }]
|
|
2185
2564
|
});
|
|
2186
2565
|
} catch (error) {
|
|
2187
2566
|
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
2188
2567
|
return {
|
|
2189
|
-
content: [
|
|
2190
|
-
{
|
|
2191
|
-
type: "text",
|
|
2192
|
-
text: `Error retrieving container logs: ${errMsg}`
|
|
2193
|
-
}
|
|
2194
|
-
],
|
|
2568
|
+
content: [{ type: "text", text: `Error retrieving container logs: ${errMsg}` }],
|
|
2195
2569
|
isError: true
|
|
2196
2570
|
};
|
|
2197
2571
|
}
|
|
2198
2572
|
})
|
|
2199
2573
|
);
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
{
|
|
2574
|
+
if (isRemote) {
|
|
2575
|
+
registerTool(
|
|
2576
|
+
"create-deployment",
|
|
2577
|
+
"Prepare a deployment by creating a presigned upload URL. Returns shell commands for the agent to execute locally: zip the source directory and upload to cloud storage. After uploading, call the start-deployment tool to trigger the build.",
|
|
2578
|
+
{
|
|
2579
|
+
sourceDirectory: z29.string().describe('Absolute path to the source directory containing files to deploy (e.g., /Users/name/project). Do not use relative paths like "."')
|
|
2580
|
+
},
|
|
2581
|
+
withUsageTracking("create-deployment", async ({ sourceDirectory }) => {
|
|
2582
|
+
try {
|
|
2583
|
+
const isAbsolutePath = sourceDirectory.startsWith("/") || /^[a-zA-Z]:[/\\]/.test(sourceDirectory);
|
|
2584
|
+
if (!isAbsolutePath) {
|
|
2585
|
+
return {
|
|
2586
|
+
content: [{
|
|
2214
2587
|
type: "text",
|
|
2215
2588
|
text: `Error: sourceDirectory must be an absolute path, not a relative path like "${sourceDirectory}". Please provide the full path to the source directory (e.g., /Users/name/project on macOS/Linux or C:\\Users\\name\\project on Windows).`
|
|
2216
|
-
}
|
|
2217
|
-
|
|
2589
|
+
}],
|
|
2590
|
+
isError: true
|
|
2591
|
+
};
|
|
2592
|
+
}
|
|
2593
|
+
const createResponse = await fetch6(`${API_BASE_URL}/api/deployments`, {
|
|
2594
|
+
method: "POST",
|
|
2595
|
+
headers: {
|
|
2596
|
+
"x-api-key": getApiKey(),
|
|
2597
|
+
"Content-Type": "application/json"
|
|
2598
|
+
}
|
|
2599
|
+
});
|
|
2600
|
+
const createResult = await handleApiResponse(createResponse);
|
|
2601
|
+
if (!isCreateDeploymentResponse(createResult)) {
|
|
2602
|
+
throw new Error("Unexpected response format from deployments endpoint");
|
|
2603
|
+
}
|
|
2604
|
+
const { id: deploymentId, uploadUrl, uploadFields } = createResult;
|
|
2605
|
+
const esc = shellEsc;
|
|
2606
|
+
const curlFields = Object.entries(uploadFields).map(([key, value]) => `-F ${esc(`${key}=${value}`)}`).join(" \\\n ");
|
|
2607
|
+
const escapedDir = esc(sourceDirectory);
|
|
2608
|
+
const tmpZip = `/tmp/insforge-deploy-${deploymentId}.zip`;
|
|
2609
|
+
const instructions = `Deployment prepared successfully. Deployment ID: ${deploymentId}
|
|
2610
|
+
|
|
2611
|
+
Please execute the following commands locally, then call the \`start-deployment\` tool:
|
|
2612
|
+
|
|
2613
|
+
## Step 1: Zip the source directory
|
|
2614
|
+
\`\`\`bash
|
|
2615
|
+
cd ${escapedDir} && zip -r ${tmpZip} . -x "node_modules/*" ".git/*" ".next/*" ".env" ".env.local" "dist/*" "build/*" ".DS_Store" "*.log"
|
|
2616
|
+
\`\`\`
|
|
2617
|
+
|
|
2618
|
+
## Step 2: Upload the zip file
|
|
2619
|
+
\`\`\`bash
|
|
2620
|
+
curl -X POST ${esc(uploadUrl)} ${curlFields} -F 'file=@${tmpZip};type=application/zip'
|
|
2621
|
+
\`\`\`
|
|
2622
|
+
|
|
2623
|
+
## Step 3: Clean up
|
|
2624
|
+
\`\`\`bash
|
|
2625
|
+
rm /tmp/insforge-deploy-${deploymentId}.zip
|
|
2626
|
+
\`\`\`
|
|
2627
|
+
|
|
2628
|
+
## Step 4: Trigger the build
|
|
2629
|
+
Call the \`start-deployment\` tool with deploymentId: "${deploymentId}"
|
|
2630
|
+
|
|
2631
|
+
Run each step in order. If any step fails, do not proceed to the next step.`;
|
|
2632
|
+
return {
|
|
2633
|
+
content: [{ type: "text", text: instructions }]
|
|
2634
|
+
};
|
|
2635
|
+
} catch (error) {
|
|
2636
|
+
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
2637
|
+
return {
|
|
2638
|
+
content: [{ type: "text", text: `Error preparing deployment: ${errMsg}` }],
|
|
2218
2639
|
isError: true
|
|
2219
2640
|
};
|
|
2220
2641
|
}
|
|
2642
|
+
})
|
|
2643
|
+
);
|
|
2644
|
+
registerTool(
|
|
2645
|
+
"start-deployment",
|
|
2646
|
+
"Trigger a deployment build after uploading source code. Use this after executing the upload commands from create-deployment.",
|
|
2647
|
+
{
|
|
2648
|
+
deploymentId: z29.string().describe("The deployment ID returned by create-deployment"),
|
|
2649
|
+
...startDeploymentRequestSchema.shape
|
|
2650
|
+
},
|
|
2651
|
+
withUsageTracking("start-deployment", async ({ deploymentId, projectSettings, envVars, meta }) => {
|
|
2221
2652
|
try {
|
|
2222
|
-
const
|
|
2223
|
-
if (
|
|
2653
|
+
const startBody = {};
|
|
2654
|
+
if (projectSettings) startBody.projectSettings = projectSettings;
|
|
2655
|
+
if (envVars) startBody.envVars = envVars;
|
|
2656
|
+
if (meta) startBody.meta = meta;
|
|
2657
|
+
const startResponse = await fetch6(`${API_BASE_URL}/api/deployments/${encodeURIComponent(deploymentId)}/start`, {
|
|
2658
|
+
method: "POST",
|
|
2659
|
+
headers: {
|
|
2660
|
+
"x-api-key": getApiKey(),
|
|
2661
|
+
"Content-Type": "application/json"
|
|
2662
|
+
},
|
|
2663
|
+
body: JSON.stringify(startBody)
|
|
2664
|
+
});
|
|
2665
|
+
const startResult = await handleApiResponse(startResponse);
|
|
2666
|
+
return await addBackgroundContext({
|
|
2667
|
+
content: [{
|
|
2668
|
+
type: "text",
|
|
2669
|
+
text: formatSuccessMessage("Deployment started", startResult) + "\n\nNote: You can check deployment status by querying the system.deployments table."
|
|
2670
|
+
}]
|
|
2671
|
+
});
|
|
2672
|
+
} catch (error) {
|
|
2673
|
+
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
2674
|
+
return {
|
|
2675
|
+
content: [{ type: "text", text: `Error starting deployment: ${errMsg}` }],
|
|
2676
|
+
isError: true
|
|
2677
|
+
};
|
|
2678
|
+
}
|
|
2679
|
+
})
|
|
2680
|
+
);
|
|
2681
|
+
} else {
|
|
2682
|
+
registerTool(
|
|
2683
|
+
"create-deployment",
|
|
2684
|
+
"Deploy source code from a directory. This tool zips files, uploads to cloud storage, and triggers deployment with optional environment variables and project settings.",
|
|
2685
|
+
{
|
|
2686
|
+
sourceDirectory: z29.string().describe('Absolute path to the source directory containing files to deploy (e.g., /Users/name/project or C:\\Users\\name\\project). Do not use relative paths like "."'),
|
|
2687
|
+
...startDeploymentRequestSchema.shape
|
|
2688
|
+
},
|
|
2689
|
+
withUsageTracking("create-deployment", async ({ sourceDirectory, projectSettings, envVars, meta }) => {
|
|
2690
|
+
try {
|
|
2691
|
+
const isAbsolutePath = sourceDirectory.startsWith("/") || /^[a-zA-Z]:[/\\]/.test(sourceDirectory);
|
|
2692
|
+
if (!isAbsolutePath) {
|
|
2224
2693
|
return {
|
|
2225
|
-
content: [
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
}
|
|
2230
|
-
],
|
|
2694
|
+
content: [{
|
|
2695
|
+
type: "text",
|
|
2696
|
+
text: `Error: sourceDirectory must be an absolute path, not a relative path like "${sourceDirectory}". Please provide the full path to the source directory (e.g., /Users/name/project on macOS/Linux or C:\\Users\\name\\project on Windows).`
|
|
2697
|
+
}],
|
|
2231
2698
|
isError: true
|
|
2232
2699
|
};
|
|
2233
2700
|
}
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
{
|
|
2701
|
+
try {
|
|
2702
|
+
const stats = await fs3.stat(sourceDirectory);
|
|
2703
|
+
if (!stats.isDirectory()) {
|
|
2704
|
+
return {
|
|
2705
|
+
content: [{
|
|
2706
|
+
type: "text",
|
|
2707
|
+
text: `Error: "${sourceDirectory}" is not a directory. Please provide a path to a directory containing the source code.`
|
|
2708
|
+
}],
|
|
2709
|
+
isError: true
|
|
2710
|
+
};
|
|
2711
|
+
}
|
|
2712
|
+
} catch {
|
|
2713
|
+
return {
|
|
2714
|
+
content: [{
|
|
2238
2715
|
type: "text",
|
|
2239
2716
|
text: `Error: Directory "${sourceDirectory}" does not exist or is not accessible. Please verify the path is correct.`
|
|
2240
|
-
}
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
};
|
|
2244
|
-
}
|
|
2245
|
-
const resolvedSourceDir = sourceDirectory;
|
|
2246
|
-
const createResponse = await fetch2(`${API_BASE_URL}/api/deployments`, {
|
|
2247
|
-
method: "POST",
|
|
2248
|
-
headers: {
|
|
2249
|
-
"x-api-key": getApiKey(),
|
|
2250
|
-
"Content-Type": "application/json"
|
|
2717
|
+
}],
|
|
2718
|
+
isError: true
|
|
2719
|
+
};
|
|
2251
2720
|
}
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
archive.on("data", (chunk) => chunks.push(chunk));
|
|
2259
|
-
archive.on("end", () => resolve(Buffer.concat(chunks)));
|
|
2260
|
-
archive.on("error", (err) => reject(err));
|
|
2261
|
-
const excludePatterns = [
|
|
2262
|
-
"node_modules",
|
|
2263
|
-
".git",
|
|
2264
|
-
".next",
|
|
2265
|
-
".env",
|
|
2266
|
-
".env.local",
|
|
2267
|
-
"dist",
|
|
2268
|
-
"build",
|
|
2269
|
-
".DS_Store"
|
|
2270
|
-
];
|
|
2271
|
-
archive.directory(resolvedSourceDir, false, (entry) => {
|
|
2272
|
-
const normalizedName = entry.name.replace(/\\/g, "/");
|
|
2273
|
-
for (const pattern of excludePatterns) {
|
|
2274
|
-
if (normalizedName.startsWith(pattern + "/") || normalizedName === pattern || normalizedName.endsWith("/" + pattern) || normalizedName.includes("/" + pattern + "/")) {
|
|
2275
|
-
return false;
|
|
2276
|
-
}
|
|
2721
|
+
const resolvedSourceDir = sourceDirectory;
|
|
2722
|
+
const createResponse = await fetch6(`${API_BASE_URL}/api/deployments`, {
|
|
2723
|
+
method: "POST",
|
|
2724
|
+
headers: {
|
|
2725
|
+
"x-api-key": getApiKey(),
|
|
2726
|
+
"Content-Type": "application/json"
|
|
2277
2727
|
}
|
|
2278
|
-
|
|
2279
|
-
|
|
2728
|
+
});
|
|
2729
|
+
const createResult = await handleApiResponse(createResponse);
|
|
2730
|
+
if (!isCreateDeploymentResponse(createResult)) {
|
|
2731
|
+
throw new Error("Unexpected response format from deployments endpoint");
|
|
2732
|
+
}
|
|
2733
|
+
const { id: deploymentId, uploadUrl, uploadFields } = createResult;
|
|
2734
|
+
const tmpZipPath = join2(tmpdir2(), `insforge-deploy-${deploymentId}.zip`);
|
|
2735
|
+
try {
|
|
2736
|
+
await new Promise((resolve, reject) => {
|
|
2737
|
+
const archive = archiver("zip", { zlib: { level: 9 } });
|
|
2738
|
+
const output = createWriteStream(tmpZipPath);
|
|
2739
|
+
output.on("close", resolve);
|
|
2740
|
+
output.on("error", reject);
|
|
2741
|
+
archive.on("error", reject);
|
|
2742
|
+
const excludePatterns = ["node_modules", ".git", ".next", ".env", ".env.local", "dist", "build", ".DS_Store"];
|
|
2743
|
+
archive.directory(resolvedSourceDir, false, (entry) => {
|
|
2744
|
+
const normalizedName = entry.name.replace(/\\/g, "/");
|
|
2745
|
+
for (const pattern of excludePatterns) {
|
|
2746
|
+
if (normalizedName.startsWith(pattern + "/") || normalizedName === pattern || normalizedName.endsWith("/" + pattern) || normalizedName.includes("/" + pattern + "/")) {
|
|
2747
|
+
return false;
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2750
|
+
if (normalizedName.endsWith(".log")) return false;
|
|
2751
|
+
return entry;
|
|
2752
|
+
});
|
|
2753
|
+
archive.pipe(output);
|
|
2754
|
+
archive.finalize();
|
|
2755
|
+
});
|
|
2756
|
+
const { size: zipSize } = await fs3.stat(tmpZipPath);
|
|
2757
|
+
const uploadFormData = new FormData2();
|
|
2758
|
+
for (const [key, value] of Object.entries(uploadFields)) {
|
|
2759
|
+
uploadFormData.append(key, value);
|
|
2760
|
+
}
|
|
2761
|
+
uploadFormData.append("file", createReadStream(tmpZipPath), {
|
|
2762
|
+
filename: "deployment.zip",
|
|
2763
|
+
contentType: "application/zip",
|
|
2764
|
+
knownLength: zipSize
|
|
2765
|
+
});
|
|
2766
|
+
const uploadResponse = await fetch6(uploadUrl, {
|
|
2767
|
+
method: "POST",
|
|
2768
|
+
body: uploadFormData,
|
|
2769
|
+
headers: uploadFormData.getHeaders()
|
|
2770
|
+
});
|
|
2771
|
+
if (!uploadResponse.ok) {
|
|
2772
|
+
const uploadError = await uploadResponse.text();
|
|
2773
|
+
throw new Error(`Failed to upload zip file: ${uploadError}`);
|
|
2280
2774
|
}
|
|
2281
|
-
|
|
2775
|
+
} finally {
|
|
2776
|
+
await fs3.rm(tmpZipPath, { force: true }).catch(() => void 0);
|
|
2777
|
+
}
|
|
2778
|
+
const startBody = {};
|
|
2779
|
+
if (projectSettings) startBody.projectSettings = projectSettings;
|
|
2780
|
+
if (envVars) startBody.envVars = envVars;
|
|
2781
|
+
if (meta) startBody.meta = meta;
|
|
2782
|
+
const startResponse = await fetch6(`${API_BASE_URL}/api/deployments/${encodeURIComponent(deploymentId)}/start`, {
|
|
2783
|
+
method: "POST",
|
|
2784
|
+
headers: {
|
|
2785
|
+
"x-api-key": getApiKey(),
|
|
2786
|
+
"Content-Type": "application/json"
|
|
2787
|
+
},
|
|
2788
|
+
body: JSON.stringify(startBody)
|
|
2282
2789
|
});
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
for (const [key, value] of Object.entries(uploadFields)) {
|
|
2287
|
-
uploadFormData.append(key, value);
|
|
2288
|
-
}
|
|
2289
|
-
uploadFormData.append("file", zipBuffer, {
|
|
2290
|
-
filename: "deployment.zip",
|
|
2291
|
-
contentType: "application/zip"
|
|
2292
|
-
});
|
|
2293
|
-
const uploadResponse = await fetch2(uploadUrl, {
|
|
2294
|
-
method: "POST",
|
|
2295
|
-
body: uploadFormData,
|
|
2296
|
-
headers: uploadFormData.getHeaders()
|
|
2297
|
-
});
|
|
2298
|
-
if (!uploadResponse.ok) {
|
|
2299
|
-
const uploadError = await uploadResponse.text();
|
|
2300
|
-
throw new Error(`Failed to upload zip file: ${uploadError}`);
|
|
2301
|
-
}
|
|
2302
|
-
const startBody = {};
|
|
2303
|
-
if (projectSettings) startBody.projectSettings = projectSettings;
|
|
2304
|
-
if (envVars) startBody.envVars = envVars;
|
|
2305
|
-
if (meta) startBody.meta = meta;
|
|
2306
|
-
const startResponse = await fetch2(`${API_BASE_URL}/api/deployments/${deploymentId}/start`, {
|
|
2307
|
-
method: "POST",
|
|
2308
|
-
headers: {
|
|
2309
|
-
"x-api-key": getApiKey(),
|
|
2310
|
-
"Content-Type": "application/json"
|
|
2311
|
-
},
|
|
2312
|
-
body: JSON.stringify(startBody)
|
|
2313
|
-
});
|
|
2314
|
-
const startResult = await handleApiResponse(startResponse);
|
|
2315
|
-
return await addBackgroundContext({
|
|
2316
|
-
content: [
|
|
2317
|
-
{
|
|
2790
|
+
const startResult = await handleApiResponse(startResponse);
|
|
2791
|
+
return await addBackgroundContext({
|
|
2792
|
+
content: [{
|
|
2318
2793
|
type: "text",
|
|
2319
2794
|
text: formatSuccessMessage("Deployment started", startResult) + "\n\nNote: You can check deployment status by querying the system.deployments table."
|
|
2320
|
-
}
|
|
2321
|
-
|
|
2322
|
-
})
|
|
2795
|
+
}]
|
|
2796
|
+
});
|
|
2797
|
+
} catch (error) {
|
|
2798
|
+
const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
|
|
2799
|
+
return {
|
|
2800
|
+
content: [{ type: "text", text: `Error creating deployment: ${errMsg}` }],
|
|
2801
|
+
isError: true
|
|
2802
|
+
};
|
|
2803
|
+
}
|
|
2804
|
+
})
|
|
2805
|
+
);
|
|
2806
|
+
}
|
|
2807
|
+
}
|
|
2808
|
+
|
|
2809
|
+
// src/shared/tools/index.ts
|
|
2810
|
+
var TOOL_VERSION_REQUIREMENTS = {
|
|
2811
|
+
// Schedule tools - require backend v1.1.1+
|
|
2812
|
+
// 'upsert-schedule': { minVersion: '1.1.1' },
|
|
2813
|
+
// 'delete-schedule': { minVersion: '1.1.1' },
|
|
2814
|
+
// 'get-schedules': { minVersion: '1.1.1' },
|
|
2815
|
+
// 'get-schedule-logs': { minVersion: '1.1.1' },
|
|
2816
|
+
"create-deployment": { minVersion: "1.4.7" },
|
|
2817
|
+
"fetch-sdk-docs": { minVersion: "1.5.1" }
|
|
2818
|
+
// Example of a deprecated tool (uncomment when needed):
|
|
2819
|
+
// 'legacy-tool': { minVersion: '1.0.0', maxVersion: '1.5.0' },
|
|
2820
|
+
};
|
|
2821
|
+
var LOCAL_ONLY_TOOLS = /* @__PURE__ */ new Set([
|
|
2822
|
+
"bulk-upsert"
|
|
2823
|
+
// Requires reading local data file (filePath is required)
|
|
2824
|
+
]);
|
|
2825
|
+
function compareVersions(v1, v2) {
|
|
2826
|
+
const clean1 = v1.replace(/^v/, "").split("-")[0];
|
|
2827
|
+
const clean2 = v2.replace(/^v/, "").split("-")[0];
|
|
2828
|
+
const parts1 = clean1.split(".").map(Number);
|
|
2829
|
+
const parts2 = clean2.split(".").map(Number);
|
|
2830
|
+
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
|
2831
|
+
const part1 = parts1[i] || 0;
|
|
2832
|
+
const part2 = parts2[i] || 0;
|
|
2833
|
+
if (part1 > part2) return 1;
|
|
2834
|
+
if (part1 < part2) return -1;
|
|
2835
|
+
}
|
|
2836
|
+
return 0;
|
|
2837
|
+
}
|
|
2838
|
+
function shouldRegisterTool(toolName, backendVersion) {
|
|
2839
|
+
const requirement = TOOL_VERSION_REQUIREMENTS[toolName];
|
|
2840
|
+
if (!requirement) return true;
|
|
2841
|
+
const { minVersion, maxVersion } = requirement;
|
|
2842
|
+
if (minVersion && compareVersions(backendVersion, minVersion) < 0) return false;
|
|
2843
|
+
if (maxVersion && compareVersions(backendVersion, maxVersion) > 0) return false;
|
|
2844
|
+
return true;
|
|
2845
|
+
}
|
|
2846
|
+
async function fetchBackendVersion(apiBaseUrl) {
|
|
2847
|
+
const controller = new AbortController();
|
|
2848
|
+
const timeoutId = setTimeout(() => controller.abort(), 1e4);
|
|
2849
|
+
try {
|
|
2850
|
+
const response = await fetch7(`${apiBaseUrl}/api/health`, {
|
|
2851
|
+
method: "GET",
|
|
2852
|
+
headers: { "Content-Type": "application/json" },
|
|
2853
|
+
signal: controller.signal
|
|
2854
|
+
});
|
|
2855
|
+
if (!response.ok) {
|
|
2856
|
+
throw new Error(`Health check failed with status ${response.status}`);
|
|
2857
|
+
}
|
|
2858
|
+
const health = await response.json();
|
|
2859
|
+
if (!health.version || typeof health.version !== "string") {
|
|
2860
|
+
throw new Error("Health check returned invalid version field");
|
|
2861
|
+
}
|
|
2862
|
+
return health.version;
|
|
2863
|
+
} catch (error) {
|
|
2864
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
2865
|
+
throw new Error(`Health check timed out after 10s \u2014 is the backend running at ${apiBaseUrl}?`, { cause: error });
|
|
2866
|
+
}
|
|
2867
|
+
throw error;
|
|
2868
|
+
} finally {
|
|
2869
|
+
clearTimeout(timeoutId);
|
|
2870
|
+
}
|
|
2871
|
+
}
|
|
2872
|
+
async function registerInsforgeTools(server, config = {}) {
|
|
2873
|
+
const GLOBAL_API_KEY = config.apiKey || process.env.API_KEY || "";
|
|
2874
|
+
const API_BASE_URL = config.apiBaseUrl || process.env.API_BASE_URL || "http://localhost:7130";
|
|
2875
|
+
const isRemote = config.mode === "remote";
|
|
2876
|
+
const usageTracker = new UsageTracker(API_BASE_URL, GLOBAL_API_KEY);
|
|
2877
|
+
let backendVersion;
|
|
2878
|
+
try {
|
|
2879
|
+
backendVersion = await fetchBackendVersion(API_BASE_URL);
|
|
2880
|
+
console.error(`Backend version: ${backendVersion}`);
|
|
2881
|
+
} catch (error) {
|
|
2882
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
2883
|
+
console.error(`Failed to fetch backend version: ${msg}`);
|
|
2884
|
+
throw new Error(`Cannot initialize tools: backend at ${API_BASE_URL} is unreachable. ${msg}`, { cause: error });
|
|
2885
|
+
}
|
|
2886
|
+
let toolCount = 0;
|
|
2887
|
+
const registerTool = (toolName, ...args) => {
|
|
2888
|
+
if (isRemote && LOCAL_ONLY_TOOLS.has(toolName)) {
|
|
2889
|
+
console.error(`Skipping tool '${toolName}': requires local filesystem (remote mode)`);
|
|
2890
|
+
return false;
|
|
2891
|
+
}
|
|
2892
|
+
if (shouldRegisterTool(toolName, backendVersion)) {
|
|
2893
|
+
server.tool(toolName, ...args);
|
|
2894
|
+
toolCount++;
|
|
2895
|
+
return true;
|
|
2896
|
+
} else {
|
|
2897
|
+
const req = TOOL_VERSION_REQUIREMENTS[toolName];
|
|
2898
|
+
const reason = req?.minVersion && compareVersions(backendVersion, req.minVersion) < 0 ? `requires backend >= ${req.minVersion}` : `deprecated after backend ${req?.maxVersion}`;
|
|
2899
|
+
console.error(`Skipping tool '${toolName}': ${reason} (current: ${backendVersion})`);
|
|
2900
|
+
return false;
|
|
2901
|
+
}
|
|
2902
|
+
};
|
|
2903
|
+
async function trackToolUsage(toolName, success = true) {
|
|
2904
|
+
if (GLOBAL_API_KEY) {
|
|
2905
|
+
await usageTracker.trackUsage(toolName, success).catch((err) => {
|
|
2906
|
+
console.error(`Failed to track usage for '${toolName}':`, err);
|
|
2907
|
+
});
|
|
2908
|
+
}
|
|
2909
|
+
}
|
|
2910
|
+
function withUsageTracking(toolName, handler) {
|
|
2911
|
+
return async (...args) => {
|
|
2912
|
+
try {
|
|
2913
|
+
const result = await handler(...args);
|
|
2914
|
+
const isStructuredError = result !== null && typeof result === "object" && "isError" in result && result["isError"] === true;
|
|
2915
|
+
void trackToolUsage(toolName, !isStructuredError);
|
|
2916
|
+
return result;
|
|
2323
2917
|
} catch (error) {
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2918
|
+
void trackToolUsage(toolName, false);
|
|
2919
|
+
throw error;
|
|
2920
|
+
}
|
|
2921
|
+
};
|
|
2922
|
+
}
|
|
2923
|
+
const getApiKey = (toolApiKey) => {
|
|
2924
|
+
const apiKey = toolApiKey?.trim() || GLOBAL_API_KEY;
|
|
2925
|
+
if (!apiKey) {
|
|
2926
|
+
throw new Error("API key is required. Pass --api_key when starting the MCP server.");
|
|
2927
|
+
}
|
|
2928
|
+
return apiKey;
|
|
2929
|
+
};
|
|
2930
|
+
const addBackgroundContext = async (response) => {
|
|
2931
|
+
const isLegacyVersion = compareVersions(backendVersion, "1.1.7") < 0;
|
|
2932
|
+
if (isLegacyVersion) {
|
|
2933
|
+
try {
|
|
2934
|
+
const docResponse = await fetch7(`${API_BASE_URL}/api/docs/instructions`, {
|
|
2935
|
+
method: "GET",
|
|
2936
|
+
headers: { "Content-Type": "application/json" }
|
|
2937
|
+
});
|
|
2938
|
+
if (docResponse.ok) {
|
|
2939
|
+
const result = await handleApiResponse(docResponse);
|
|
2940
|
+
if (result && typeof result === "object" && "content" in result) {
|
|
2941
|
+
response.content.push({
|
|
2328
2942
|
type: "text",
|
|
2329
|
-
text: `
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2943
|
+
text: `
|
|
2944
|
+
|
|
2945
|
+
---
|
|
2946
|
+
\u{1F527} INSFORGE DEVELOPMENT RULES (Auto-loaded):
|
|
2947
|
+
${result.content}`
|
|
2948
|
+
});
|
|
2949
|
+
}
|
|
2950
|
+
}
|
|
2951
|
+
} catch (error) {
|
|
2952
|
+
console.error("Failed to fetch insforge-instructions.md:", error);
|
|
2334
2953
|
}
|
|
2335
|
-
}
|
|
2336
|
-
|
|
2954
|
+
}
|
|
2955
|
+
return response;
|
|
2956
|
+
};
|
|
2957
|
+
const ctx = {
|
|
2958
|
+
API_BASE_URL,
|
|
2959
|
+
isRemote,
|
|
2960
|
+
registerTool,
|
|
2961
|
+
withUsageTracking,
|
|
2962
|
+
getApiKey,
|
|
2963
|
+
addBackgroundContext
|
|
2964
|
+
};
|
|
2965
|
+
registerDocsTools(ctx);
|
|
2966
|
+
registerDatabaseTools(ctx);
|
|
2967
|
+
registerStorageTools(ctx);
|
|
2968
|
+
registerFunctionTools(ctx);
|
|
2969
|
+
registerDeploymentTools(ctx);
|
|
2337
2970
|
return {
|
|
2338
2971
|
apiKey: GLOBAL_API_KEY,
|
|
2339
2972
|
apiBaseUrl: API_BASE_URL,
|
|
2340
|
-
|
|
2341
|
-
|
|
2973
|
+
backendVersion,
|
|
2974
|
+
toolCount
|
|
2342
2975
|
};
|
|
2343
2976
|
}
|
|
2344
2977
|
|