@schuttdev/gigai 0.1.0-beta.17 → 0.1.0-beta.19

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.
@@ -1,16 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- AuthStore
4
- } from "./chunk-OWDYY3IG.js";
5
- import {
6
- generatePairingCode,
7
- validateAndPair
8
- } from "./chunk-HN7WQY7K.js";
9
2
  import {
10
3
  ErrorCode,
11
4
  GigaiConfigSchema,
12
5
  GigaiError,
13
6
  decrypt,
7
+ encrypt,
14
8
  generateEncryptionKey
15
9
  } from "./chunk-HIKBVSBK.js";
16
10
 
@@ -21,7 +15,9 @@ import cors from "@fastify/cors";
21
15
  import rateLimit from "@fastify/rate-limit";
22
16
  import multipart from "@fastify/multipart";
23
17
  import fp from "fastify-plugin";
18
+ import { nanoid } from "nanoid";
24
19
  import { randomBytes } from "crypto";
20
+ import { nanoid as nanoid2 } from "nanoid";
25
21
  import fp2 from "fastify-plugin";
26
22
  import fp3 from "fastify-plugin";
27
23
  import { spawn } from "child_process";
@@ -37,7 +33,7 @@ import { spawn as spawn2 } from "child_process";
37
33
  import { writeFile, readFile as readFile2, unlink, mkdir } from "fs/promises";
38
34
  import { join as join2 } from "path";
39
35
  import { tmpdir } from "os";
40
- import { nanoid } from "nanoid";
36
+ import { nanoid as nanoid3 } from "nanoid";
41
37
  import { readFile as readFile3 } from "fs/promises";
42
38
  import { resolve as resolve3 } from "path";
43
39
  import { spawn as spawn3 } from "child_process";
@@ -55,6 +51,71 @@ import { resolve as resolve6, join as join3 } from "path";
55
51
  import { homedir, platform } from "os";
56
52
  import { execFile as execFile2 } from "child_process";
57
53
  import { promisify as promisify2 } from "util";
