@schuttdev/gigai 0.2.5 → 0.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/dist/{dist-G2KJBUZX.js → dist-MGLETZTT.js} +283 -30
- package/dist/index.js +155 -963
- package/package.json +3 -4
- package/dist/chunk-7C3UYEKE.js +0 -281
|
@@ -1,12 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
ErrorCode,
|
|
4
|
-
GigaiConfigSchema,
|
|
5
|
-
GigaiError,
|
|
6
|
-
decrypt,
|
|
7
|
-
encrypt,
|
|
8
|
-
generateEncryptionKey
|
|
9
|
-
} from "./chunk-7C3UYEKE.js";
|
|
10
2
|
|
|
11
3
|
// ../server/dist/index.mjs
|
|
12
4
|
import { parseArgs } from "util";
|
|
@@ -14,9 +6,270 @@ import Fastify from "fastify";
|
|
|
14
6
|
import cors from "@fastify/cors";
|
|
15
7
|
import rateLimit from "@fastify/rate-limit";
|
|
16
8
|
import multipart from "@fastify/multipart";
|
|
9
|
+
|
|
10
|
+
// ../shared/dist/index.mjs
|
|
11
|
+
import { randomBytes, createCipheriv, createDecipheriv } from "crypto";
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
var ALGORITHM = "aes-256-gcm";
|
|
14
|
+
var IV_LENGTH = 12;
|
|
15
|
+
var TAG_LENGTH = 16;
|
|
16
|
+
function encrypt(payload, key) {
|
|
17
|
+
const keyBuffer = Buffer.from(key, "hex");
|
|
18
|
+
if (keyBuffer.length !== 32) {
|
|
19
|
+
throw new Error("Encryption key must be 32 bytes (64 hex chars)");
|
|
20
|
+
}
|
|
21
|
+
const iv = randomBytes(IV_LENGTH);
|
|
22
|
+
const cipher = createCipheriv(ALGORITHM, keyBuffer, iv, {
|
|
23
|
+
authTagLength: TAG_LENGTH
|
|
24
|
+
});
|
|
25
|
+
const plaintext = JSON.stringify(payload);
|
|
26
|
+
const encrypted = Buffer.concat([
|
|
27
|
+
cipher.update(plaintext, "utf8"),
|
|
28
|
+
cipher.final()
|
|
29
|
+
]);
|
|
30
|
+
const tag = cipher.getAuthTag();
|
|
31
|
+
return {
|
|
32
|
+
iv: iv.toString("base64"),
|
|
33
|
+
ciphertext: encrypted.toString("base64"),
|
|
34
|
+
tag: tag.toString("base64")
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function decrypt(encrypted, key) {
|
|
38
|
+
const keyBuffer = Buffer.from(key, "hex");
|
|
39
|
+
if (keyBuffer.length !== 32) {
|
|
40
|
+
throw new Error("Encryption key must be 32 bytes (64 hex chars)");
|
|
41
|
+
}
|
|
42
|
+
const iv = Buffer.from(encrypted.iv, "base64");
|
|
43
|
+
const ciphertext = Buffer.from(encrypted.ciphertext, "base64");
|
|
44
|
+
const tag = Buffer.from(encrypted.tag, "base64");
|
|
45
|
+
const decipher = createDecipheriv(ALGORITHM, keyBuffer, iv, {
|
|
46
|
+
authTagLength: TAG_LENGTH
|
|
47
|
+
});
|
|
48
|
+
decipher.setAuthTag(tag);
|
|
49
|
+
const decrypted = Buffer.concat([
|
|
50
|
+
decipher.update(ciphertext),
|
|
51
|
+
decipher.final()
|
|
52
|
+
]);
|
|
53
|
+
return JSON.parse(decrypted.toString("utf8"));
|
|
54
|
+
}
|
|
55
|
+
function generateEncryptionKey() {
|
|
56
|
+
return randomBytes(32).toString("hex");
|
|
57
|
+
}
|
|
58
|
+
var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
|
|
59
|
+
ErrorCode2["PAIRING_EXPIRED"] = "PAIRING_EXPIRED";
|
|
60
|
+
ErrorCode2["PAIRING_INVALID"] = "PAIRING_INVALID";
|
|
61
|
+
ErrorCode2["PAIRING_USED"] = "PAIRING_USED";
|
|
62
|
+
ErrorCode2["TOKEN_INVALID"] = "TOKEN_INVALID";
|
|
63
|
+
ErrorCode2["TOKEN_DECRYPT_FAILED"] = "TOKEN_DECRYPT_FAILED";
|
|
64
|
+
ErrorCode2["ORG_MISMATCH"] = "ORG_MISMATCH";
|
|
65
|
+
ErrorCode2["SESSION_EXPIRED"] = "SESSION_EXPIRED";
|
|
66
|
+
ErrorCode2["SESSION_INVALID"] = "SESSION_INVALID";
|
|
67
|
+
ErrorCode2["AUTH_REQUIRED"] = "AUTH_REQUIRED";
|
|
68
|
+
ErrorCode2["TOOL_NOT_FOUND"] = "TOOL_NOT_FOUND";
|
|
69
|
+
ErrorCode2["EXEC_TIMEOUT"] = "EXEC_TIMEOUT";
|
|
70
|
+
ErrorCode2["EXEC_FAILED"] = "EXEC_FAILED";
|
|
71
|
+
ErrorCode2["HTTPS_REQUIRED"] = "HTTPS_REQUIRED";
|
|
72
|
+
ErrorCode2["RATE_LIMITED"] = "RATE_LIMITED";
|
|
73
|
+
ErrorCode2["VALIDATION_ERROR"] = "VALIDATION_ERROR";
|
|
74
|
+
ErrorCode2["INTERNAL_ERROR"] = "INTERNAL_ERROR";
|
|
75
|
+
ErrorCode2["MCP_ERROR"] = "MCP_ERROR";
|
|
76
|
+
ErrorCode2["MCP_NOT_CONNECTED"] = "MCP_NOT_CONNECTED";
|
|
77
|
+
ErrorCode2["TRANSFER_NOT_FOUND"] = "TRANSFER_NOT_FOUND";
|
|
78
|
+
ErrorCode2["TRANSFER_EXPIRED"] = "TRANSFER_EXPIRED";
|
|
79
|
+
ErrorCode2["PATH_NOT_ALLOWED"] = "PATH_NOT_ALLOWED";
|
|
80
|
+
ErrorCode2["COMMAND_NOT_ALLOWED"] = "COMMAND_NOT_ALLOWED";
|
|
81
|
+
return ErrorCode2;
|
|
82
|
+
})(ErrorCode || {});
|
|
83
|
+
var STATUS_CODES = {
|
|
84
|
+
[
|
|
85
|
+
"PAIRING_EXPIRED"
|
|
86
|
+
/* PAIRING_EXPIRED */
|
|
87
|
+
]: 410,
|
|
88
|
+
[
|
|
89
|
+
"PAIRING_INVALID"
|
|
90
|
+
/* PAIRING_INVALID */
|
|
91
|
+
]: 400,
|
|
92
|
+
[
|
|
93
|
+
"PAIRING_USED"
|
|
94
|
+
/* PAIRING_USED */
|
|
95
|
+
]: 409,
|
|
96
|
+
[
|
|
97
|
+
"TOKEN_INVALID"
|
|
98
|
+
/* TOKEN_INVALID */
|
|
99
|
+
]: 401,
|
|
100
|
+
[
|
|
101
|
+
"TOKEN_DECRYPT_FAILED"
|
|
102
|
+
/* TOKEN_DECRYPT_FAILED */
|
|
103
|
+
]: 401,
|
|
104
|
+
[
|
|
105
|
+
"ORG_MISMATCH"
|
|
106
|
+
/* ORG_MISMATCH */
|
|
107
|
+
]: 403,
|
|
108
|
+
[
|
|
109
|
+
"SESSION_EXPIRED"
|
|
110
|
+
/* SESSION_EXPIRED */
|
|
111
|
+
]: 401,
|
|
112
|
+
[
|
|
113
|
+
"SESSION_INVALID"
|
|
114
|
+
/* SESSION_INVALID */
|
|
115
|
+
]: 401,
|
|
116
|
+
[
|
|
117
|
+
"AUTH_REQUIRED"
|
|
118
|
+
/* AUTH_REQUIRED */
|
|
119
|
+
]: 401,
|
|
120
|
+
[
|
|
121
|
+
"TOOL_NOT_FOUND"
|
|
122
|
+
/* TOOL_NOT_FOUND */
|
|
123
|
+
]: 404,
|
|
124
|
+
[
|
|
125
|
+
"EXEC_TIMEOUT"
|
|
126
|
+
/* EXEC_TIMEOUT */
|
|
127
|
+
]: 408,
|
|
128
|
+
[
|
|
129
|
+
"EXEC_FAILED"
|
|
130
|
+
/* EXEC_FAILED */
|
|
131
|
+
]: 500,
|
|
132
|
+
[
|
|
133
|
+
"HTTPS_REQUIRED"
|
|
134
|
+
/* HTTPS_REQUIRED */
|
|
135
|
+
]: 403,
|
|
136
|
+
[
|
|
137
|
+
"RATE_LIMITED"
|
|
138
|
+
/* RATE_LIMITED */
|
|
139
|
+
]: 429,
|
|
140
|
+
[
|
|
141
|
+
"VALIDATION_ERROR"
|
|
142
|
+
/* VALIDATION_ERROR */
|
|
143
|
+
]: 400,
|
|
144
|
+
[
|
|
145
|
+
"INTERNAL_ERROR"
|
|
146
|
+
/* INTERNAL_ERROR */
|
|
147
|
+
]: 500,
|
|
148
|
+
[
|
|
149
|
+
"MCP_ERROR"
|
|
150
|
+
/* MCP_ERROR */
|
|
151
|
+
]: 502,
|
|
152
|
+
[
|
|
153
|
+
"MCP_NOT_CONNECTED"
|
|
154
|
+
/* MCP_NOT_CONNECTED */
|
|
155
|
+
]: 503,
|
|
156
|
+
[
|
|
157
|
+
"TRANSFER_NOT_FOUND"
|
|
158
|
+
/* TRANSFER_NOT_FOUND */
|
|
159
|
+
]: 404,
|
|
160
|
+
[
|
|
161
|
+
"TRANSFER_EXPIRED"
|
|
162
|
+
/* TRANSFER_EXPIRED */
|
|
163
|
+
]: 410,
|
|
164
|
+
[
|
|
165
|
+
"PATH_NOT_ALLOWED"
|
|
166
|
+
/* PATH_NOT_ALLOWED */
|
|
167
|
+
]: 403,
|
|
168
|
+
[
|
|
169
|
+
"COMMAND_NOT_ALLOWED"
|
|
170
|
+
/* COMMAND_NOT_ALLOWED */
|
|
171
|
+
]: 403
|
|
172
|
+
};
|
|
173
|
+
var GigaiError = class extends Error {
|
|
174
|
+
code;
|
|
175
|
+
statusCode;
|
|
176
|
+
details;
|
|
177
|
+
constructor(code, message, details) {
|
|
178
|
+
super(message);
|
|
179
|
+
this.name = "GigaiError";
|
|
180
|
+
this.code = code;
|
|
181
|
+
this.statusCode = STATUS_CODES[code];
|
|
182
|
+
this.details = details;
|
|
183
|
+
}
|
|
184
|
+
toJSON() {
|
|
185
|
+
return {
|
|
186
|
+
error: {
|
|
187
|
+
code: this.code,
|
|
188
|
+
message: this.message,
|
|
189
|
+
...this.details !== void 0 && { details: this.details }
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
var TailscaleHttpsConfigSchema = z.object({
|
|
195
|
+
provider: z.literal("tailscale"),
|
|
196
|
+
funnelPort: z.number().optional()
|
|
197
|
+
});
|
|
198
|
+
var CloudflareHttpsConfigSchema = z.object({
|
|
199
|
+
provider: z.literal("cloudflare"),
|
|
200
|
+
tunnelName: z.string(),
|
|
201
|
+
domain: z.string().optional()
|
|
202
|
+
});
|
|
203
|
+
var ManualHttpsConfigSchema = z.object({
|
|
204
|
+
provider: z.literal("manual"),
|
|
205
|
+
certPath: z.string(),
|
|
206
|
+
keyPath: z.string()
|
|
207
|
+
});
|
|
208
|
+
var HttpsConfigSchema = z.discriminatedUnion("provider", [
|
|
209
|
+
TailscaleHttpsConfigSchema,
|
|
210
|
+
CloudflareHttpsConfigSchema,
|
|
211
|
+
ManualHttpsConfigSchema
|
|
212
|
+
]);
|
|
213
|
+
var CliToolConfigSchema = z.object({
|
|
214
|
+
type: z.literal("cli"),
|
|
215
|
+
name: z.string(),
|
|
216
|
+
command: z.string(),
|
|
217
|
+
args: z.array(z.string()).optional(),
|
|
218
|
+
description: z.string(),
|
|
219
|
+
timeout: z.number().optional(),
|
|
220
|
+
cwd: z.string().optional(),
|
|
221
|
+
env: z.record(z.string()).optional()
|
|
222
|
+
});
|
|
223
|
+
var McpToolConfigSchema = z.object({
|
|
224
|
+
type: z.literal("mcp"),
|
|
225
|
+
name: z.string(),
|
|
226
|
+
command: z.string(),
|
|
227
|
+
args: z.array(z.string()).optional(),
|
|
228
|
+
description: z.string(),
|
|
229
|
+
env: z.record(z.string()).optional()
|
|
230
|
+
});
|
|
231
|
+
var ScriptToolConfigSchema = z.object({
|
|
232
|
+
type: z.literal("script"),
|
|
233
|
+
name: z.string(),
|
|
234
|
+
path: z.string(),
|
|
235
|
+
description: z.string(),
|
|
236
|
+
timeout: z.number().optional(),
|
|
237
|
+
interpreter: z.string().optional()
|
|
238
|
+
});
|
|
239
|
+
var BuiltinToolConfigSchema = z.object({
|
|
240
|
+
type: z.literal("builtin"),
|
|
241
|
+
name: z.string(),
|
|
242
|
+
builtin: z.enum(["filesystem", "shell"]),
|
|
243
|
+
description: z.string(),
|
|
244
|
+
config: z.record(z.unknown()).optional()
|
|
245
|
+
});
|
|
246
|
+
var ToolConfigSchema = z.discriminatedUnion("type", [
|
|
247
|
+
CliToolConfigSchema,
|
|
248
|
+
McpToolConfigSchema,
|
|
249
|
+
ScriptToolConfigSchema,
|
|
250
|
+
BuiltinToolConfigSchema
|
|
251
|
+
]);
|
|
252
|
+
var AuthConfigSchema = z.object({
|
|
253
|
+
encryptionKey: z.string().length(64),
|
|
254
|
+
pairingTtlSeconds: z.number().default(300),
|
|
255
|
+
sessionTtlSeconds: z.number().default(14400)
|
|
256
|
+
});
|
|
257
|
+
var ServerConfigSchema = z.object({
|
|
258
|
+
port: z.number().default(7443),
|
|
259
|
+
host: z.string().default("0.0.0.0"),
|
|
260
|
+
https: HttpsConfigSchema.optional()
|
|
261
|
+
});
|
|
262
|
+
var GigaiConfigSchema = z.object({
|
|
263
|
+
serverName: z.string().optional(),
|
|
264
|
+
server: ServerConfigSchema,
|
|
265
|
+
auth: AuthConfigSchema,
|
|
266
|
+
tools: z.array(ToolConfigSchema).default([])
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// ../server/dist/index.mjs
|
|
17
270
|
import fp from "fastify-plugin";
|
|
18
271
|
import { nanoid } from "nanoid";
|
|
19
|
-
import { randomBytes } from "crypto";
|
|
272
|
+
import { randomBytes as randomBytes2 } from "crypto";
|
|
20
273
|
import { hostname } from "os";
|
|
21
274
|
import { nanoid as nanoid2 } from "nanoid";
|
|
22
275
|
import fp2 from "fastify-plugin";
|
|
@@ -25,19 +278,19 @@ import { spawn } from "child_process";
|
|
|
25
278
|
import fp4 from "fastify-plugin";
|
|
26
279
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
27
280
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
28
|
-
import {
|
|
281
|
+
import { readFileSync } from "fs";
|
|
29
282
|
import { resolve } from "path";
|
|
30
283
|
import { readFile as fsReadFile, readdir } from "fs/promises";
|
|
31
284
|
import { resolve as resolve2, relative, join } from "path";
|
|
32
285
|
import { realpath } from "fs/promises";
|
|
33
286
|
import { spawn as spawn2 } from "child_process";
|
|
34
|
-
import { writeFile, readFile
|
|
287
|
+
import { writeFile, readFile, unlink, mkdir } from "fs/promises";
|
|
35
288
|
import { join as join2 } from "path";
|
|
36
289
|
import { tmpdir } from "os";
|
|
37
290
|
import { nanoid as nanoid3 } from "nanoid";
|
|
38
291
|
import { execFile, spawn as spawn3 } from "child_process";
|
|
39
292
|
import { promisify } from "util";
|
|
40
|
-
import { readFile as
|
|
293
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
41
294
|
import { resolve as resolve3 } from "path";
|
|
42
295
|
import { spawn as spawn4 } from "child_process";
|
|
43
296
|
import { spawn as spawn5 } from "child_process";
|
|
@@ -47,7 +300,7 @@ import { resolve as resolve4 } from "path";
|
|
|
47
300
|
import { execFile as execFile2, spawn as spawn6 } from "child_process";
|
|
48
301
|
import { promisify as promisify2 } from "util";
|
|
49
302
|
import { input as input2 } from "@inquirer/prompts";
|
|
50
|
-
import { readFile as
|
|
303
|
+
import { readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
51
304
|
import { resolve as resolve5 } from "path";
|
|
52
305
|
import { writeFile as writeFile4 } from "fs/promises";
|
|
53
306
|
import { resolve as resolve6, join as join3 } from "path";
|
|
@@ -187,7 +440,7 @@ function validateAndPair(store, code, orgUuid, encryptionKey, serverFingerprint)
|
|
|
187
440
|
);
|
|
188
441
|
}
|
|
189
442
|
function registerAuthRoutes(server, store, config) {
|
|
190
|
-
const serverFingerprint =
|
|
443
|
+
const serverFingerprint = randomBytes2(16).toString("hex");
|
|
191
444
|
const serverName = config.serverName ?? hostname();
|
|
192
445
|
server.post("/auth/pair", {
|
|
193
446
|
config: {
|
|
@@ -565,21 +818,21 @@ var mcpPlugin = fp4(async (server, opts) => {
|
|
|
565
818
|
});
|
|
566
819
|
}, { name: "mcp" });
|
|
567
820
|
var startTime = Date.now();
|
|
821
|
+
var startupVersion = "0.0.0";
|
|
822
|
+
try {
|
|
823
|
+
const pkg = JSON.parse(
|
|
824
|
+
readFileSync(resolve(import.meta.dirname ?? ".", "../package.json"), "utf8")
|
|
825
|
+
);
|
|
826
|
+
startupVersion = pkg.version;
|
|
827
|
+
} catch {
|
|
828
|
+
}
|
|
568
829
|
async function healthRoutes(server) {
|
|
569
830
|
server.get("/health", {
|
|
570
831
|
config: { skipAuth: true }
|
|
571
832
|
}, async () => {
|
|
572
|
-
let version = "0.1.0";
|
|
573
|
-
try {
|
|
574
|
-
const pkg = JSON.parse(
|
|
575
|
-
await readFile(resolve(import.meta.dirname ?? ".", "../package.json"), "utf8")
|
|
576
|
-
);
|
|
577
|
-
version = pkg.version;
|
|
578
|
-
} catch {
|
|
579
|
-
}
|
|
580
833
|
return {
|
|
581
834
|
status: "ok",
|
|
582
|
-
version,
|
|
835
|
+
version: startupVersion,
|
|
583
836
|
uptime: Date.now() - startTime
|
|
584
837
|
};
|
|
585
838
|
});
|
|
@@ -872,7 +1125,7 @@ async function transferRoutes(server) {
|
|
|
872
1125
|
transfers.delete(id);
|
|
873
1126
|
throw new GigaiError(ErrorCode.TRANSFER_EXPIRED, "Transfer expired");
|
|
874
1127
|
}
|
|
875
|
-
const content = await
|
|
1128
|
+
const content = await readFile(entry.path);
|
|
876
1129
|
reply.type(entry.mimeType).send(content);
|
|
877
1130
|
});
|
|
878
1131
|
}
|
|
@@ -969,7 +1222,7 @@ async function createServer(opts) {
|
|
|
969
1222
|
var DEFAULT_CONFIG_PATH = "gigai.config.json";
|
|
970
1223
|
async function loadConfig(path) {
|
|
971
1224
|
const configPath = resolve3(path ?? DEFAULT_CONFIG_PATH);
|
|
972
|
-
const raw = await
|
|
1225
|
+
const raw = await readFile2(configPath, "utf8");
|
|
973
1226
|
const json = JSON.parse(raw);
|
|
974
1227
|
return GigaiConfigSchema.parse(json);
|
|
975
1228
|
}
|
|
@@ -1272,11 +1525,11 @@ async function runInit() {
|
|
|
1272
1525
|
Paste this into Claude to pair:
|
|
1273
1526
|
`);
|
|
1274
1527
|
console.log(` \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`);
|
|
1275
|
-
console.log(` Install
|
|
1528
|
+
console.log(` Install kon and pair with my server:
|
|
1276
1529
|
`);
|
|
1277
1530
|
console.log(` \`\`\`bash`);
|
|
1278
|
-
console.log(` npm install -g @schuttdev/
|
|
1279
|
-
console.log(`
|
|
1531
|
+
console.log(` npm install -g @schuttdev/kon`);
|
|
1532
|
+
console.log(` kon pair ${code} ${serverUrl}`);
|
|
1280
1533
|
console.log(` \`\`\`
|
|
1281
1534
|
`);
|
|
1282
1535
|
console.log(` Then show me the skill file output so I can save it.`);
|
|
@@ -1288,7 +1541,7 @@ async function runInit() {
|
|
|
1288
1541
|
}
|
|
1289
1542
|
async function loadConfigFile(path) {
|
|
1290
1543
|
const configPath = resolve5(path ?? "gigai.config.json");
|
|
1291
|
-
const raw = await
|
|
1544
|
+
const raw = await readFile3(configPath, "utf8");
|
|
1292
1545
|
const config = GigaiConfigSchema.parse(JSON.parse(raw));
|
|
1293
1546
|
return { config, path: configPath };
|
|
1294
1547
|
}
|
|
@@ -1363,7 +1616,7 @@ async function wrapScript() {
|
|
|
1363
1616
|
}
|
|
1364
1617
|
async function wrapImport(configFilePath) {
|
|
1365
1618
|
const { config, path } = await loadConfigFile();
|
|
1366
|
-
const raw = await
|
|
1619
|
+
const raw = await readFile3(resolve5(configFilePath), "utf8");
|
|
1367
1620
|
const desktopConfig = JSON.parse(raw);
|
|
1368
1621
|
const mcpServers = desktopConfig.mcpServers ?? {};
|
|
1369
1622
|
for (const [serverName, serverConfig] of Object.entries(mcpServers)) {
|