@schuttdev/gigai 0.2.8 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,330 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ErrorCode,
4
+ GigaiError
5
+ } from "./chunk-P53UVHTF.js";
6
+
7
+ // ../server/dist/chunk-PO3MFBDO.mjs
8
+ import {
9
+ readFile as fsReadFile,
10
+ writeFile as fsWriteFile,
11
+ readdir
12
+ } from "fs/promises";
13
+ import { resolve, relative, join } from "path";
14
+ import { realpath } from "fs/promises";
15
+ import { spawn } from "child_process";
16
+ var MAX_OUTPUT_SIZE = 10 * 1024 * 1024;
17
+ var MAX_READ_SIZE = 2 * 1024 * 1024;
18
+ async function validatePath(targetPath, allowedPaths) {
19
+ const resolved = resolve(targetPath);
20
+ let real;
21
+ try {
22
+ real = await realpath(resolved);
23
+ } catch {
24
+ real = resolved;
25
+ }
26
+ const isAllowed = allowedPaths.some((allowed) => {
27
+ const resolvedAllowed = resolve(allowed);
28
+ const allowedPrefix = resolvedAllowed.endsWith("/") ? resolvedAllowed : resolvedAllowed + "/";
29
+ return real === resolvedAllowed || real.startsWith(allowedPrefix) || resolved === resolvedAllowed || resolved.startsWith(allowedPrefix);
30
+ });
31
+ if (!isAllowed) {
32
+ throw new GigaiError(
33
+ ErrorCode.PATH_NOT_ALLOWED,
34
+ `Path not within allowed directories: ${targetPath}`
35
+ );
36
+ }
37
+ return resolved;
38
+ }
39
+ async function readFileSafe(path, allowedPaths) {
40
+ const safePath = await validatePath(path, allowedPaths);
41
+ return fsReadFile(safePath, "utf8");
42
+ }
43
+ async function listDirSafe(path, allowedPaths) {
44
+ const safePath = await validatePath(path, allowedPaths);
45
+ const entries = await readdir(safePath, { withFileTypes: true });
46
+ return entries.map((e) => ({
47
+ name: e.name,
48
+ type: e.isDirectory() ? "directory" : "file"
49
+ }));
50
+ }
51
+ async function searchFilesSafe(path, pattern, allowedPaths) {
52
+ const safePath = await validatePath(path, allowedPaths);
53
+ const results = [];
54
+ let regex;
55
+ try {
56
+ regex = new RegExp(pattern, "i");
57
+ } catch {
58
+ throw new GigaiError(ErrorCode.VALIDATION_ERROR, `Invalid search pattern: ${pattern}`);
59
+ }
60
+ async function walk(dir) {
61
+ const entries = await readdir(dir, { withFileTypes: true });
62
+ for (const entry of entries) {
63
+ const fullPath = join(dir, entry.name);
64
+ if (regex.test(entry.name)) {
65
+ results.push(relative(safePath, fullPath));
66
+ }
67
+ if (entry.isDirectory()) {
68
+ await walk(fullPath);
69
+ }
70
+ }
71
+ }
72
+ await walk(safePath);
73
+ return results;
74
+ }
75
+ async function readBuiltin(args, allowedPaths) {
76
+ const filePath = args[0];
77
+ if (!filePath) {
78
+ throw new GigaiError(ErrorCode.VALIDATION_ERROR, "Usage: read <file> [offset] [limit]");
79
+ }
80
+ const safePath = await validatePath(filePath, allowedPaths);
81
+ const content = await fsReadFile(safePath, "utf8");
82
+ if (content.length > MAX_READ_SIZE) {
83
+ throw new GigaiError(
84
+ ErrorCode.VALIDATION_ERROR,
85
+ `File too large (${(content.length / 1024 / 1024).toFixed(1)}MB). Max: ${MAX_READ_SIZE / 1024 / 1024}MB. Use offset/limit.`
86
+ );
87
+ }
88
+ const offset = args[1] ? parseInt(args[1], 10) : 0;
89
+ const limit = args[2] ? parseInt(args[2], 10) : 0;
90
+ if (offset || limit) {
91
+ const lines = content.split("\n");
92
+ const start = Math.max(0, offset);
93
+ const end = limit ? start + limit : lines.length;
94
+ const sliced = lines.slice(start, end);
95
+ return { stdout: sliced.join("\n"), stderr: "", exitCode: 0 };
96
+ }
97
+ return { stdout: content, stderr: "", exitCode: 0 };
98
+ }
99
+ async function writeBuiltin(args, allowedPaths) {
100
+ const filePath = args[0];
101
+ const content = args[1];
102
+ if (!filePath || content === void 0) {
103
+ throw new GigaiError(ErrorCode.VALIDATION_ERROR, "Usage: write <file> <content>");
104
+ }
105
+ const safePath = await validatePath(filePath, allowedPaths);
106
+ const { mkdir } = await import("fs/promises");
107
+ const { dirname } = await import("path");
108
+ await mkdir(dirname(safePath), { recursive: true });
109
+ await fsWriteFile(safePath, content, "utf8");
110
+ return { stdout: `Written: ${safePath}`, stderr: "", exitCode: 0 };
111
+ }
112
+ async function editBuiltin(args, allowedPaths) {
113
+ const filePath = args[0];
114
+ const oldStr = args[1];
115
+ const newStr = args[2];
116
+ const replaceAll = args.includes("--all");
117
+ if (!filePath || oldStr === void 0 || newStr === void 0) {
118
+ throw new GigaiError(ErrorCode.VALIDATION_ERROR, "Usage: edit <file> <old_string> <new_string> [--all]");
119
+ }
120
+ const safePath = await validatePath(filePath, allowedPaths);
121
+ const content = await fsReadFile(safePath, "utf8");
122
+ if (!content.includes(oldStr)) {
123
+ throw new GigaiError(ErrorCode.VALIDATION_ERROR, "old_string not found in file");
124
+ }
125
+ if (!replaceAll) {
126
+ const firstIdx = content.indexOf(oldStr);
127
+ const secondIdx = content.indexOf(oldStr, firstIdx + 1);
128
+ if (secondIdx !== -1) {
129
+ throw new GigaiError(
130
+ ErrorCode.VALIDATION_ERROR,
131
+ "old_string matches multiple locations. Use --all to replace all, or provide more context to make it unique."
132
+ );
133
+ }
134
+ }
135
+ const updated = replaceAll ? content.split(oldStr).join(newStr) : content.replace(oldStr, newStr);
136
+ await fsWriteFile(safePath, updated, "utf8");
137
+ const count = replaceAll ? content.split(oldStr).length - 1 : 1;
138
+ return { stdout: `Replaced ${count} occurrence(s) in ${safePath}`, stderr: "", exitCode: 0 };
139
+ }
140
+ async function globBuiltin(args, allowedPaths) {
141
+ const pattern = args[0];
142
+ if (!pattern) {
143
+ throw new GigaiError(ErrorCode.VALIDATION_ERROR, "Usage: glob <pattern> [path]");
144
+ }
145
+ const searchPath = args[1] ?? ".";
146
+ const safePath = await validatePath(searchPath, allowedPaths);
147
+ const results = [];
148
+ const globRegex = globToRegex(pattern);
149
+ async function walk(dir) {
150
+ let entries;
151
+ try {
152
+ entries = await readdir(dir, { withFileTypes: true });
153
+ } catch {
154
+ return;
155
+ }
156
+ for (const entry of entries) {
157
+ const fullPath = join(dir, entry.name);
158
+ const relPath = relative(safePath, fullPath);
159
+ if (globRegex.test(relPath) || globRegex.test(entry.name)) {
160
+ results.push(relPath);
161
+ }
162
+ if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
163
+ await walk(fullPath);
164
+ }
165
+ if (results.length >= 1e3) return;
166
+ }
167
+ }
168
+ await walk(safePath);
169
+ return { stdout: results.join("\n"), stderr: "", exitCode: 0 };
170
+ }
171
+ async function grepBuiltin(args, allowedPaths) {
172
+ if (args.length === 0) {
173
+ throw new GigaiError(ErrorCode.VALIDATION_ERROR, "Usage: grep <pattern> [path] [--glob <filter>] [-i] [-n] [-C <num>]");
174
+ }
175
+ const positional = [];
176
+ const flags = [];
177
+ let i = 0;
178
+ while (i < args.length) {
179
+ const arg = args[i];
180
+ if (arg === "--glob" && args[i + 1]) {
181
+ flags.push("--glob", args[i + 1]);
182
+ i += 2;
183
+ } else if (arg === "--type" && args[i + 1]) {
184
+ flags.push("--type", args[i + 1]);
185
+ i += 2;
186
+ } else if (arg === "-C" && args[i + 1]) {
187
+ flags.push("-C", args[i + 1]);
188
+ i += 2;
189
+ } else if (arg === "-i" || arg === "-n" || arg === "-l") {
190
+ flags.push(arg);
191
+ i++;
192
+ } else {
193
+ positional.push(arg);
194
+ i++;
195
+ }
196
+ }
197
+ const pattern = positional[0];
198
+ if (!pattern) {
199
+ throw new GigaiError(ErrorCode.VALIDATION_ERROR, "No search pattern provided");
200
+ }
201
+ const searchPath = positional[1] ?? ".";
202
+ const safePath = await validatePath(searchPath, allowedPaths);
203
+ try {
204
+ return await spawnGrep("rg", [pattern, safePath, "-n", ...flags]);
205
+ } catch {
206
+ try {
207
+ return await spawnGrep("grep", ["-rn", ...flags, pattern, safePath]);
208
+ } catch {
209
+ return jsGrep(pattern, safePath);
210
+ }
211
+ }
212
+ }
213
+ function spawnGrep(cmd, args) {
214
+ return new Promise((resolve2, reject) => {
215
+ const child = spawn(cmd, args, { shell: false, stdio: ["ignore", "pipe", "pipe"] });
216
+ const stdoutChunks = [];
217
+ const stderrChunks = [];
218
+ let totalSize = 0;
219
+ child.stdout.on("data", (chunk) => {
220
+ totalSize += chunk.length;
221
+ if (totalSize <= MAX_OUTPUT_SIZE) stdoutChunks.push(chunk);
222
+ else child.kill("SIGTERM");
223
+ });
224
+ child.stderr.on("data", (chunk) => {
225
+ totalSize += chunk.length;
226
+ if (totalSize <= MAX_OUTPUT_SIZE) stderrChunks.push(chunk);
227
+ });
228
+ child.on("error", () => reject(new Error(`${cmd} not available`)));
229
+ child.on("close", (exitCode) => {
230
+ resolve2({
231
+ stdout: Buffer.concat(stdoutChunks).toString("utf8"),
232
+ stderr: Buffer.concat(stderrChunks).toString("utf8"),
233
+ exitCode: exitCode ?? 1
234
+ });
235
+ });
236
+ });
237
+ }
238
+ async function jsGrep(pattern, searchPath) {
239
+ let regex;
240
+ try {
241
+ regex = new RegExp(pattern);
242
+ } catch {
243
+ throw new GigaiError(ErrorCode.VALIDATION_ERROR, `Invalid pattern: ${pattern}`);
244
+ }
245
+ const results = [];
246
+ async function walk(dir) {
247
+ let entries;
248
+ try {
249
+ entries = await readdir(dir, { withFileTypes: true });
250
+ } catch {
251
+ return;
252
+ }
253
+ for (const entry of entries) {
254
+ if (results.length >= 500) return;
255
+ const fullPath = join(dir, entry.name);
256
+ if (entry.isDirectory()) {
257
+ if (!entry.name.startsWith(".") && entry.name !== "node_modules") {
258
+ await walk(fullPath);
259
+ }
260
+ } else {
261
+ try {
262
+ const content = await fsReadFile(fullPath, "utf8");
263
+ const lines = content.split("\n");
264
+ for (let i = 0; i < lines.length; i++) {
265
+ if (regex.test(lines[i])) {
266
+ results.push(`${relative(searchPath, fullPath)}:${i + 1}:${lines[i]}`);
267
+ if (results.length >= 500) return;
268
+ }
269
+ }
270
+ } catch {
271
+ }
272
+ }
273
+ }
274
+ }
275
+ await walk(searchPath);
276
+ return {
277
+ stdout: results.join("\n"),
278
+ stderr: results.length >= 500 ? "Results truncated at 500 matches" : "",
279
+ exitCode: results.length > 0 ? 0 : 1
280
+ };
281
+ }
282
+ function globToRegex(pattern) {
283
+ let regex = "";
284
+ let i = 0;
285
+ while (i < pattern.length) {
286
+ const c = pattern[i];
287
+ if (c === "*") {
288
+ if (pattern[i + 1] === "*") {
289
+ regex += ".*";
290
+ i += 2;
291
+ if (pattern[i] === "/") i++;
292
+ } else {
293
+ regex += "[^/]*";
294
+ i++;
295
+ }
296
+ } else if (c === "?") {
297
+ regex += "[^/]";
298
+ i++;
299
+ } else if (c === "{") {
300
+ const end = pattern.indexOf("}", i);
301
+ if (end !== -1) {
302
+ const options = pattern.slice(i + 1, end).split(",");
303
+ regex += `(?:${options.map(escapeRegex).join("|")})`;
304
+ i = end + 1;
305
+ } else {
306
+ regex += escapeRegex(c);
307
+ i++;
308
+ }
309
+ } else {
310
+ regex += escapeRegex(c);
311
+ i++;
312
+ }
313
+ }
314
+ return new RegExp(regex);
315
+ }
316
+ function escapeRegex(s) {
317
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
318
+ }
319
+
320
+ export {
321
+ validatePath,
322
+ readFileSafe,
323
+ listDirSafe,
324
+ searchFilesSafe,
325
+ readBuiltin,
326
+ writeBuiltin,
327
+ editBuiltin,
328
+ globBuiltin,
329
+ grepBuiltin
330
+ };
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ErrorCode,
4
+ GigaiError
5
+ } from "./chunk-P53UVHTF.js";
6
+
7
+ // ../server/dist/chunk-C43LTZCK.mjs
8
+ import { spawn } from "child_process";
9
+ var SHELL_INTERPRETERS = /* @__PURE__ */ new Set([
10
+ "sh",
11
+ "bash",
12
+ "zsh",
13
+ "fish",
14
+ "csh",
15
+ "tcsh",
16
+ "dash",
17
+ "ksh",
18
+ "env",
19
+ "xargs",
20
+ "nohup",
21
+ "strace",
22
+ "ltrace"
23
+ ]);
24
+ var MAX_OUTPUT_SIZE = 10 * 1024 * 1024;
25
+ async function execCommandSafe(command, args, config) {
26
+ if (!config.allowlist.includes(command)) {
27
+ throw new GigaiError(
28
+ ErrorCode.COMMAND_NOT_ALLOWED,
29
+ `Command not in allowlist: ${command}. Allowed: ${config.allowlist.join(", ")}`
30
+ );
31
+ }
32
+ if (command === "sudo" && !config.allowSudo) {
33
+ throw new GigaiError(ErrorCode.COMMAND_NOT_ALLOWED, "sudo is not allowed");
34
+ }
35
+ if (SHELL_INTERPRETERS.has(command)) {
36
+ throw new GigaiError(
37
+ ErrorCode.COMMAND_NOT_ALLOWED,
38
+ `Shell interpreter not allowed: ${command}`
39
+ );
40
+ }
41
+ for (const arg of args) {
42
+ if (arg.includes("\0")) {
43
+ throw new GigaiError(ErrorCode.VALIDATION_ERROR, "Null byte in argument");
44
+ }
45
+ }
46
+ return new Promise((resolve, reject) => {
47
+ const child = spawn(command, args, {
48
+ shell: false,
49
+ stdio: ["ignore", "pipe", "pipe"]
50
+ });
51
+ const stdoutChunks = [];
52
+ const stderrChunks = [];
53
+ let totalSize = 0;
54
+ child.stdout.on("data", (chunk) => {
55
+ totalSize += chunk.length;
56
+ if (totalSize <= MAX_OUTPUT_SIZE) stdoutChunks.push(chunk);
57
+ else child.kill("SIGTERM");
58
+ });
59
+ child.stderr.on("data", (chunk) => {
60
+ totalSize += chunk.length;
61
+ if (totalSize <= MAX_OUTPUT_SIZE) stderrChunks.push(chunk);
62
+ else child.kill("SIGTERM");
63
+ });
64
+ child.on("error", (err) => {
65
+ reject(new GigaiError(ErrorCode.EXEC_FAILED, `Failed to spawn ${command}: ${err.message}`));
66
+ });
67
+ child.on("close", (exitCode) => {
68
+ resolve({
69
+ stdout: Buffer.concat(stdoutChunks).toString("utf8"),
70
+ stderr: Buffer.concat(stderrChunks).toString("utf8"),
71
+ exitCode: exitCode ?? 1
72
+ });
73
+ });
74
+ });
75
+ }
76
+
77
+ export {
78
+ execCommandSafe
79
+ };
@@ -0,0 +1,269 @@
1
+ #!/usr/bin/env node
2
+
3
+ // ../shared/dist/index.mjs
4
+ import { randomBytes, createCipheriv, createDecipheriv } from "crypto";
5
+ import { z } from "zod";
6
+ var ALGORITHM = "aes-256-gcm";
7
+ var IV_LENGTH = 12;
8
+ var TAG_LENGTH = 16;
9
+ function encrypt(payload, key) {
10
+ const keyBuffer = Buffer.from(key, "hex");
11
+ if (keyBuffer.length !== 32) {
12
+ throw new Error("Encryption key must be 32 bytes (64 hex chars)");
13
+ }
14
+ const iv = randomBytes(IV_LENGTH);
15
+ const cipher = createCipheriv(ALGORITHM, keyBuffer, iv, {
16
+ authTagLength: TAG_LENGTH
17
+ });
18
+ const plaintext = JSON.stringify(payload);
19
+ const encrypted = Buffer.concat([
20
+ cipher.update(plaintext, "utf8"),
21
+ cipher.final()
22
+ ]);
23
+ const tag = cipher.getAuthTag();
24
+ return {
25
+ iv: iv.toString("base64"),
26
+ ciphertext: encrypted.toString("base64"),
27
+ tag: tag.toString("base64")
28
+ };
29
+ }
30
+ function decrypt(encrypted, key) {
31
+ const keyBuffer = Buffer.from(key, "hex");
32
+ if (keyBuffer.length !== 32) {
33
+ throw new Error("Encryption key must be 32 bytes (64 hex chars)");
34
+ }
35
+ const iv = Buffer.from(encrypted.iv, "base64");
36
+ const ciphertext = Buffer.from(encrypted.ciphertext, "base64");
37
+ const tag = Buffer.from(encrypted.tag, "base64");
38
+ const decipher = createDecipheriv(ALGORITHM, keyBuffer, iv, {
39
+ authTagLength: TAG_LENGTH
40
+ });
41
+ decipher.setAuthTag(tag);
42
+ const decrypted = Buffer.concat([
43
+ decipher.update(ciphertext),
44
+ decipher.final()
45
+ ]);
46
+ return JSON.parse(decrypted.toString("utf8"));
47
+ }
48
+ function generateEncryptionKey() {
49
+ return randomBytes(32).toString("hex");
50
+ }
51
+ var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
52
+ ErrorCode2["PAIRING_EXPIRED"] = "PAIRING_EXPIRED";
53
+ ErrorCode2["PAIRING_INVALID"] = "PAIRING_INVALID";
54
+ ErrorCode2["PAIRING_USED"] = "PAIRING_USED";
55
+ ErrorCode2["TOKEN_INVALID"] = "TOKEN_INVALID";
56
+ ErrorCode2["TOKEN_DECRYPT_FAILED"] = "TOKEN_DECRYPT_FAILED";
57
+ ErrorCode2["ORG_MISMATCH"] = "ORG_MISMATCH";
58
+ ErrorCode2["SESSION_EXPIRED"] = "SESSION_EXPIRED";
59
+ ErrorCode2["SESSION_INVALID"] = "SESSION_INVALID";
60
+ ErrorCode2["AUTH_REQUIRED"] = "AUTH_REQUIRED";
61
+ ErrorCode2["TOOL_NOT_FOUND"] = "TOOL_NOT_FOUND";
62
+ ErrorCode2["EXEC_TIMEOUT"] = "EXEC_TIMEOUT";
63
+ ErrorCode2["EXEC_FAILED"] = "EXEC_FAILED";
64
+ ErrorCode2["HTTPS_REQUIRED"] = "HTTPS_REQUIRED";
65
+ ErrorCode2["RATE_LIMITED"] = "RATE_LIMITED";
66
+ ErrorCode2["VALIDATION_ERROR"] = "VALIDATION_ERROR";
67
+ ErrorCode2["INTERNAL_ERROR"] = "INTERNAL_ERROR";
68
+ ErrorCode2["MCP_ERROR"] = "MCP_ERROR";
69
+ ErrorCode2["MCP_NOT_CONNECTED"] = "MCP_NOT_CONNECTED";
70
+ ErrorCode2["TRANSFER_NOT_FOUND"] = "TRANSFER_NOT_FOUND";
71
+ ErrorCode2["TRANSFER_EXPIRED"] = "TRANSFER_EXPIRED";
72
+ ErrorCode2["PATH_NOT_ALLOWED"] = "PATH_NOT_ALLOWED";
73
+ ErrorCode2["COMMAND_NOT_ALLOWED"] = "COMMAND_NOT_ALLOWED";
74
+ return ErrorCode2;
75
+ })(ErrorCode || {});
76
+ var STATUS_CODES = {
77
+ [
78
+ "PAIRING_EXPIRED"
79
+ /* PAIRING_EXPIRED */
80
+ ]: 410,
81
+ [
82
+ "PAIRING_INVALID"
83
+ /* PAIRING_INVALID */
84
+ ]: 400,
85
+ [
86
+ "PAIRING_USED"
87
+ /* PAIRING_USED */
88
+ ]: 409,
89
+ [
90
+ "TOKEN_INVALID"
91
+ /* TOKEN_INVALID */
92
+ ]: 401,
93
+ [
94
+ "TOKEN_DECRYPT_FAILED"
95
+ /* TOKEN_DECRYPT_FAILED */
96
+ ]: 401,
97
+ [
98
+ "ORG_MISMATCH"
99
+ /* ORG_MISMATCH */
100
+ ]: 403,
101
+ [
102
+ "SESSION_EXPIRED"
103
+ /* SESSION_EXPIRED */
104
+ ]: 401,
105
+ [
106
+ "SESSION_INVALID"
107
+ /* SESSION_INVALID */
108
+ ]: 401,
109
+ [
110
+ "AUTH_REQUIRED"
111
+ /* AUTH_REQUIRED */
112
+ ]: 401,
113
+ [
114
+ "TOOL_NOT_FOUND"
115
+ /* TOOL_NOT_FOUND */
116
+ ]: 404,
117
+ [
118
+ "EXEC_TIMEOUT"
119
+ /* EXEC_TIMEOUT */
120
+ ]: 408,
121
+ [
122
+ "EXEC_FAILED"
123
+ /* EXEC_FAILED */
124
+ ]: 500,
125
+ [
126
+ "HTTPS_REQUIRED"
127
+ /* HTTPS_REQUIRED */
128
+ ]: 403,
129
+ [
130
+ "RATE_LIMITED"
131
+ /* RATE_LIMITED */
132
+ ]: 429,
133
+ [
134
+ "VALIDATION_ERROR"
135
+ /* VALIDATION_ERROR */
136
+ ]: 400,
137
+ [
138
+ "INTERNAL_ERROR"
139
+ /* INTERNAL_ERROR */
140
+ ]: 500,
141
+ [
142
+ "MCP_ERROR"
143
+ /* MCP_ERROR */
144
+ ]: 502,
145
+ [
146
+ "MCP_NOT_CONNECTED"
147
+ /* MCP_NOT_CONNECTED */
148
+ ]: 503,
149
+ [
150
+ "TRANSFER_NOT_FOUND"
151
+ /* TRANSFER_NOT_FOUND */
152
+ ]: 404,
153
+ [
154
+ "TRANSFER_EXPIRED"
155
+ /* TRANSFER_EXPIRED */
156
+ ]: 410,
157
+ [
158
+ "PATH_NOT_ALLOWED"
159
+ /* PATH_NOT_ALLOWED */
160
+ ]: 403,
161
+ [
162
+ "COMMAND_NOT_ALLOWED"
163
+ /* COMMAND_NOT_ALLOWED */
164
+ ]: 403
165
+ };
166
+ var GigaiError = class extends Error {
167
+ code;
168
+ statusCode;
169
+ details;
170
+ constructor(code, message, details) {
171
+ super(message);
172
+ this.name = "GigaiError";
173
+ this.code = code;
174
+ this.statusCode = STATUS_CODES[code];
175
+ this.details = details;
176
+ }
177
+ toJSON() {
178
+ return {
179
+ error: {
180
+ code: this.code,
181
+ message: this.message,
182
+ ...this.details !== void 0 && { details: this.details }
183
+ }
184
+ };
185
+ }
186
+ };
187
+ var TailscaleHttpsConfigSchema = z.object({
188
+ provider: z.literal("tailscale"),
189
+ funnelPort: z.number().optional()
190
+ });
191
+ var CloudflareHttpsConfigSchema = z.object({
192
+ provider: z.literal("cloudflare"),
193
+ tunnelName: z.string(),
194
+ domain: z.string().optional()
195
+ });
196
+ var ManualHttpsConfigSchema = z.object({
197
+ provider: z.literal("manual"),
198
+ certPath: z.string(),
199
+ keyPath: z.string()
200
+ });
201
+ var HttpsConfigSchema = z.discriminatedUnion("provider", [
202
+ TailscaleHttpsConfigSchema,
203
+ CloudflareHttpsConfigSchema,
204
+ ManualHttpsConfigSchema
205
+ ]);
206
+ var CliToolConfigSchema = z.object({
207
+ type: z.literal("cli"),
208
+ name: z.string(),
209
+ command: z.string(),
210
+ args: z.array(z.string()).optional(),
211
+ description: z.string(),
212
+ timeout: z.number().optional(),
213
+ cwd: z.string().optional(),
214
+ env: z.record(z.string()).optional()
215
+ });
216
+ var McpToolConfigSchema = z.object({
217
+ type: z.literal("mcp"),
218
+ name: z.string(),
219
+ command: z.string(),
220
+ args: z.array(z.string()).optional(),
221
+ description: z.string(),
222
+ env: z.record(z.string()).optional()
223
+ });
224
+ var ScriptToolConfigSchema = z.object({
225
+ type: z.literal("script"),
226
+ name: z.string(),
227
+ path: z.string(),
228
+ description: z.string(),
229
+ timeout: z.number().optional(),
230
+ interpreter: z.string().optional()
231
+ });
232
+ var BuiltinToolConfigSchema = z.object({
233
+ type: z.literal("builtin"),
234
+ name: z.string(),
235
+ builtin: z.enum(["filesystem", "shell", "read", "write", "edit", "glob", "grep", "bash"]),
236
+ description: z.string(),
237
+ config: z.record(z.unknown()).optional()
238
+ });
239
+ var ToolConfigSchema = z.discriminatedUnion("type", [
240
+ CliToolConfigSchema,
241
+ McpToolConfigSchema,
242
+ ScriptToolConfigSchema,
243
+ BuiltinToolConfigSchema
244
+ ]);
245
+ var AuthConfigSchema = z.object({
246
+ encryptionKey: z.string().length(64),
247
+ pairingTtlSeconds: z.number().default(300),
248
+ sessionTtlSeconds: z.number().default(14400)
249
+ });
250
+ var ServerConfigSchema = z.object({
251
+ port: z.number().default(7443),
252
+ host: z.string().default("0.0.0.0"),
253
+ https: HttpsConfigSchema.optional()
254
+ });
255
+ var GigaiConfigSchema = z.object({
256
+ serverName: z.string().optional(),
257
+ server: ServerConfigSchema,
258
+ auth: AuthConfigSchema,
259
+ tools: z.array(ToolConfigSchema).default([])
260
+ });
261
+
262
+ export {
263
+ encrypt,
264
+ decrypt,
265
+ generateEncryptionKey,
266
+ ErrorCode,
267
+ GigaiError,
268
+ GigaiConfigSchema
269
+ };