@schuttdev/gigai 0.1.0-beta.16 → 0.1.0-beta.18
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 =
|
|
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
|
-
|
|
1100
|
-
const
|
|
1101
|
-
|
|
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
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
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() {
|
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-
|
|
580
|
+
const { startServer } = await import("./dist-4DHEQIOT.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-
|
|
591
|
+
const { runInit } = await import("./dist-4DHEQIOT.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-
|
|
601
|
+
const { generateServerPairingCode } = await import("./dist-4DHEQIOT.js");
|
|
602
602
|
await generateServerPairingCode(args.config);
|
|
603
603
|
}
|
|
604
604
|
}),
|
|
@@ -608,14 +608,14 @@ 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-
|
|
611
|
+
const { installDaemon } = await import("./dist-4DHEQIOT.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-
|
|
618
|
+
const { uninstallDaemon } = await import("./dist-4DHEQIOT.js");
|
|
619
619
|
await uninstallDaemon();
|
|
620
620
|
}
|
|
621
621
|
}),
|
|
@@ -642,21 +642,21 @@ function runCitty() {
|
|
|
642
642
|
cli: defineCommand({
|
|
643
643
|
meta: { name: "cli", description: "Wrap a CLI command" },
|
|
644
644
|
async run() {
|
|
645
|
-
const { wrapCli } = await import("./dist-
|
|
645
|
+
const { wrapCli } = await import("./dist-4DHEQIOT.js");
|
|
646
646
|
await wrapCli();
|
|
647
647
|
}
|
|
648
648
|
}),
|
|
649
649
|
mcp: defineCommand({
|
|
650
650
|
meta: { name: "mcp", description: "Wrap an MCP server" },
|
|
651
651
|
async run() {
|
|
652
|
-
const { wrapMcp } = await import("./dist-
|
|
652
|
+
const { wrapMcp } = await import("./dist-4DHEQIOT.js");
|
|
653
653
|
await wrapMcp();
|
|
654
654
|
}
|
|
655
655
|
}),
|
|
656
656
|
script: defineCommand({
|
|
657
657
|
meta: { name: "script", description: "Wrap a script" },
|
|
658
658
|
async run() {
|
|
659
|
-
const { wrapScript } = await import("./dist-
|
|
659
|
+
const { wrapScript } = await import("./dist-4DHEQIOT.js");
|
|
660
660
|
await wrapScript();
|
|
661
661
|
}
|
|
662
662
|
}),
|
|
@@ -666,7 +666,7 @@ function runCitty() {
|
|
|
666
666
|
path: { type: "positional", description: "Path to config file", required: true }
|
|
667
667
|
},
|
|
668
668
|
async run({ args }) {
|
|
669
|
-
const { wrapImport } = await import("./dist-
|
|
669
|
+
const { wrapImport } = await import("./dist-4DHEQIOT.js");
|
|
670
670
|
await wrapImport(args.path);
|
|
671
671
|
}
|
|
672
672
|
})
|
|
@@ -678,7 +678,7 @@ function runCitty() {
|
|
|
678
678
|
name: { type: "positional", description: "Tool name", required: true }
|
|
679
679
|
},
|
|
680
680
|
async run({ args }) {
|
|
681
|
-
const { unwrapTool } = await import("./dist-
|
|
681
|
+
const { unwrapTool } = await import("./dist-4DHEQIOT.js");
|
|
682
682
|
await unwrapTool(args.name);
|
|
683
683
|
}
|
|
684
684
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@schuttdev/gigai",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.18",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"gigai": "dist/index.js"
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
31
31
|
"@inquirer/prompts": "^7.0.0",
|
|
32
32
|
"nanoid": "^5.0.0",
|
|
33
|
-
"zod": "^3.22.0"
|
|
33
|
+
"zod": "^3.22.0",
|
|
34
|
+
"undici": "^6.0.0"
|
|
34
35
|
},
|
|
35
36
|
"devDependencies": {
|
|
36
37
|
"@gigai/shared": "*",
|
package/dist/chunk-HN7WQY7K.js
DELETED
|
@@ -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
|
-
};
|
package/dist/chunk-OWDYY3IG.js
DELETED
|
@@ -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
|
-
};
|