@schuttdev/gigai 0.2.4 → 0.2.6

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/index.js CHANGED
@@ -1,7 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- decodeJWTPayload
4
- } from "./chunk-7C3UYEKE.js";
5
2
 
6
3
  // src/index.ts
7
4
  import { defineCommand, runMain } from "citty";
@@ -99,6 +96,94 @@ function normalizeUrl(url) {
99
96
  }
100
97
  }
101
98
 
99
+ // ../shared/dist/index.mjs
100
+ import { z } from "zod";
101
+ var TailscaleHttpsConfigSchema = z.object({
102
+ provider: z.literal("tailscale"),
103
+ funnelPort: z.number().optional()
104
+ });
105
+ var CloudflareHttpsConfigSchema = z.object({
106
+ provider: z.literal("cloudflare"),
107
+ tunnelName: z.string(),
108
+ domain: z.string().optional()
109
+ });
110
+ var ManualHttpsConfigSchema = z.object({
111
+ provider: z.literal("manual"),
112
+ certPath: z.string(),
113
+ keyPath: z.string()
114
+ });
115
+ var HttpsConfigSchema = z.discriminatedUnion("provider", [
116
+ TailscaleHttpsConfigSchema,
117
+ CloudflareHttpsConfigSchema,
118
+ ManualHttpsConfigSchema
119
+ ]);
120
+ var CliToolConfigSchema = z.object({
121
+ type: z.literal("cli"),
122
+ name: z.string(),
123
+ command: z.string(),
124
+ args: z.array(z.string()).optional(),
125
+ description: z.string(),
126
+ timeout: z.number().optional(),
127
+ cwd: z.string().optional(),
128
+ env: z.record(z.string()).optional()
129
+ });
130
+ var McpToolConfigSchema = z.object({
131
+ type: z.literal("mcp"),
132
+ name: z.string(),
133
+ command: z.string(),
134
+ args: z.array(z.string()).optional(),
135
+ description: z.string(),
136
+ env: z.record(z.string()).optional()
137
+ });
138
+ var ScriptToolConfigSchema = z.object({
139
+ type: z.literal("script"),
140
+ name: z.string(),
141
+ path: z.string(),
142
+ description: z.string(),
143
+ timeout: z.number().optional(),
144
+ interpreter: z.string().optional()
145
+ });
146
+ var BuiltinToolConfigSchema = z.object({
147
+ type: z.literal("builtin"),
148
+ name: z.string(),
149
+ builtin: z.enum(["filesystem", "shell"]),
150
+ description: z.string(),
151
+ config: z.record(z.unknown()).optional()
152
+ });
153
+ var ToolConfigSchema = z.discriminatedUnion("type", [
154
+ CliToolConfigSchema,
155
+ McpToolConfigSchema,
156
+ ScriptToolConfigSchema,
157
+ BuiltinToolConfigSchema
158
+ ]);
159
+ var AuthConfigSchema = z.object({
160
+ encryptionKey: z.string().length(64),
161
+ pairingTtlSeconds: z.number().default(300),
162
+ sessionTtlSeconds: z.number().default(14400)
163
+ });
164
+ var ServerConfigSchema = z.object({
165
+ port: z.number().default(7443),
166
+ host: z.string().default("0.0.0.0"),
167
+ https: HttpsConfigSchema.optional()
168
+ });
169
+ var GigaiConfigSchema = z.object({
170
+ serverName: z.string().optional(),
171
+ server: ServerConfigSchema,
172
+ auth: AuthConfigSchema,
173
+ tools: z.array(ToolConfigSchema).default([])
174
+ });
175
+ function decodeJWTPayload(token) {
176
+ const parts = token.split(".");
177
+ if (parts.length !== 3) {
178
+ throw new Error("Invalid JWT format: expected 3 segments");
179
+ }
180
+ const payload = parts[1];
181
+ const base64 = payload.replace(/-/g, "+").replace(/_/g, "/");
182
+ const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
183
+ const decoded = Buffer.from(padded, "base64").toString("utf8");
184
+ return JSON.parse(decoded);
185
+ }
186
+
102
187
  // src/identity.ts
