@schuttdev/gigai 0.1.0-beta.11 → 0.1.0-beta.13

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.
@@ -193,13 +193,6 @@ var CloudflareHttpsConfigSchema = z.object({
193
193
  tunnelName: z.string(),
194
194
  domain: z.string().optional()
195
195
  });
196
- var LetsEncryptHttpsConfigSchema = z.object({
197
- provider: z.literal("letsencrypt"),
198
- domain: z.string(),
199
- email: z.string().email(),
200
- certPath: z.string().optional(),
201
- keyPath: z.string().optional()
202
- });
203
196
  var ManualHttpsConfigSchema = z.object({
204
197
  provider: z.literal("manual"),
205
198
  certPath: z.string(),
@@ -208,7 +201,6 @@ var ManualHttpsConfigSchema = z.object({
208
201
  var HttpsConfigSchema = z.discriminatedUnion("provider", [
209
202
  TailscaleHttpsConfigSchema,
210
203
  CloudflareHttpsConfigSchema,
211
- LetsEncryptHttpsConfigSchema,
212
204
  ManualHttpsConfigSchema
213
205
  ]);
214
206
  var CliToolConfigSchema = z.object({
@@ -3,7 +3,7 @@ import {
3
3
  ErrorCode,
4
4
  GigaiError,
5
5
  encrypt
6
- } from "./chunk-4XUWD3DZ.js";
6
+ } from "./chunk-HIKBVSBK.js";
7
7
 
8
8
  // ../server/dist/chunk-54TEF6CS.mjs
9
9
  import { nanoid } from "nanoid";
@@ -5,14 +5,14 @@ import {
5
5
  import {
6
6
  generatePairingCode,
7
7
  validateAndPair
8
- } from "./chunk-FN4LCKUA.js";
8
+ } from "./chunk-HN7WQY7K.js";
9
9
  import {
10
10
  ErrorCode,
11
11
  GigaiConfigSchema,
12
12
  GigaiError,
13
13
  decrypt,
14
14
  generateEncryptionKey
15
- } from "./chunk-4XUWD3DZ.js";
15
+ } from "./chunk-HIKBVSBK.js";
16
16
 
17
17
  // ../server/dist/index.mjs
18
18
  import { parseArgs } from "util";
@@ -40,6 +40,8 @@ import { tmpdir } from "os";
40
40
  import { nanoid } from "nanoid";
41
41
  import { readFile as readFile3 } from "fs/promises";
42
42
  import { resolve as resolve3 } from "path";
43
+ import { spawn as spawn3 } from "child_process";
44
+ import { spawn as spawn4 } from "child_process";
43
45
  import { input, select, checkbox, confirm } from "@inquirer/prompts";
44
46
  import { writeFile as writeFile2 } from "fs/promises";
45
47
  import { resolve as resolve4 } from "path";
@@ -828,6 +830,63 @@ async function loadConfig(path) {
828
830
  const json = JSON.parse(raw);
829
831
  return GigaiConfigSchema.parse(json);
830
832
  }
833
+ function runCommand(command, args) {
834
+ return new Promise((resolve6, reject) => {
835
+ const child = spawn3(command, args, { shell: false, stdio: ["ignore", "pipe", "pipe"] });
836
+ const chunks = [];
837
+ child.stdout.on("data", (chunk) => chunks.push(chunk));
838
+ child.on("error", reject);
839
+ child.on("close", (exitCode) => {
840
+ resolve6({ stdout: Buffer.concat(chunks).toString("utf8").trim(), exitCode: exitCode ?? 1 });
841
+ });
842
+ });
843
+ }
844
+ async function getTailscaleStatus() {
845
+ try {
846
+ const { stdout, exitCode } = await runCommand("tailscale", ["status", "--json"]);
847
+ if (exitCode !== 0) return { online: false };
848
+ const status = JSON.parse(stdout);
849
+ return {
850
+ online: status.BackendState === "Running",
851
+ hostname: status.Self?.DNSName?.replace(/\.$/, "")
852
+ };
853
+ } catch {
854
+ return { online: false };
855
+ }
856
+ }
857
+ async function enableFunnel(port) {
858
+ const status = await getTailscaleStatus();
859
+ if (!status.online || !status.hostname) {
860
+ throw new Error("Tailscale is not running or not connected");
861
+ }
862
+ const { exitCode, stdout } = await runCommand("tailscale", [
863
+ "funnel",
864
+ "--bg",
865
+ `${port}`
866
+ ]);
867
+ if (exitCode !== 0) {
868
+ throw new Error(`Failed to enable Tailscale Funnel: ${stdout}`);
869
+ }
870
+ return `https://${status.hostname}:${port}`;
871
+ }
872
+ async function disableFunnel(port) {
873
+ await runCommand("tailscale", ["funnel", "--bg", "off", `${port}`]);
874
+ }
875
+ function runTunnel(tunnelName, localPort) {
876
+ const child = spawn4("cloudflared", [
877
+ "tunnel",
878
+ "--url",
879
+ `http://localhost:${localPort}`,
880
+ "run",
881
+ tunnelName
882
+ ], {
883
+ shell: false,
884
+ stdio: "ignore",
885
+ detached: true
886
+ });
887
+ child.unref();
888
+ return child;
889
+ }
831
890
  var execFileAsync = promisify(execFile);
832
891
  async function getTailscaleDnsName() {
833
892
  try {
@@ -847,7 +906,6 @@ async function runInit() {
847
906
  choices: [
848
907
  { name: "Tailscale Funnel (recommended)", value: "tailscale" },
849
908
  { name: "Cloudflare Tunnel", value: "cloudflare" },
850
- { name: "Let's Encrypt", value: "letsencrypt" },
851
909
  { name: "Manual (provide certs)", value: "manual" },
852
910
  { name: "None (dev mode only)", value: "none" }
853
911
  ]
@@ -876,22 +934,6 @@ async function runInit() {
876
934
  };
877
935
  break;
878
936
  }
879
- case "letsencrypt": {
880
- const domain = await input({
881
- message: "Domain name:",
882
- required: true
883
- });
884
- const email = await input({
885
- message: "Email for Let's Encrypt:",
886
- required: true
887
- });
888
- httpsConfig = {
889
- provider: "letsencrypt",
890
- domain,
891
- email
892
- };
893
- break;
894
- }
895
937
  case "manual": {
896
938
  const certPath = await input({
897
939
  message: "Path to TLS certificate:",
@@ -977,13 +1019,22 @@ async function runInit() {
977
1019
  await writeFile2(configPath, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
978
1020
  console.log(`
979
1021
  Config written to: ${configPath}`);
980
- let serverUrl = "<YOUR_SERVER_URL>";
1022
+ let serverUrl;
981
1023
  if (httpsProvider === "tailscale") {
982
1024
  const dnsName = await getTailscaleDnsName();
983
1025
  if (dnsName) {
984
1026
  serverUrl = `https://${dnsName}:${port}`;
985
1027
  console.log(` Detected Tailscale URL: ${serverUrl}`);
986
1028
  }
1029
+ } else if (httpsProvider === "cloudflare" && httpsConfig && "domain" in httpsConfig && httpsConfig.domain) {
1030
+ serverUrl = `https://${httpsConfig.domain}`;
1031
+ console.log(` Cloudflare URL: ${serverUrl}`);
1032
+ }
1033
+ if (!serverUrl) {
1034
+ serverUrl = await input({
1035
+ message: "Server URL (how clients will reach this server):",
1036
+ required: true
1037
+ });
987
1038
  }
988
1039
  const store = new AuthStore();
989
1040
  const code = generatePairingCode(store, config.auth.pairingTtlSeconds);
@@ -1119,7 +1170,7 @@ async function unwrapTool(name) {
1119
1170
  async function generateServerPairingCode(configPath) {
1120
1171
  const { config } = await loadConfigFile(configPath);
1121
1172
  const { AuthStore: AuthStore2 } = await import("./store-Y4V3TOYJ-GKOB6ANA.js");
1122
- const { generatePairingCode: generatePairingCode2 } = await import("./pairing-IGMDVOIZ-RA7GNFU7.js");
1173
+ const { generatePairingCode: generatePairingCode2 } = await import("./pairing-IGMDVOIZ-SZYYTKV3.js");
1123
1174
  const store = new AuthStore2();
1124
1175
  const code = generatePairingCode2(store, config.auth.pairingTtlSeconds);
1125
1176
  console.log(`
@@ -1144,8 +1195,38 @@ async function startServer() {
1144
1195
  const host = config.server.host;
1145
1196
  await server.listen({ port, host });
1146
1197
  server.log.info(`gigai server listening on ${host}:${port}`);
1198
+ let cfTunnel;
1199
+ const httpsProvider = config.server.https?.provider;
1200
+ if (httpsProvider === "tailscale") {
1201
+ try {
1202
+ const funnelUrl = await enableFunnel(port);
1203
+ server.log.info(`Tailscale Funnel enabled: ${funnelUrl}`);
1204
+ } catch (e) {
1205
+ server.log.error(`Failed to enable Tailscale Funnel: ${e.message}`);
1206
+ }
1207
+ } else if (httpsProvider === "cloudflare") {
1208
+ try {
1209
+ const tunnelName = config.server.https.tunnelName;
1210
+ cfTunnel = runTunnel(tunnelName, port);
1211
+ server.log.info(`Cloudflare Tunnel started: ${tunnelName}`);
1212
+ } catch (e) {
1213
+ server.log.error(`Failed to start Cloudflare Tunnel: ${e.message}`);
1214
+ }
1215
+ }
1147
1216
  const shutdown = async () => {
1148
1217
  server.log.info("Shutting down...");
1218
+ if (httpsProvider === "tailscale") {
1219
+ try {
1220
+ await disableFunnel(port);
1221
+ } catch {
1222
+ }
1223
+ }
1224
+ if (cfTunnel) {
1225
+ try {
1226
+ cfTunnel.kill();
1227
+ } catch {
1228
+ }
1229
+ }
1149
1230
  await server.close();
1150
1231
  process.exit(0);
1151
1232
  };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  decodeJWTPayload
4
- } from "./chunk-4XUWD3DZ.js";
4
+ } from "./chunk-HIKBVSBK.js";
5
5
 
6
6
  // src/index.ts
7
7
  import { defineCommand, runMain } from "citty";
@@ -307,6 +307,25 @@ async function execTool(http, name, args, timeout) {
307
307
  if (res.stderr) process.stderr.write(res.stderr);
308
308
  process.exitCode = res.exitCode;
309
309
  }
310
+ async function execMcpTool(http, tool, mcpTool, args) {
311
+ const res = await http.post("/exec/mcp", {
312
+ tool,
313
+ mcpTool,
314
+ args
315
+ });
316
+ for (const content of res.content) {
317
+ if (content.type === "text" && content.text) {
318
+ process.stdout.write(content.text + "\n");
319
+ } else if (content.type === "image") {
320
+ console.log(`[Image: ${content.mimeType}]`);
321
+ } else if (content.type === "resource") {
322
+ console.log(`[Resource: ${content.mimeType}]`);
323
+ }
324
+ }
325
+ if (res.isError) {
326
+ process.exitCode = 1;
327
+ }
328
+ }
310
329
 
311
330
  // src/transfer.ts
312
331
  import { readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
@@ -408,7 +427,21 @@ if (mode === "client") {
408
427
  try {
409
428
  const { serverUrl, sessionToken } = await connect();
410
429
  const http = createHttpClient(serverUrl, sessionToken);
411
- await execTool(http, toolName, toolArgs);
430
+ const { tool: detail } = await fetchToolDetail(http, toolName);
431
+ if (detail.type === "mcp") {
432
+ const mcpToolName = toolArgs[0];
433
+ if (!mcpToolName) {
434
+ const toolNames = (detail.mcpTools ?? []).map((t) => ` ${t.name} \u2014 ${t.description}`);
435
+ console.log(`MCP tools for ${toolName}:
436
+ ${toolNames.join("\n")}`);
437
+ } else {
438
+ const jsonArg = toolArgs.slice(1).join(" ");
439
+ const args = jsonArg ? JSON.parse(jsonArg) : {};
440
+ await execMcpTool(http, toolName, mcpToolName, args);
441
+ }
442
+ } else {
443
+ await execTool(http, toolName, toolArgs);
444
+ }
412
445
  } catch (e) {
413
446
  console.error(`Error: ${e.message}`);
414
447
  process.exitCode = 1;
@@ -505,7 +538,7 @@ function runCitty() {
505
538
  dev: { type: "boolean", description: "Development mode (no HTTPS)" }
506
539
  },
507
540
  async run({ args }) {
508
- const { startServer } = await import("./dist-66IDK7VT.js");
541
+ const { startServer } = await import("./dist-SIS4UF2D.js");
509
542
  const extraArgs = [];
510
543
  if (args.config) extraArgs.push("--config", args.config);
511
544
  if (args.dev) extraArgs.push("--dev");
@@ -516,7 +549,7 @@ function runCitty() {
516
549
  init: defineCommand({
517
550
  meta: { name: "init", description: "Interactive setup wizard" },
518
551
  async run() {
519
- const { runInit } = await import("./dist-66IDK7VT.js");
552
+ const { runInit } = await import("./dist-SIS4UF2D.js");
520
553
  await runInit();
521
554
  }
522
555
  }),
@@ -526,7 +559,7 @@ function runCitty() {
526
559
  config: { type: "string", alias: "c", description: "Config file path" }
527
560
  },
528
561
  async run({ args }) {
529
- const { generateServerPairingCode } = await import("./dist-66IDK7VT.js");
562
+ const { generateServerPairingCode } = await import("./dist-SIS4UF2D.js");
530
563
  await generateServerPairingCode(args.config);
531
564
  }
532
565
  }),
@@ -553,21 +586,21 @@ function runCitty() {
553
586
  cli: defineCommand({
554
587
  meta: { name: "cli", description: "Wrap a CLI command" },
555
588
  async run() {
556
- const { wrapCli } = await import("./dist-66IDK7VT.js");
589
+ const { wrapCli } = await import("./dist-SIS4UF2D.js");
557
590
  await wrapCli();
558
591
  }
559
592
  }),
560
593
  mcp: defineCommand({
561
594
  meta: { name: "mcp", description: "Wrap an MCP server" },
562
595
  async run() {
563
- const { wrapMcp } = await import("./dist-66IDK7VT.js");
596
+ const { wrapMcp } = await import("./dist-SIS4UF2D.js");
564
597
  await wrapMcp();
565
598
  }
566
599
  }),
567
600
  script: defineCommand({
568
601
  meta: { name: "script", description: "Wrap a script" },
569
602
  async run() {
570
- const { wrapScript } = await import("./dist-66IDK7VT.js");
603
+ const { wrapScript } = await import("./dist-SIS4UF2D.js");
571
604
  await wrapScript();
572
605
  }
573
606
  }),
@@ -577,7 +610,7 @@ function runCitty() {
577
610
  path: { type: "positional", description: "Path to config file", required: true }
578
611
  },
579
612
  async run({ args }) {
580
- const { wrapImport } = await import("./dist-66IDK7VT.js");
613
+ const { wrapImport } = await import("./dist-SIS4UF2D.js");
581
614
  await wrapImport(args.path);
582
615
  }
583
616
  })
@@ -589,7 +622,7 @@ function runCitty() {
589
622
  name: { type: "positional", description: "Tool name", required: true }
590
623
  },
591
624
  async run({ args }) {
592
- const { unwrapTool } = await import("./dist-66IDK7VT.js");
625
+ const { unwrapTool } = await import("./dist-SIS4UF2D.js");
593
626
  await unwrapTool(args.name);
594
627
  }
595
628
  });
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  generatePairingCode,
4
4
  validateAndPair
5
- } from "./chunk-FN4LCKUA.js";
6
- import "./chunk-4XUWD3DZ.js";
5
+ } from "./chunk-HN7WQY7K.js";
6
+ import "./chunk-HIKBVSBK.js";
7
7
  export {
8
8
  generatePairingCode,
9
9
  validateAndPair
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schuttdev/gigai",
3
- "version": "0.1.0-beta.11",
3
+ "version": "0.1.0-beta.13",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "gigai": "dist/index.js"