54
+ var AuthStore = class {
55
+ pairingCodes = /* @__PURE__ */ new Map();
56
+ sessions = /* @__PURE__ */ new Map();
57
+ cleanupInterval;
58
+ constructor() {
59
+ this.cleanupInterval = setInterval(() => this.cleanup(), 6e4);
60
+ }
61
+ // Pairing codes
62
+ addPairingCode(code, ttlSeconds) {
63
+ const entry = {
64
+ code,
65
+ expiresAt: Date.now() + ttlSeconds * 1e3,
66
+ used: false
67
+ };
68
+ this.pairingCodes.set(code, entry);
69
+ return entry;
70
+ }
71
+ getPairingCode(code) {
72
+ return this.pairingCodes.get(code);
73
+ }
74
+ markPairingCodeUsed(code) {
75
+ const entry = this.pairingCodes.get(code);
76
+ if (entry) {
77
+ entry.used = true;
78
+ }
79
+ }
80
+ // Sessions
81
+ createSession(orgUuid, ttlSeconds) {
82
+ const session = {
83
+ id: nanoid(32),
84
+ orgUuid,
85
+ token: nanoid(48),
86
+ expiresAt: Date.now() + ttlSeconds * 1e3,
87
+ lastActivity: Date.now()
88
+ };
89
+ this.sessions.set(session.token, session);
90
+ return session;
91
+ }
92
+ getSession(token) {
93
+ const session = this.sessions.get(token);
94
+ if (session) {
95
+ session.lastActivity = Date.now();
96
+ }
97
+ return session;
98
+ }
99
+ // Cleanup
100
+ cleanup() {
101
+ const now = Date.now();
102
+ for (const [key, code] of this.pairingCodes) {
103
+ if (code.expiresAt < now) {
104
+ this.pairingCodes.delete(key);
105
+ }
106
+ }
107
+ for (const [key, session] of this.sessions) {
108
+ if (session.expiresAt < now) {
109
+ this.sessions.delete(key);
110
+ }
111
+ }
112
+ }
113
+ destroy() {
114
+ clearInterval(this.cleanupInterval);
115
+ this.pairingCodes.clear();
116
+ this.sessions.clear();
117
+ }
118
+ };
58
119
  function connectWithToken(store, encryptedToken, orgUuid, encryptionKey, sessionTtlSeconds) {
59
120
  let payload;
60
121
  try {
@@ -94,6 +155,34 @@ function createAuthMiddleware(store) {
94
155
  request.session = session;
95
156
  };
96
157
  }
158
+ var PAIRING_CODE_LENGTH = 8;
159
+ var PAIRING_CODE_CHARS = "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ";
160
+ function generatePairingCode(store, ttlSeconds) {
161
+ let code = "";
162
+ const bytes = nanoid2(PAIRING_CODE_LENGTH);
163
+ for (let i = 0; i < PAIRING_CODE_LENGTH; i++) {
164
+ code += PAIRING_CODE_CHARS[bytes.charCodeAt(i) % PAIRING_CODE_CHARS.length];
165
+ }
166
+ store.addPairingCode(code, ttlSeconds);
167
+ return code;
168
+ }
169
+ function validateAndPair(store, code, orgUuid, encryptionKey, serverFingerprint) {
170
+ const entry = store.getPairingCode(code.toUpperCase());
171
+ if (!entry) {
172
+ throw new GigaiError(ErrorCode.PAIRING_INVALID, "Invalid pairing code");
173
+ }
174
+ if (entry.used) {
175
+ throw new GigaiError(ErrorCode.PAIRING_USED, "Pairing code already used");
176
+ }
177
+ if (entry.expiresAt < Date.now()) {
178
+ throw new GigaiError(ErrorCode.PAIRING_EXPIRED, "Pairing code expired");
179
+ }
180
+ store.markPairingCodeUsed(code.toUpperCase());
181
+ return encrypt(
182
+ { orgUuid, serverFingerprint, createdAt: Date.now() },
183
+ encryptionKey
184
+ );
185
+ }
97
186
  function registerAuthRoutes(server, store, config) {
98
187
  const serverFingerprint = randomBytes(16).toString("hex");
99
188
  server.post("/auth/pair", {
@@ -752,7 +841,7 @@ async function transferRoutes(server) {
752
841
  if (!data) {
753
842
  throw new GigaiError(ErrorCode.VALIDATION_ERROR, "No file uploaded");
754
843
  }
755
- const id = nanoid(16);
844
+ const id = nanoid3(16);
756
845
  const buffer = await data.toBuffer();
757
846
  const filePath = join2(TRANSFER_DIR, id);
758
847
  await writeFile(filePath, buffer);
@@ -1096,9 +1185,25 @@ async function runInit() {
1096
1185
  } catch {
1097
1186
  console.log(` Server starting in background (PID ${child.pid})`);
1098
1187
  }
1099
- const store = new AuthStore();
1100
- const code = generatePairingCode(store, config.auth.pairingTtlSeconds);
1101
- store.destroy();
1188
+ let code;
1189
+ const maxRetries = 5;
1190
+ for (let i = 0; i < maxRetries; i++) {
1191
+ try {
1192
+ const res = await fetch(`http://localhost:${port}/auth/pair/generate`);
1193
+ if (res.ok) {
1194
+ const data = await res.json();
1195
+ code = data.code;
1196
+ break;
1197
+ }
1198
+ } catch {
1199
+ await new Promise((r) => setTimeout(r, 1e3));
1200
+ }
1201
+ }
1202
+ if (!code) {
1203
+ console.log("\n Server is starting but not ready yet.");
1204
+ console.log(" Run 'gigai server pair' once it's up to get a pairing code.\n");
1205
+ return;
1206
+ }
1102
1207
  console.log(`
1103
1208
  Paste this into Claude to pair:
1104
1209
  `);
@@ -1228,17 +1333,25 @@ async function unwrapTool(name) {
1228
1333
  }
1229
1334
  async function generateServerPairingCode(configPath) {
1230
1335
  const { config } = await loadConfigFile(configPath);
1231
- const { AuthStore: AuthStore2 } = await import("./store-Y4V3TOYJ-GKOB6ANA.js");
1232
- const { generatePairingCode: generatePairingCode2 } = await import("./pairing-IGMDVOIZ-SZYYTKV3.js");
1233
- const store = new AuthStore2();
1234
- const code = generatePairingCode2(store, config.auth.pairingTtlSeconds);
1235
- console.log(`
1236
- Pairing code: ${code}`);
1237
- console.log(`Expires in ${config.auth.pairingTtlSeconds / 60} minutes.`);
1238
- console.log(`
1239
- Note: The server must be running for the client to use this code.`);
1240
- console.log(`For a live pairing code, use the server's /auth/pair/generate endpoint.`);
1241
- store.destroy();
1336
+ const port = config.server.port;
1337
+ try {
1338
+ const res = await fetch(`http://localhost:${port}/auth/pair/generate`);
1339
+ if (!res.ok) {
1340
+ const body = await res.text();
1341
+ throw new Error(`Server returned ${res.status}: ${body}`);
1342
+ }
1343
+ const data = await res.json();
1344
+ console.log(`
1345
+ Pairing code: ${data.code}`);
1346
+ console.log(`Expires in ${data.expiresIn / 60} minutes.`);
1347
+ } catch (e) {
1348
+ if (e.message.includes("fetch failed") || e.message.includes("ECONNREFUSED")) {
1349
+ console.error("Server is not running. Start it with: gigai server start");
1350
+ } else {
1351
+ console.error(`Error: ${e.message}`);
1352
+ }
1353
+ process.exitCode = 1;
1354
+ }
1242
1355
  }
1243
1356
  var execFileAsync2 = promisify2(execFile2);
1244
1357
  function getGigaiBin() {
@@ -1359,6 +1472,27 @@ async function uninstallDaemon() {
1359
1472
  }
1360
1473
  }
1361
1474
  }
1475
+ async function stopServer() {
1476
+ const { execFileSync } = await import("child_process");
1477
+ let pids = [];
1478
+ try {
1479
+ const out = execFileSync("pgrep", ["-f", "gigai server start"], { encoding: "utf8" });
1480
+ pids = out.trim().split("\n").map(Number).filter((pid) => pid && pid !== process.pid);
1481
+ } catch {
1482
+ }
1483
+ if (pids.length === 0) {
1484
+ console.log("No running gigai server found.");
1485
+ return;
1486
+ }
1487
+ for (const pid of pids) {
1488
+ try {
1489
+ process.kill(pid, "SIGTERM");
1490
+ console.log(`Stopped gigai server (PID ${pid})`);
1491
+ } catch (e) {
1492
+ console.error(`Failed to stop PID ${pid}: ${e.message}`);
1493
+ }
1494
+ }
1495
+ }
1362
1496
  async function startServer() {
1363
1497
  const { values } = parseArgs({
1364
1498
  options: {
@@ -1418,6 +1552,7 @@ export {
1418
1552
  loadConfig,
1419
1553
  runInit,
1420
1554
  startServer,
1555
+ stopServer,
1421
1556
  uninstallDaemon,
1422
1557
  unwrapTool,
1423
1558
  wrapCli,
package/dist/index.js CHANGED
@@ -577,7 +577,7 @@ function runCitty() {
577
577
  dev: { type: "boolean", description: "Development mode (no HTTPS)" }
578
578
  },
579
579
  async run({ args }) {
580
- const { startServer } = await import("./dist-GANOIL6Z.js");
580
+ const { startServer } = await import("./dist-IQVGU6KW.js");
581
581
  const extraArgs = [];
582
582
  if (args.config) extraArgs.push("--config", args.config);
583
583
  if (args.dev) extraArgs.push("--dev");
@@ -588,7 +588,7 @@ function runCitty() {
588
588
  init: defineCommand({
589
589
  meta: { name: "init", description: "Interactive setup wizard" },
590
590
  async run() {
591
- const { runInit } = await import("./dist-GANOIL6Z.js");
591
+ const { runInit } = await import("./dist-IQVGU6KW.js");
592
592
  await runInit();
593
593
  }
594
594
  }),
@@ -598,7 +598,7 @@ function runCitty() {
598
598
  config: { type: "string", alias: "c", description: "Config file path" }
599
599
  },
600
600
  async run({ args }) {
601
- const { generateServerPairingCode } = await import("./dist-GANOIL6Z.js");
601
+ const { generateServerPairingCode } = await import("./dist-IQVGU6KW.js");
602
602
  await generateServerPairingCode(args.config);
603
603
  }
604
604
  }),
@@ -608,17 +608,24 @@ function runCitty() {
608
608
  config: { type: "string", alias: "c", description: "Config file path" }
609
609
  },
610
610
  async run({ args }) {
611
- const { installDaemon } = await import("./dist-GANOIL6Z.js");
611
+ const { installDaemon } = await import("./dist-IQVGU6KW.js");
612
612
  await installDaemon(args.config);
613
613
  }
614
614
  }),
615
615
  uninstall: defineCommand({
616
616
  meta: { name: "uninstall", description: "Remove background service" },
617
617
  async run() {
618
- const { uninstallDaemon } = await import("./dist-GANOIL6Z.js");
618
+ const { uninstallDaemon } = await import("./dist-IQVGU6KW.js");
619
619
  await uninstallDaemon();
620
620
  }
621
621
  }),
622
+ stop: defineCommand({
623
+ meta: { name: "stop", description: "Stop the running gigai server" },
624
+ async run() {
625
+ const { stopServer } = await import("./dist-IQVGU6KW.js");
626
+ await stopServer();
627
+ }
628
+ }),
622
629
  status: defineCommand({
623
630
  meta: { name: "status", description: "Show server status" },
624
631
  async run() {
@@ -642,21 +649,21 @@ function runCitty() {
642
649
  cli: defineCommand({
643
650
  meta: { name: "cli", description: "Wrap a CLI command" },
644
651
  async run() {
645
- const { wrapCli } = await import("./dist-GANOIL6Z.js");
652
+ const { wrapCli } = await import("./dist-IQVGU6KW.js");
646
653
  await wrapCli();
647
654
  }
648
655
  }),
649
656
  mcp: defineCommand({
650
657
  meta: { name: "mcp", description: "Wrap an MCP server" },
651
658
  async run() {
652
- const { wrapMcp } = await import("./dist-GANOIL6Z.js");
659
+ const { wrapMcp } = await import("./dist-IQVGU6KW.js");
653
660
  await wrapMcp();
654
661
  }
655
662
  }),
656
663
  script: defineCommand({
657
664
  meta: { name: "script", description: "Wrap a script" },
658
665
  async run() {
659
- const { wrapScript } = await import("./dist-GANOIL6Z.js");
666
+ const { wrapScript } = await import("./dist-IQVGU6KW.js");
660
667
  await wrapScript();
661
668
  }
662
669
  }),
@@ -666,7 +673,7 @@ function runCitty() {
666
673
  path: { type: "positional", description: "Path to config file", required: true }
667
674
  },
668
675
  async run({ args }) {
669
- const { wrapImport } = await import("./dist-GANOIL6Z.js");
676
+ const { wrapImport } = await import("./dist-IQVGU6KW.js");
670
677
  await wrapImport(args.path);
671
678
  }
672
679
  })
@@ -678,7 +685,7 @@ function runCitty() {
678
685
  name: { type: "positional", description: "Tool name", required: true }
679
686
  },
680
687
  async run({ args }) {
681
- const { unwrapTool } = await import("./dist-GANOIL6Z.js");
688
+ const { unwrapTool } = await import("./dist-IQVGU6KW.js");
682
689
  await unwrapTool(args.name);
683
690
  }
684
691
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schuttdev/gigai",
3
- "version": "0.1.0-beta.17",
3
+ "version": "0.1.0-beta.19",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "gigai": "dist/index.js"
@@ -1,42 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- ErrorCode,
4
- GigaiError,
5
- encrypt
6
- } from "./chunk-HIKBVSBK.js";
7
-
8
- // ../server/dist/chunk-54TEF6CS.mjs
9
- import { nanoid } from "nanoid";
10
- var PAIRING_CODE_LENGTH = 8;
11
- var PAIRING_CODE_CHARS = "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ";
12
- function generatePairingCode(store, ttlSeconds) {
13
- let code = "";
14
- const bytes = nanoid(PAIRING_CODE_LENGTH);
15
- for (let i = 0; i < PAIRING_CODE_LENGTH; i++) {
16
- code += PAIRING_CODE_CHARS[bytes.charCodeAt(i) % PAIRING_CODE_CHARS.length];
17
- }
18
- store.addPairingCode(code, ttlSeconds);
19
- return code;
20
- }
21
- function validateAndPair(store, code, orgUuid, encryptionKey, serverFingerprint) {
22
- const entry = store.getPairingCode(code.toUpperCase());
23
- if (!entry) {
24
- throw new GigaiError(ErrorCode.PAIRING_INVALID, "Invalid pairing code");
25
- }
26
- if (entry.used) {
27
- throw new GigaiError(ErrorCode.PAIRING_USED, "Pairing code already used");
28
- }
29
- if (entry.expiresAt < Date.now()) {
30
- throw new GigaiError(ErrorCode.PAIRING_EXPIRED, "Pairing code expired");
31
- }
32
- store.markPairingCodeUsed(code.toUpperCase());
33
- return encrypt(
34
- { orgUuid, serverFingerprint, createdAt: Date.now() },
35
- encryptionKey
36
- );
37
- }
38
-
39
- export {
40
- generatePairingCode,
41
- validateAndPair
42
- };
@@ -1,73 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // ../server/dist/chunk-RZTCSUFS.mjs
4
- import { nanoid } from "nanoid";
5
- var AuthStore = class {
6
- pairingCodes = /* @__PURE__ */ new Map();
7
- sessions = /* @__PURE__ */ new Map();
8
- cleanupInterval;
9
- constructor() {
10
- this.cleanupInterval = setInterval(() => this.cleanup(), 6e4);
11
- }
12
- // Pairing codes
13
- addPairingCode(code, ttlSeconds) {
14
- const entry = {
15
- code,
16
- expiresAt: Date.now() + ttlSeconds * 1e3,
17
- used: false
18
- };
19
- this.pairingCodes.set(code, entry);
20
- return entry;
21
- }
22
- getPairingCode(code) {
23
- return this.pairingCodes.get(code);
24
- }
25
- markPairingCodeUsed(code) {
26
- const entry = this.pairingCodes.get(code);
27
- if (entry) {
28
- entry.used = true;
29
- }
30
- }
31
- // Sessions
32
- createSession(orgUuid, ttlSeconds) {
33
- const session = {
34
- id: nanoid(32),
35
- orgUuid,
36
- token: nanoid(48),
37
- expiresAt: Date.now() + ttlSeconds * 1e3,
38
- lastActivity: Date.now()
39
- };
40
- this.sessions.set(session.token, session);
41
- return session;
42
- }
43
- getSession(token) {
44
- const session = this.sessions.get(token);
45
- if (session) {
46
- session.lastActivity = Date.now();
47
- }
48
- return session;
49
- }
50
- // Cleanup
51
- cleanup() {
52
- const now = Date.now();
53
- for (const [key, code] of this.pairingCodes) {
54
- if (code.expiresAt < now) {
55
- this.pairingCodes.delete(key);
56
- }
57
- }
58
- for (const [key, session] of this.sessions) {
59
- if (session.expiresAt < now) {
60
- this.sessions.delete(key);
61
- }
62
- }
63
- }
64
- destroy() {
65
- clearInterval(this.cleanupInterval);
66
- this.pairingCodes.clear();
67
- this.sessions.clear();
68
- }
69
- };
70
-
71
- export {
72
- AuthStore
73
- };
@@ -1,10 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- generatePairingCode,
4
- validateAndPair
5
- } from "./chunk-HN7WQY7K.js";
6
- import "./chunk-HIKBVSBK.js";
7
- export {
8
- generatePairingCode,
9
- validateAndPair
10
- };
@@ -1,7 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- AuthStore
4
- } from "./chunk-OWDYY3IG.js";
5
- export {
6
- AuthStore
7
- };