103
188
  function getOrgUUID() {
104
189
  if (process.env.GIGAI_ORG_UUID) {
@@ -246,7 +331,7 @@ function createHttpClient(serverUrl, sessionToken) {
246
331
  }
247
332
 
248
333
  // src/version.ts
249
- var VERSION = "0.2.4";
334
+ var VERSION = "0.2.6";
250
335
 
251
336
  // src/connect.ts
252
337
  async function connect(serverName) {
@@ -347,7 +432,7 @@ You have access to tools running on the user's local machine through the gigai C
347
432
  ## Setup (run once per conversation)
348
433
 
349
434
  \`\`\`bash
350
- npm install -g @schuttdev/gigai 2>/dev/null
435
+ npm install -g @schuttdev/gigai --omit=optional 2>/dev/null
351
436
  mkdir -p ~/.gigai
352
437
  cp /mnt/skills/user/gigai/config.json ~/.gigai/config.json
353
438
  gigai connect
@@ -397,6 +482,14 @@ gigai download <id> <dest>
397
482
  - If you get auth errors, run \`gigai connect\` to refresh the session
398
483
  - Tools are scoped to what the user has configured \u2014 if a tool is missing, tell the user
399
484
  `;
485
+ async function hasExistingSkill() {
486
+ try {
487
+ await readFile2("/mnt/skills/user/gigai/config.json", "utf8");
488
+ return true;
489
+ } catch {
490
+ return false;
491
+ }
492
+ }
400
493
  async function generateSkillZip(serverName, serverUrl, token) {
401
494
  let skillConfig = { servers: {} };
402
495
  try {
@@ -524,12 +617,17 @@ async function pair(code, serverUrl) {
524
617
  orgUuid
525
618
  });
526
619
  await addServer(res.serverName, serverUrl, res.encryptedToken);
527
- console.log(`Paired with "${res.serverName}" successfully!
528
- `);
620
+ console.log(`Paired with "${res.serverName}" successfully!`);
621
+ const existing = await hasExistingSkill();
529
622
  const zip = await generateSkillZip(res.serverName, serverUrl, res.encryptedToken);
530
623
  const outPath = await writeSkillZip(zip);
531
- console.log(`Skill zip written to: ${outPath}`);
532
- console.log("Upload this file as a skill in Claude Desktop (Settings \u2192 Customize \u2192 Upload Skill).");
624
+ console.log(`
625
+ Skill zip written to: ${outPath}`);
626
+ if (existing) {
627
+ console.log("Skill file updated. Download and re-upload to Claude.");
628
+ } else {
629
+ console.log("Upload this file as a skill in Claude (Settings \u2192 Customize \u2192 Upload Skill).");
630
+ }
533
631
  }
534
632
 
535
633
  // src/discover.ts
@@ -725,6 +823,15 @@ ${toolNames.join("\n")}`);
725
823
  } else {
726
824
  runCitty();
727
825
  }
826
+ async function requireServer() {
827
+ try {
828
+ return await requireServer();
829
+ } catch {
830
+ console.error("Server dependencies not installed.");
831
+ console.error("Run: npm install -g @schuttdev/gigai");
832
+ process.exit(1);
833
+ }
834
+ }
728
835
  function runCitty() {
729
836
  const pairCommand = defineCommand({
730
837
  meta: { name: "pair", description: "Pair with a gigai server" },
@@ -813,7 +920,7 @@ function runCitty() {
813
920
  dev: { type: "boolean", description: "Development mode (no HTTPS)" }
814
921
  },
815
922
  async run({ args }) {
816
- const { startServer } = await import("./dist-G2KJBUZX.js");
923
+ const { startServer } = await requireServer();
817
924
  const extraArgs = [];
818
925
  if (args.config) extraArgs.push("--config", args.config);
819
926
  if (args.dev) extraArgs.push("--dev");
@@ -824,7 +931,7 @@ function runCitty() {
824
931
  init: defineCommand({
825
932
  meta: { name: "init", description: "Interactive setup wizard" },
826
933
  async run() {
827
- const { runInit } = await import("./dist-G2KJBUZX.js");
934
+ const { runInit } = await requireServer();
828
935
  await runInit();
829
936
  }
830
937
  }),
@@ -834,7 +941,7 @@ function runCitty() {
834
941
  config: { type: "string", alias: "c", description: "Config file path" }
835
942
  },
836
943
  async run({ args }) {
837
- const { generateServerPairingCode } = await import("./dist-G2KJBUZX.js");
944
+ const { generateServerPairingCode } = await requireServer();
838
945
  await generateServerPairingCode(args.config);
839
946
  }
840
947
  }),
@@ -844,14 +951,14 @@ function runCitty() {
844
951
  config: { type: "string", alias: "c", description: "Config file path" }
845
952
  },
846
953
  async run({ args }) {
847
- const { installDaemon } = await import("./dist-G2KJBUZX.js");
954
+ const { installDaemon } = await requireServer();
848
955
  await installDaemon(args.config);
849
956
  }
850
957
  }),
851
958
  uninstall: defineCommand({
852
959
  meta: { name: "uninstall", description: "Remove background service" },
853
960
  async run() {
854
- const { uninstallDaemon } = await import("./dist-G2KJBUZX.js");
961
+ const { uninstallDaemon } = await requireServer();
855
962
  await uninstallDaemon();
856
963
  }
857
964
  }),
@@ -902,21 +1009,21 @@ function runCitty() {
902
1009
  cli: defineCommand({
903
1010
  meta: { name: "cli", description: "Wrap a CLI command" },
904
1011
  async run() {
905
- const { wrapCli } = await import("./dist-G2KJBUZX.js");
1012
+ const { wrapCli } = await requireServer();
906
1013
  await wrapCli();
907
1014
  }
908
1015
  }),
909
1016
  mcp: defineCommand({
910
1017
  meta: { name: "mcp", description: "Wrap an MCP server" },
911
1018
  async run() {
912
- const { wrapMcp } = await import("./dist-G2KJBUZX.js");
1019
+ const { wrapMcp } = await requireServer();
913
1020
  await wrapMcp();
914
1021
  }
915
1022
  }),
916
1023
  script: defineCommand({
917
1024
  meta: { name: "script", description: "Wrap a script" },
918
1025
  async run() {
919
- const { wrapScript } = await import("./dist-G2KJBUZX.js");
1026
+ const { wrapScript } = await requireServer();
920
1027
  await wrapScript();
921
1028
  }
922
1029
  }),
@@ -926,7 +1033,7 @@ function runCitty() {
926
1033
  path: { type: "positional", description: "Path to config file", required: true }
927
1034
  },
928
1035
  async run({ args }) {
929
- const { wrapImport } = await import("./dist-G2KJBUZX.js");
1036
+ const { wrapImport } = await requireServer();
930
1037
  await wrapImport(args.path);
931
1038
  }
932
1039
  })
@@ -938,7 +1045,7 @@ function runCitty() {
938
1045
  name: { type: "positional", description: "Tool name", required: true }
939
1046
  },
940
1047
  async run({ args }) {
941
- const { unwrapTool } = await import("./dist-G2KJBUZX.js");
1048
+ const { unwrapTool } = await requireServer();
942
1049
  await unwrapTool(args.name);
943
1050
  }
944
1051
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schuttdev/gigai",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "gigai": "dist/index.js"
@@ -22,6 +22,10 @@
22
22
  },
23
23
  "dependencies": {
24
24
  "citty": "^0.1.6",
25
+ "zod": "^3.22.0",
26
+ "undici": "^6.0.0"
27
+ },
28
+ "optionalDependencies": {
25
29
  "fastify": "^4.25.0",
26
30
  "@fastify/cors": "^9.0.0",
27
31
  "@fastify/rate-limit": "^9.0.0",
@@ -29,9 +33,7 @@
29
33
  "fastify-plugin": "^4.5.0",
30
34
  "@modelcontextprotocol/sdk": "^1.0.0",
31
35
  "@inquirer/prompts": "^7.0.0",
32
- "nanoid": "^5.0.0",
33
- "zod": "^3.22.0",
34
- "undici": "^6.0.0"
36
+ "nanoid": "^5.0.0"
35
37
  },
36
38
  "devDependencies": {
37
39
  "@gigai/shared": "*",
@@ -1,281 +0,0 @@
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"]),
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
- function decodeJWTPayload(token) {
262
- const parts = token.split(".");
263
- if (parts.length !== 3) {
264
- throw new Error("Invalid JWT format: expected 3 segments");
265
- }
266
- const payload = parts[1];
267
- const base64 = payload.replace(/-/g, "+").replace(/_/g, "/");
268
- const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
269
- const decoded = Buffer.from(padded, "base64").toString("utf8");
270
- return JSON.parse(decoded);
271
- }
272
-
273
- export {
274
- encrypt,
275
- decrypt,
276
- generateEncryptionKey,
277
- ErrorCode,
278
- GigaiError,
279
- GigaiConfigSchema,
280
- decodeJWTPayload
281
- };