cleargate 0.1.0-alpha.1

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/cli.cjs ADDED
@@ -0,0 +1,459 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
18
+ // If the importer is in node compatibility mode or this is not an ESM
19
+ // file that has been converted to a CommonJS file using a Babel-
20
+ // compatible transform (i.e. "__esModule" has not been set), then set
21
+ // "default" to the CommonJS "module.exports" for node compatibility.
22
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
+ mod
24
+ ));
25
+
26
+ // src/cli.ts
27
+ var import_commander = require("commander");
28
+
29
+ // package.json
30
+ var package_default = {
31
+ name: "cleargate",
32
+ version: "0.1.0-alpha.1",
33
+ private: false,
34
+ type: "module",
35
+ description: "ClearGate CLI \u2014 connects AI agent teams to the ClearGate MCP server",
36
+ bin: {
37
+ cleargate: "dist/cli.js"
38
+ },
39
+ main: "./dist/cli.cjs",
40
+ module: "./dist/cli.js",
41
+ exports: {
42
+ ".": {
43
+ types: "./dist/cli.d.ts",
44
+ import: "./dist/cli.js",
45
+ require: "./dist/cli.cjs"
46
+ },
47
+ "./admin-api": {
48
+ types: "./dist/admin-api/index.d.ts",
49
+ import: "./dist/admin-api/index.js",
50
+ require: "./dist/admin-api/index.cjs"
51
+ }
52
+ },
53
+ files: [
54
+ "dist",
55
+ "README.md"
56
+ ],
57
+ engines: {
58
+ node: ">=24.0.0"
59
+ },
60
+ scripts: {
61
+ build: "tsup",
62
+ dev: "tsup --watch",
63
+ typecheck: "tsc --noEmit",
64
+ pretest: "npm run build",
65
+ test: "vitest run",
66
+ "test:watch": "vitest"
67
+ },
68
+ dependencies: {
69
+ "@napi-rs/keyring": "^1.2.0",
70
+ commander: "^12",
71
+ zod: "^4.3.0"
72
+ },
73
+ devDependencies: {
74
+ "@types/node": "^24.0.0",
75
+ tsup: "^8",
76
+ typescript: "^5.8.0",
77
+ vitest: "^2.1.0"
78
+ }
79
+ };
80
+
81
+ // src/commands/_stub.ts
82
+ function stubHandler(name) {
83
+ return () => {
84
+ process.stderr.write(`${name}: not yet implemented
85
+ `);
86
+ process.exit(1);
87
+ };
88
+ }
89
+
90
+ // src/commands/join.ts
91
+ var os3 = __toESM(require("os"), 1);
92
+
93
+ // src/config.ts
94
+ var fs = __toESM(require("fs"), 1);
95
+ var os = __toESM(require("os"), 1);
96
+ var path = __toESM(require("path"), 1);
97
+ var import_zod = require("zod");
98
+ var ConfigSchema = import_zod.z.object({
99
+ mcpUrl: import_zod.z.string().url().optional(),
100
+ profile: import_zod.z.string().min(1).default("default"),
101
+ logLevel: import_zod.z.enum(["debug", "info", "warn", "error"]).default("info")
102
+ }).strict();
103
+ function loadConfig(opts = {}) {
104
+ const {
105
+ flags = {},
106
+ env = process.env,
107
+ configPath
108
+ } = opts;
109
+ const resolvedConfigPath = configPath ?? (() => {
110
+ const home = os.homedir();
111
+ if (!home) return null;
112
+ return path.join(home, ".cleargate", "config.json");
113
+ })();
114
+ let fileLayer = {};
115
+ if (resolvedConfigPath) {
116
+ try {
117
+ const raw = fs.readFileSync(resolvedConfigPath, "utf8");
118
+ let parsed;
119
+ try {
120
+ parsed = JSON.parse(raw);
121
+ } catch {
122
+ throw new Error(
123
+ `Failed to parse config file at ${resolvedConfigPath}: invalid JSON`
124
+ );
125
+ }
126
+ const fileResult = ConfigSchema.safeParse(parsed);
127
+ if (!fileResult.success) {
128
+ throw new Error(
129
+ `Invalid config file at ${resolvedConfigPath}: ${fileResult.error.message}`
130
+ );
131
+ }
132
+ fileLayer = fileResult.data;
133
+ } catch (err) {
134
+ if (err instanceof Error && "code" in err && err.code === "ENOENT") {
135
+ } else {
136
+ throw err;
137
+ }
138
+ }
139
+ }
140
+ const envLayer = {};
141
+ if (env["CLEARGATE_MCP_URL"]) {
142
+ envLayer.mcpUrl = env["CLEARGATE_MCP_URL"];
143
+ }
144
+ if (env["CLEARGATE_PROFILE"]) {
145
+ envLayer.profile = env["CLEARGATE_PROFILE"];
146
+ }
147
+ if (env["CLEARGATE_LOG_LEVEL"]) {
148
+ envLayer.logLevel = env["CLEARGATE_LOG_LEVEL"];
149
+ }
150
+ const merged = {
151
+ ...fileLayer,
152
+ ...envLayer,
153
+ ...flags.mcpUrl !== void 0 ? { mcpUrl: flags.mcpUrl } : {},
154
+ ...flags.profile !== void 0 ? { profile: flags.profile } : {},
155
+ ...flags.logLevel !== void 0 ? { logLevel: flags.logLevel } : {}
156
+ };
157
+ for (const key of Object.keys(merged)) {
158
+ if (merged[key] === void 0) {
159
+ delete merged[key];
160
+ }
161
+ }
162
+ const result = ConfigSchema.safeParse(merged);
163
+ if (!result.success) {
164
+ throw new Error(`Config validation failed: ${result.error.message}`);
165
+ }
166
+ return result.data;
167
+ }
168
+
169
+ // src/auth/factory.ts
170
+ var os2 = __toESM(require("os"), 1);
171
+ var path3 = __toESM(require("path"), 1);
172
+
173
+ // src/auth/keychain-store.ts
174
+ var import_keyring = require("@napi-rs/keyring");
175
+ var KeychainTokenStore = class {
176
+ constructor(service) {
177
+ this.service = service;
178
+ }
179
+ service;
180
+ backend = "keychain";
181
+ async save(profile, token) {
182
+ new import_keyring.Entry(this.service, profile).setPassword(token);
183
+ }
184
+ async load(profile) {
185
+ try {
186
+ const result = new import_keyring.Entry(this.service, profile).getPassword();
187
+ return result ?? null;
188
+ } catch {
189
+ return null;
190
+ }
191
+ }
192
+ async remove(profile) {
193
+ try {
194
+ new import_keyring.Entry(this.service, profile).deletePassword();
195
+ } catch {
196
+ }
197
+ }
198
+ };
199
+
200
+ // src/auth/file-store.ts
201
+ var fs2 = __toESM(require("fs/promises"), 1);
202
+ var path2 = __toESM(require("path"), 1);
203
+ var import_zod2 = require("zod");
204
+ var ProfileEntrySchema = import_zod2.z.object({ refreshToken: import_zod2.z.string().min(1) }).strict();
205
+ var AuthFileSchema = import_zod2.z.object({
206
+ version: import_zod2.z.literal(1),
207
+ profiles: import_zod2.z.record(import_zod2.z.string().min(1), ProfileEntrySchema)
208
+ }).strict();
209
+ var EMPTY_AUTH_FILE = { version: 1, profiles: {} };
210
+ var FileTokenStore = class {
211
+ constructor(filePath) {
212
+ this.filePath = filePath;
213
+ }
214
+ filePath;
215
+ backend = "file";
216
+ async save(profile, token) {
217
+ const current = await this.readFile();
218
+ const updated = {
219
+ ...current,
220
+ profiles: {
221
+ ...current.profiles,
222
+ [profile]: { refreshToken: token }
223
+ }
224
+ };
225
+ await this.writeFile(updated);
226
+ }
227
+ async load(profile) {
228
+ const data = await this.readFile();
229
+ return data.profiles[profile]?.refreshToken ?? null;
230
+ }
231
+ async remove(profile) {
232
+ let current;
233
+ try {
234
+ current = await this.readFile();
235
+ } catch {
236
+ return;
237
+ }
238
+ if (!(profile in current.profiles)) {
239
+ return;
240
+ }
241
+ const { [profile]: _removed, ...rest } = current.profiles;
242
+ const updated = { ...current, profiles: rest };
243
+ await this.writeFile(updated);
244
+ }
245
+ async readFile() {
246
+ let raw;
247
+ try {
248
+ raw = await fs2.readFile(this.filePath, "utf8");
249
+ } catch (err) {
250
+ if (err.code === "ENOENT") {
251
+ return EMPTY_AUTH_FILE;
252
+ }
253
+ throw err;
254
+ }
255
+ let parsed;
256
+ try {
257
+ parsed = JSON.parse(raw);
258
+ } catch {
259
+ throw new Error(
260
+ `Failed to parse auth file at ${this.filePath}: invalid JSON`
261
+ );
262
+ }
263
+ const result = AuthFileSchema.safeParse(parsed);
264
+ if (!result.success) {
265
+ const versionCheck = parsed?.["version"];
266
+ if (versionCheck !== 1) {
267
+ throw new Error(
268
+ `Invalid auth file at ${this.filePath}: unsupported version ${String(versionCheck)}. Please upgrade \`cleargate\` to read this file.`
269
+ );
270
+ }
271
+ throw new Error(
272
+ `Invalid auth file at ${this.filePath}: ${result.error.message}`
273
+ );
274
+ }
275
+ return result.data;
276
+ }
277
+ async writeFile(data) {
278
+ const dir = path2.dirname(this.filePath);
279
+ await fs2.mkdir(dir, { recursive: true, mode: 448 });
280
+ await fs2.chmod(dir, 448).catch(() => {
281
+ });
282
+ const json = JSON.stringify(data, null, 2);
283
+ const tmpPath = path2.join(dir, ".auth.json.tmp");
284
+ await fs2.writeFile(tmpPath, json, { mode: 384 });
285
+ await fs2.chmod(tmpPath, 384);
286
+ await fs2.rename(tmpPath, this.filePath);
287
+ await fs2.chmod(this.filePath, 384);
288
+ }
289
+ };
290
+
291
+ // src/auth/factory.ts
292
+ var DEFAULT_KEYCHAIN_SERVICE = "cleargate";
293
+ function resolveFilePath(opts) {
294
+ if (opts.filePath) return opts.filePath;
295
+ const home = os2.homedir();
296
+ if (!home) {
297
+ throw new Error(
298
+ "Cannot determine home directory. Set opts.filePath explicitly or ensure os.homedir() returns a non-empty string."
299
+ );
300
+ }
301
+ return path3.join(home, ".cleargate", "auth.json");
302
+ }
303
+ function defaultWarn(msg) {
304
+ process.stderr.write(msg + "\n");
305
+ }
306
+ async function createTokenStore(opts = {}) {
307
+ const filePath = resolveFilePath(opts);
308
+ const service = opts.keychainService ?? DEFAULT_KEYCHAIN_SERVICE;
309
+ const warn = opts.warn ?? defaultWarn;
310
+ if (opts.forceBackend === "file") {
311
+ return new FileTokenStore(filePath);
312
+ }
313
+ if (opts.forceBackend === "keychain") {
314
+ return new KeychainTokenStore(service);
315
+ }
316
+ try {
317
+ const { Entry: Entry2 } = await import("@napi-rs/keyring");
318
+ new Entry2(service, "__cleargate_probe__").getPassword();
319
+ return new KeychainTokenStore(service);
320
+ } catch {
321
+ warn(
322
+ `cleargate: OS keychain unavailable, falling back to file storage at ${filePath}. Run with --log-level=debug for details.`
323
+ );
324
+ return new FileTokenStore(filePath);
325
+ }
326
+ }
327
+
328
+ // src/commands/join.ts
329
+ var UUID_V4_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
330
+ async function joinHandler(opts) {
331
+ const fetchFn = opts.fetch ?? globalThis.fetch;
332
+ const stdout = opts.stdout ?? ((s) => process.stdout.write(s));
333
+ const stderr = opts.stderr ?? ((s) => process.stderr.write(s));
334
+ const exit = opts.exit ?? ((c) => process.exit(c));
335
+ const hostname2 = opts.hostname ?? (() => os3.hostname());
336
+ let token;
337
+ let baseUrl;
338
+ try {
339
+ if (UUID_V4_RE.test(opts.inviteUrl)) {
340
+ token = opts.inviteUrl;
341
+ const cfg = loadConfig({
342
+ flags: { profile: opts.profile, mcpUrl: opts.mcpUrlFlag }
343
+ });
344
+ if (!cfg.mcpUrl) {
345
+ stderr(
346
+ "cleargate: bare invite token requires mcpUrl. Pass --mcp-url <url> or set CLEARGATE_MCP_URL.\n"
347
+ );
348
+ exit(5);
349
+ return;
350
+ }
351
+ baseUrl = cfg.mcpUrl;
352
+ } else {
353
+ const url = new URL(opts.inviteUrl);
354
+ const m = url.pathname.match(/^\/join\/([0-9a-f-]{36})$/i);
355
+ if (!m || !UUID_V4_RE.test(m[1])) {
356
+ throw new Error("bad path");
357
+ }
358
+ token = m[1];
359
+ baseUrl = url.origin;
360
+ }
361
+ } catch {
362
+ stderr("cleargate: invalid invite URL or token format.\n");
363
+ exit(5);
364
+ return;
365
+ }
366
+ let response;
367
+ try {
368
+ response = await fetchFn(`${baseUrl}/join/${token}`, { method: "POST" });
369
+ } catch (err) {
370
+ stderr(
371
+ `cleargate: cannot reach ${baseUrl} (${err instanceof Error ? err.message : String(err)}).
372
+ `
373
+ );
374
+ exit(2);
375
+ return;
376
+ }
377
+ if (response.status === 410) {
378
+ const body = await response.json().catch(() => ({}));
379
+ if (body.error === "invite_expired") {
380
+ stderr("cleargate: invite expired. Request a new invite.\n");
381
+ } else {
382
+ stderr("cleargate: invite already consumed. Request a new invite.\n");
383
+ }
384
+ exit(3);
385
+ return;
386
+ }
387
+ if (response.status === 404) {
388
+ stderr("cleargate: invite not found.\n");
389
+ exit(4);
390
+ return;
391
+ }
392
+ if (response.status === 429) {
393
+ const retry = response.headers.get("retry-after") ?? "900";
394
+ stderr(`cleargate: too many requests. Retry after ${retry}s.
395
+ `);
396
+ exit(8);
397
+ return;
398
+ }
399
+ if (response.status >= 500) {
400
+ stderr(`cleargate: server error ${response.status}.
401
+ `);
402
+ exit(6);
403
+ return;
404
+ }
405
+ if (!response.ok) {
406
+ stderr(`cleargate: unexpected status ${response.status}.
407
+ `);
408
+ exit(7);
409
+ return;
410
+ }
411
+ let rawBody;
412
+ try {
413
+ rawBody = await response.json();
414
+ } catch {
415
+ stderr("cleargate: server returned non-JSON response.\n");
416
+ exit(7);
417
+ return;
418
+ }
419
+ const b = rawBody;
420
+ if (typeof b.refresh_token !== "string" || typeof b.project_name !== "string") {
421
+ stderr("cleargate: server returned unexpected response shape.\n");
422
+ exit(7);
423
+ return;
424
+ }
425
+ const refreshToken = b.refresh_token;
426
+ const projectName = b.project_name;
427
+ try {
428
+ const store = await (opts.createStore ?? createTokenStore)();
429
+ await store.save(opts.profile, refreshToken);
430
+ stdout(`joined project '${projectName}' as '${hostname2()}'
431
+ `);
432
+ stdout(`refresh token saved to ${store.backend}.
433
+ `);
434
+ } catch (err) {
435
+ stderr(
436
+ `cleargate: internal error: ${err instanceof Error ? err.message : String(err)}
437
+ `
438
+ );
439
+ exit(99);
440
+ }
441
+ }
442
+
443
+ // src/cli.ts
444
+ var program = new import_commander.Command();
445
+ program.name("cleargate").description("ClearGate CLI \u2014 connects AI agent teams to the ClearGate MCP server").version(package_default.version, "-V, --version").option("--profile <name>", "configuration profile to use", "default").option("--mcp-url <url>", "MCP server URL (overrides config file and env)").showHelpAfterError("(use `cleargate --help`)");
446
+ program.command("join <invite-url>").description("join a ClearGate workspace using an invite URL").action(async (inviteUrl, _opts, command) => {
447
+ const globals = command.parent.opts();
448
+ await joinHandler({
449
+ inviteUrl,
450
+ profile: globals.profile,
451
+ mcpUrlFlag: globals.mcpUrl
452
+ });
453
+ });
454
+ program.command("whoami").description("print the currently authenticated agent identity").action(stubHandler("whoami"));
455
+ program.command("stamp").description("stamp a delivery artifact into the MCP server").action(stubHandler("stamp"));
456
+ program.command("wiki").description("query or update the workspace wiki").action(stubHandler("wiki"));
457
+ program.command("admin").description("administrative operations (create-project, invite, issue-token, revoke-token)").action(stubHandler("admin"));
458
+ void program.parseAsync(process.argv);
459
+ //# sourceMappingURL=cli.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts","../package.json","../src/commands/_stub.ts","../src/commands/join.ts","../src/config.ts","../src/auth/factory.ts","../src/auth/keychain-store.ts","../src/auth/file-store.ts"],"sourcesContent":["import { Command } from 'commander';\nimport pkg from '../package.json' with { type: 'json' };\nimport { stubHandler } from './commands/_stub.js';\nimport { joinHandler } from './commands/join.js';\n\nconst program = new Command();\n\nprogram\n .name('cleargate')\n .description('ClearGate CLI — connects AI agent teams to the ClearGate MCP server')\n .version(pkg.version, '-V, --version')\n .option('--profile <name>', 'configuration profile to use', 'default')\n .option('--mcp-url <url>', 'MCP server URL (overrides config file and env)')\n .showHelpAfterError('(use `cleargate --help`)');\n\nprogram\n .command('join <invite-url>')\n .description('join a ClearGate workspace using an invite URL')\n .action(async (inviteUrl: string, _opts: Record<string, unknown>, command: Command) => {\n const globals = command.parent!.opts<{ profile: string; mcpUrl?: string }>();\n await joinHandler({\n inviteUrl,\n profile: globals.profile,\n mcpUrlFlag: globals.mcpUrl,\n });\n });\n\nprogram\n .command('whoami')\n .description('print the currently authenticated agent identity')\n .action(stubHandler('whoami'));\n\nprogram\n .command('stamp')\n .description('stamp a delivery artifact into the MCP server')\n .action(stubHandler('stamp'));\n\nprogram\n .command('wiki')\n .description('query or update the workspace wiki')\n .action(stubHandler('wiki'));\n\nprogram\n .command('admin')\n .description('administrative operations (create-project, invite, issue-token, revoke-token)')\n .action(stubHandler('admin'));\n\nvoid program.parseAsync(process.argv);\n","{\n \"name\": \"cleargate\",\n \"version\": \"0.1.0-alpha.1\",\n \"private\": false,\n \"type\": \"module\",\n \"description\": \"ClearGate CLI — connects AI agent teams to the ClearGate MCP server\",\n \"bin\": {\n \"cleargate\": \"dist/cli.js\"\n },\n \"main\": \"./dist/cli.cjs\",\n \"module\": \"./dist/cli.js\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/cli.d.ts\",\n \"import\": \"./dist/cli.js\",\n \"require\": \"./dist/cli.cjs\"\n },\n \"./admin-api\": {\n \"types\": \"./dist/admin-api/index.d.ts\",\n \"import\": \"./dist/admin-api/index.js\",\n \"require\": \"./dist/admin-api/index.cjs\"\n }\n },\n \"files\": [\n \"dist\",\n \"README.md\"\n ],\n \"engines\": {\n \"node\": \">=24.0.0\"\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"typecheck\": \"tsc --noEmit\",\n \"pretest\": \"npm run build\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\"\n },\n \"dependencies\": {\n \"@napi-rs/keyring\": \"^1.2.0\",\n \"commander\": \"^12\",\n \"zod\": \"^4.3.0\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^24.0.0\",\n \"tsup\": \"^8\",\n \"typescript\": \"^5.8.0\",\n \"vitest\": \"^2.1.0\"\n }\n}\n","/**\n * Shared stub handler for all not-yet-implemented subcommands.\n * Writes \"<name>: not yet implemented\" to stderr and exits 1.\n */\nexport function stubHandler(name: string): () => never {\n return (): never => {\n process.stderr.write(`${name}: not yet implemented\\n`);\n process.exit(1);\n };\n}\n","import * as os from 'node:os';\nimport { loadConfig } from '../config.js';\nimport { createTokenStore } from '../auth/factory.js';\n\nconst UUID_V4_RE =\n /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\nexport interface JoinOptions {\n inviteUrl: string;\n profile: string;\n mcpUrlFlag?: string;\n /** Test seam: replaces globalThis.fetch */\n fetch?: typeof globalThis.fetch;\n /** Test seam: replaces createTokenStore */\n createStore?: typeof createTokenStore;\n /** Test seam: replaces os.hostname() */\n hostname?: () => string;\n /** Test seam: replaces process.stdout.write */\n stdout?: (s: string) => void;\n /** Test seam: replaces process.stderr.write */\n stderr?: (s: string) => void;\n /** Test seam: replaces process.exit */\n exit?: (code: number) => never;\n}\n\nexport async function joinHandler(opts: JoinOptions): Promise<void> {\n const fetchFn = opts.fetch ?? globalThis.fetch;\n const stdout = opts.stdout ?? ((s) => process.stdout.write(s));\n const stderr = opts.stderr ?? ((s) => process.stderr.write(s));\n const exit = opts.exit ?? ((c: number): never => process.exit(c));\n const hostname = opts.hostname ?? (() => os.hostname());\n\n // ── Parse inviteUrl → { token, baseUrl } ──────────────────────────────────\n let token: string;\n let baseUrl: string;\n\n try {\n if (UUID_V4_RE.test(opts.inviteUrl)) {\n // Bare UUID form — requires mcpUrl from config\n token = opts.inviteUrl;\n const cfg = loadConfig({\n flags: { profile: opts.profile, mcpUrl: opts.mcpUrlFlag },\n });\n if (!cfg.mcpUrl) {\n stderr(\n 'cleargate: bare invite token requires mcpUrl. Pass --mcp-url <url> or set CLEARGATE_MCP_URL.\\n',\n );\n exit(5);\n return; // unreachable — satisfies TypeScript after mock exit\n }\n baseUrl = cfg.mcpUrl;\n } else {\n // Full URL form: https://host/join/<uuid>\n const url = new URL(opts.inviteUrl);\n const m = url.pathname.match(/^\\/join\\/([0-9a-f-]{36})$/i);\n if (!m || !UUID_V4_RE.test(m[1]!)) {\n throw new Error('bad path');\n }\n token = m[1]!;\n baseUrl = url.origin;\n }\n } catch {\n stderr('cleargate: invalid invite URL or token format.\\n');\n exit(5);\n return; // unreachable\n }\n\n // ── POST /join/:token ──────────────────────────────────────────────────────\n let response: Response;\n try {\n response = await fetchFn(`${baseUrl}/join/${token}`, { method: 'POST' });\n } catch (err) {\n stderr(\n `cleargate: cannot reach ${baseUrl} (${err instanceof Error ? err.message : String(err)}).\\n`,\n );\n exit(2);\n return; // unreachable\n }\n\n // ── Error status handling ──────────────────────────────────────────────────\n if (response.status === 410) {\n const body = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n if (body.error === 'invite_expired') {\n stderr('cleargate: invite expired. Request a new invite.\\n');\n } else {\n stderr('cleargate: invite already consumed. Request a new invite.\\n');\n }\n exit(3);\n return;\n }\n\n if (response.status === 404) {\n stderr('cleargate: invite not found.\\n');\n exit(4);\n return;\n }\n\n if (response.status === 429) {\n const retry = response.headers.get('retry-after') ?? '900';\n stderr(`cleargate: too many requests. Retry after ${retry}s.\\n`);\n exit(8);\n return;\n }\n\n if (response.status >= 500) {\n stderr(`cleargate: server error ${response.status}.\\n`);\n exit(6);\n return;\n }\n\n if (!response.ok) {\n stderr(`cleargate: unexpected status ${response.status}.\\n`);\n exit(7);\n return;\n }\n\n // ── 200 — extract with named field access (NEVER spread) ──────────────────\n let rawBody: unknown;\n try {\n rawBody = await response.json();\n } catch {\n stderr('cleargate: server returned non-JSON response.\\n');\n exit(7);\n return;\n }\n\n const b = rawBody as {\n refresh_token?: unknown;\n project_name?: unknown;\n member_role?: unknown;\n };\n\n if (typeof b.refresh_token !== 'string' || typeof b.project_name !== 'string') {\n stderr('cleargate: server returned unexpected response shape.\\n');\n exit(7);\n return;\n }\n\n // ── Seat the refresh token ─────────────────────────────────────────────────\n // Named field access — b.refresh_token is a bare string, never logged\n const refreshToken: string = b.refresh_token;\n const projectName: string = b.project_name;\n\n try {\n const store = await (opts.createStore ?? createTokenStore)();\n await store.save(opts.profile, refreshToken);\n\n // ── Success output (D10) ─────────────────────────────────────────────────\n stdout(`joined project '${projectName}' as '${hostname()}'\\n`);\n stdout(`refresh token saved to ${store.backend}.\\n`);\n } catch (err) {\n stderr(\n `cleargate: internal error: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n exit(99);\n }\n}\n","import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { z } from 'zod';\n\nexport const ConfigSchema = z\n .object({\n mcpUrl: z.string().url().optional(),\n profile: z.string().min(1).default('default'),\n logLevel: z.enum(['debug', 'info', 'warn', 'error']).default('info'),\n })\n .strict();\n\nexport type Config = z.infer<typeof ConfigSchema>;\n\n/** Partial raw config used for each layer before merge */\ntype RawConfig = Partial<{\n mcpUrl: string | undefined;\n profile: string | undefined;\n logLevel: string | undefined;\n}>;\n\nexport interface LoadConfigOptions {\n flags?: RawConfig;\n env?: NodeJS.ProcessEnv;\n configPath?: string;\n}\n\n/**\n * Synchronously loads and merges config from all layers:\n * flags > env > config file > zod defaults\n */\nexport function loadConfig(opts: LoadConfigOptions = {}): Config {\n const {\n flags = {},\n env = process.env,\n configPath,\n } = opts;\n\n // Resolve config file path\n const resolvedConfigPath =\n configPath ??\n (() => {\n const home = os.homedir();\n if (!home) return null;\n return path.join(home, '.cleargate', 'config.json');\n })();\n\n // Layer: file\n let fileLayer: RawConfig = {};\n if (resolvedConfigPath) {\n try {\n const raw = fs.readFileSync(resolvedConfigPath, 'utf8');\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(\n `Failed to parse config file at ${resolvedConfigPath}: invalid JSON`,\n );\n }\n // Validate file contents strictly (unknown keys will throw here)\n const fileResult = ConfigSchema.safeParse(parsed);\n if (!fileResult.success) {\n throw new Error(\n `Invalid config file at ${resolvedConfigPath}: ${fileResult.error.message}`,\n );\n }\n fileLayer = fileResult.data;\n } catch (err) {\n // Re-throw parse/validation errors; silently skip only ENOENT\n if (\n err instanceof Error &&\n 'code' in err &&\n (err as NodeJS.ErrnoException).code === 'ENOENT'\n ) {\n // file doesn't exist — skip silently\n } else {\n throw err;\n }\n }\n }\n\n // Layer: env\n const envLayer: RawConfig = {};\n if (env['CLEARGATE_MCP_URL']) {\n envLayer.mcpUrl = env['CLEARGATE_MCP_URL'];\n }\n if (env['CLEARGATE_PROFILE']) {\n envLayer.profile = env['CLEARGATE_PROFILE'];\n }\n if (env['CLEARGATE_LOG_LEVEL']) {\n envLayer.logLevel = env['CLEARGATE_LOG_LEVEL'];\n }\n\n // Merge: flags > env > file (start from {} so zod defaults fill in missing fields)\n const merged: Record<string, unknown> = {\n ...fileLayer,\n ...envLayer,\n ...(flags.mcpUrl !== undefined ? { mcpUrl: flags.mcpUrl } : {}),\n ...(flags.profile !== undefined ? { profile: flags.profile } : {}),\n ...(flags.logLevel !== undefined ? { logLevel: flags.logLevel } : {}),\n };\n\n // Remove undefined values so zod defaults apply properly\n for (const key of Object.keys(merged)) {\n if (merged[key] === undefined) {\n delete merged[key];\n }\n }\n\n const result = ConfigSchema.safeParse(merged);\n if (!result.success) {\n throw new Error(`Config validation failed: ${result.error.message}`);\n }\n\n return result.data;\n}\n\n/**\n * Asserts mcpUrl is present, throws a user-friendly error if not.\n */\nexport function requireMcpUrl(cfg: Config): string {\n if (cfg.mcpUrl === undefined) {\n throw new Error(\n 'mcpUrl not configured. Run `cleargate join <invite-url>` first.',\n );\n }\n return cfg.mcpUrl;\n}\n","import * as os from 'node:os';\nimport * as path from 'node:path';\nimport { KeychainTokenStore } from './keychain-store.js';\nimport { FileTokenStore } from './file-store.js';\nimport type { TokenStore, TokenStoreFactoryOptions } from './token-store.js';\n\nconst DEFAULT_KEYCHAIN_SERVICE = 'cleargate';\n\nfunction resolveFilePath(opts: TokenStoreFactoryOptions): string {\n if (opts.filePath) return opts.filePath;\n const home = os.homedir();\n if (!home) {\n throw new Error(\n 'Cannot determine home directory. Set opts.filePath explicitly or ensure os.homedir() returns a non-empty string.',\n );\n }\n return path.join(home, '.cleargate', 'auth.json');\n}\n\nfunction defaultWarn(msg: string): void {\n process.stderr.write(msg + '\\n');\n}\n\n/**\n * Creates a TokenStore, selecting the keychain backend when available and\n * falling back to file storage with a stderr warning when the OS keychain\n * cannot be accessed.\n */\nexport async function createTokenStore(\n opts: TokenStoreFactoryOptions = {},\n): Promise<TokenStore> {\n const filePath = resolveFilePath(opts);\n const service = opts.keychainService ?? DEFAULT_KEYCHAIN_SERVICE;\n const warn = opts.warn ?? defaultWarn;\n\n // Short-circuit if backend is forced (test seam, skips probe)\n if (opts.forceBackend === 'file') {\n return new FileTokenStore(filePath);\n }\n if (opts.forceBackend === 'keychain') {\n return new KeychainTokenStore(service);\n }\n\n // Probe the keychain to determine availability\n try {\n const { Entry } = await import('@napi-rs/keyring');\n new Entry(service, '__cleargate_probe__').getPassword();\n // Probe succeeded (returned string | null cleanly) — use keychain\n return new KeychainTokenStore(service);\n } catch {\n // Constructor threw (native module load failed, libsecret missing on Linux)\n // OR getPassword() threw (dbus not running, prompt cancelled)\n // Either way, keychain is unavailable for this CLI invocation\n warn(\n `cleargate: OS keychain unavailable, falling back to file storage at ${filePath}. Run with --log-level=debug for details.`,\n );\n return new FileTokenStore(filePath);\n }\n}\n","import { Entry } from '@napi-rs/keyring';\nimport type { TokenStore } from './token-store.js';\n\nexport class KeychainTokenStore implements TokenStore {\n readonly backend = 'keychain' as const;\n\n constructor(private readonly service: string) {}\n\n async save(profile: string, token: string): Promise<void> {\n new Entry(this.service, profile).setPassword(token);\n }\n\n async load(profile: string): Promise<string | null> {\n try {\n const result = new Entry(this.service, profile).getPassword();\n // getPassword() returns string | null per @napi-rs/keyring@1.2.0 index.d.ts:124\n // Despite the docstring claiming it throws NoEntry, the return type wins.\n // Handle both: null return AND potential thrown NoEntry (platform-specific).\n return result ?? null;\n } catch {\n // NoEntry or other keychain error — treat as absent\n return null;\n }\n }\n\n async remove(profile: string): Promise<void> {\n try {\n new Entry(this.service, profile).deletePassword();\n } catch {\n // Entry didn't exist or other keychain error — idempotent, swallow\n }\n }\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { z } from 'zod';\nimport type { TokenStore } from './token-store.js';\n\nconst ProfileEntrySchema = z.object({ refreshToken: z.string().min(1) }).strict();\n\nexport const AuthFileSchema = z\n .object({\n version: z.literal(1),\n profiles: z.record(z.string().min(1), ProfileEntrySchema),\n })\n .strict();\n\ntype AuthFile = z.infer<typeof AuthFileSchema>;\n\nconst EMPTY_AUTH_FILE: AuthFile = { version: 1, profiles: {} };\n\nexport class FileTokenStore implements TokenStore {\n readonly backend = 'file' as const;\n\n constructor(private readonly filePath: string) {}\n\n async save(profile: string, token: string): Promise<void> {\n const current = await this.readFile();\n const updated: AuthFile = {\n ...current,\n profiles: {\n ...current.profiles,\n [profile]: { refreshToken: token },\n },\n };\n await this.writeFile(updated);\n }\n\n async load(profile: string): Promise<string | null> {\n const data = await this.readFile();\n return data.profiles[profile]?.refreshToken ?? null;\n }\n\n async remove(profile: string): Promise<void> {\n let current: AuthFile;\n try {\n current = await this.readFile();\n } catch {\n // File doesn't exist or unreadable — no-op since there's nothing to remove\n return;\n }\n if (!(profile in current.profiles)) {\n return; // Profile doesn't exist — idempotent\n }\n const { [profile]: _removed, ...rest } = current.profiles;\n const updated: AuthFile = { ...current, profiles: rest };\n await this.writeFile(updated);\n }\n\n private async readFile(): Promise<AuthFile> {\n let raw: string;\n try {\n raw = await fs.readFile(this.filePath, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return EMPTY_AUTH_FILE;\n }\n throw err;\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(\n `Failed to parse auth file at ${this.filePath}: invalid JSON`,\n );\n }\n\n const result = AuthFileSchema.safeParse(parsed);\n if (!result.success) {\n // Check for version mismatch specifically\n const versionCheck = (parsed as Record<string, unknown>)?.['version'];\n if (versionCheck !== 1) {\n throw new Error(\n `Invalid auth file at ${this.filePath}: unsupported version ${String(versionCheck)}. Please upgrade \\`cleargate\\` to read this file.`,\n );\n }\n throw new Error(\n `Invalid auth file at ${this.filePath}: ${result.error.message}`,\n );\n }\n\n return result.data;\n }\n\n private async writeFile(data: AuthFile): Promise<void> {\n const dir = path.dirname(this.filePath);\n await fs.mkdir(dir, { recursive: true, mode: 0o700 });\n // Explicit chmod after mkdir — mkdir only sets mode on newly created dirs\n await fs.chmod(dir, 0o700).catch(() => {\n // If chmod fails on existing dir, that's acceptable — we don't want to\n // surprise users who have set custom modes on ~/.cleargate/\n });\n\n const json = JSON.stringify(data, null, 2);\n const tmpPath = path.join(dir, '.auth.json.tmp');\n\n // Atomic write: write to tmp then rename to avoid partial-write corruption\n await fs.writeFile(tmpPath, json, { mode: 0o600 });\n // Explicit chmod after writeFile — writeFile only sets mode on file creation\n await fs.chmod(tmpPath, 0o600);\n await fs.rename(tmpPath, this.filePath);\n // After rename, chmod the final path to ensure it stays 0600\n await fs.chmod(this.filePath, 0o600);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uBAAwB;;;ACAxB;AAAA,EACE,MAAQ;AAAA,EACR,SAAW;AAAA,EACX,SAAW;AAAA,EACX,MAAQ;AAAA,EACR,aAAe;AAAA,EACf,KAAO;AAAA,IACL,WAAa;AAAA,EACf;AAAA,EACA,MAAQ;AAAA,EACR,QAAU;AAAA,EACV,SAAW;AAAA,IACT,KAAK;AAAA,MACH,OAAS;AAAA,MACT,QAAU;AAAA,MACV,SAAW;AAAA,IACb;AAAA,IACA,eAAe;AAAA,MACb,OAAS;AAAA,MACT,QAAU;AAAA,MACV,SAAW;AAAA,IACb;AAAA,EACF;AAAA,EACA,OAAS;AAAA,IACP;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAW;AAAA,IACT,MAAQ;AAAA,EACV;AAAA,EACA,SAAW;AAAA,IACT,OAAS;AAAA,IACT,KAAO;AAAA,IACP,WAAa;AAAA,IACb,SAAW;AAAA,IACX,MAAQ;AAAA,IACR,cAAc;AAAA,EAChB;AAAA,EACA,cAAgB;AAAA,IACd,oBAAoB;AAAA,IACpB,WAAa;AAAA,IACb,KAAO;AAAA,EACT;AAAA,EACA,iBAAmB;AAAA,IACjB,eAAe;AAAA,IACf,MAAQ;AAAA,IACR,YAAc;AAAA,IACd,QAAU;AAAA,EACZ;AACF;;;AC7CO,SAAS,YAAY,MAA2B;AACrD,SAAO,MAAa;AAClB,YAAQ,OAAO,MAAM,GAAG,IAAI;AAAA,CAAyB;AACrD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;;;ACTA,IAAAA,MAAoB;;;ACApB,SAAoB;AACpB,SAAoB;AACpB,WAAsB;AACtB,iBAAkB;AAEX,IAAM,eAAe,aACzB,OAAO;AAAA,EACN,QAAQ,aAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EAClC,SAAS,aAAE,OAAO,EAAE,IAAI,CAAC,EAAE,QAAQ,SAAS;AAAA,EAC5C,UAAU,aAAE,KAAK,CAAC,SAAS,QAAQ,QAAQ,OAAO,CAAC,EAAE,QAAQ,MAAM;AACrE,CAAC,EACA,OAAO;AAqBH,SAAS,WAAW,OAA0B,CAAC,GAAW;AAC/D,QAAM;AAAA,IACJ,QAAQ,CAAC;AAAA,IACT,MAAM,QAAQ;AAAA,IACd;AAAA,EACF,IAAI;AAGJ,QAAM,qBACJ,eACC,MAAM;AACL,UAAM,OAAU,WAAQ;AACxB,QAAI,CAAC,KAAM,QAAO;AAClB,WAAY,UAAK,MAAM,cAAc,aAAa;AAAA,EACpD,GAAG;AAGL,MAAI,YAAuB,CAAC;AAC5B,MAAI,oBAAoB;AACtB,QAAI;AACF,YAAM,MAAS,gBAAa,oBAAoB,MAAM;AACtD,UAAI;AACJ,UAAI;AACF,iBAAS,KAAK,MAAM,GAAG;AAAA,MACzB,QAAQ;AACN,cAAM,IAAI;AAAA,UACR,kCAAkC,kBAAkB;AAAA,QACtD;AAAA,MACF;AAEA,YAAM,aAAa,aAAa,UAAU,MAAM;AAChD,UAAI,CAAC,WAAW,SAAS;AACvB,cAAM,IAAI;AAAA,UACR,0BAA0B,kBAAkB,KAAK,WAAW,MAAM,OAAO;AAAA,QAC3E;AAAA,MACF;AACA,kBAAY,WAAW;AAAA,IACzB,SAAS,KAAK;AAEZ,UACE,eAAe,SACf,UAAU,OACT,IAA8B,SAAS,UACxC;AAAA,MAEF,OAAO;AACL,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAGA,QAAM,WAAsB,CAAC;AAC7B,MAAI,IAAI,mBAAmB,GAAG;AAC5B,aAAS,SAAS,IAAI,mBAAmB;AAAA,EAC3C;AACA,MAAI,IAAI,mBAAmB,GAAG;AAC5B,aAAS,UAAU,IAAI,mBAAmB;AAAA,EAC5C;AACA,MAAI,IAAI,qBAAqB,GAAG;AAC9B,aAAS,WAAW,IAAI,qBAAqB;AAAA,EAC/C;AAGA,QAAM,SAAkC;AAAA,IACtC,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAI,MAAM,WAAW,SAAY,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;AAAA,IAC7D,GAAI,MAAM,YAAY,SAAY,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;AAAA,IAChE,GAAI,MAAM,aAAa,SAAY,EAAE,UAAU,MAAM,SAAS,IAAI,CAAC;AAAA,EACrE;AAGA,aAAW,OAAO,OAAO,KAAK,MAAM,GAAG;AACrC,QAAI,OAAO,GAAG,MAAM,QAAW;AAC7B,aAAO,OAAO,GAAG;AAAA,IACnB;AAAA,EACF;AAEA,QAAM,SAAS,aAAa,UAAU,MAAM;AAC5C,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,IAAI,MAAM,6BAA6B,OAAO,MAAM,OAAO,EAAE;AAAA,EACrE;AAEA,SAAO,OAAO;AAChB;;;ACrHA,IAAAC,MAAoB;AACpB,IAAAC,QAAsB;;;ACDtB,qBAAsB;AAGf,IAAM,qBAAN,MAA+C;AAAA,EAGpD,YAA6B,SAAiB;AAAjB;AAAA,EAAkB;AAAA,EAAlB;AAAA,EAFpB,UAAU;AAAA,EAInB,MAAM,KAAK,SAAiB,OAA8B;AACxD,QAAI,qBAAM,KAAK,SAAS,OAAO,EAAE,YAAY,KAAK;AAAA,EACpD;AAAA,EAEA,MAAM,KAAK,SAAyC;AAClD,QAAI;AACF,YAAM,SAAS,IAAI,qBAAM,KAAK,SAAS,OAAO,EAAE,YAAY;AAI5D,aAAO,UAAU;AAAA,IACnB,QAAQ;AAEN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,OAAO,SAAgC;AAC3C,QAAI;AACF,UAAI,qBAAM,KAAK,SAAS,OAAO,EAAE,eAAe;AAAA,IAClD,QAAQ;AAAA,IAER;AAAA,EACF;AACF;;;AChCA,IAAAC,MAAoB;AACpB,IAAAC,QAAsB;AACtB,IAAAC,cAAkB;AAGlB,IAAM,qBAAqB,cAAE,OAAO,EAAE,cAAc,cAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,OAAO;AAEzE,IAAM,iBAAiB,cAC3B,OAAO;AAAA,EACN,SAAS,cAAE,QAAQ,CAAC;AAAA,EACpB,UAAU,cAAE,OAAO,cAAE,OAAO,EAAE,IAAI,CAAC,GAAG,kBAAkB;AAC1D,CAAC,EACA,OAAO;AAIV,IAAM,kBAA4B,EAAE,SAAS,GAAG,UAAU,CAAC,EAAE;AAEtD,IAAM,iBAAN,MAA2C;AAAA,EAGhD,YAA6B,UAAkB;AAAlB;AAAA,EAAmB;AAAA,EAAnB;AAAA,EAFpB,UAAU;AAAA,EAInB,MAAM,KAAK,SAAiB,OAA8B;AACxD,UAAM,UAAU,MAAM,KAAK,SAAS;AACpC,UAAM,UAAoB;AAAA,MACxB,GAAG;AAAA,MACH,UAAU;AAAA,QACR,GAAG,QAAQ;AAAA,QACX,CAAC,OAAO,GAAG,EAAE,cAAc,MAAM;AAAA,MACnC;AAAA,IACF;AACA,UAAM,KAAK,UAAU,OAAO;AAAA,EAC9B;AAAA,EAEA,MAAM,KAAK,SAAyC;AAClD,UAAM,OAAO,MAAM,KAAK,SAAS;AACjC,WAAO,KAAK,SAAS,OAAO,GAAG,gBAAgB;AAAA,EACjD;AAAA,EAEA,MAAM,OAAO,SAAgC;AAC3C,QAAI;AACJ,QAAI;AACF,gBAAU,MAAM,KAAK,SAAS;AAAA,IAChC,QAAQ;AAEN;AAAA,IACF;AACA,QAAI,EAAE,WAAW,QAAQ,WAAW;AAClC;AAAA,IACF;AACA,UAAM,EAAE,CAAC,OAAO,GAAG,UAAU,GAAG,KAAK,IAAI,QAAQ;AACjD,UAAM,UAAoB,EAAE,GAAG,SAAS,UAAU,KAAK;AACvD,UAAM,KAAK,UAAU,OAAO;AAAA,EAC9B;AAAA,EAEA,MAAc,WAA8B;AAC1C,QAAI;AACJ,QAAI;AACF,YAAM,MAAS,aAAS,KAAK,UAAU,MAAM;AAAA,IAC/C,SAAS,KAAK;AACZ,UAAK,IAA8B,SAAS,UAAU;AACpD,eAAO;AAAA,MACT;AACA,YAAM;AAAA,IACR;AAEA,QAAI;AACJ,QAAI;AACF,eAAS,KAAK,MAAM,GAAG;AAAA,IACzB,QAAQ;AACN,YAAM,IAAI;AAAA,QACR,gCAAgC,KAAK,QAAQ;AAAA,MAC/C;AAAA,IACF;AAEA,UAAM,SAAS,eAAe,UAAU,MAAM;AAC9C,QAAI,CAAC,OAAO,SAAS;AAEnB,YAAM,eAAgB,SAAqC,SAAS;AACpE,UAAI,iBAAiB,GAAG;AACtB,cAAM,IAAI;AAAA,UACR,wBAAwB,KAAK,QAAQ,yBAAyB,OAAO,YAAY,CAAC;AAAA,QACpF;AAAA,MACF;AACA,YAAM,IAAI;AAAA,QACR,wBAAwB,KAAK,QAAQ,KAAK,OAAO,MAAM,OAAO;AAAA,MAChE;AAAA,IACF;AAEA,WAAO,OAAO;AAAA,EAChB;AAAA,EAEA,MAAc,UAAU,MAA+B;AACrD,UAAM,MAAW,cAAQ,KAAK,QAAQ;AACtC,UAAS,UAAM,KAAK,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AAEpD,UAAS,UAAM,KAAK,GAAK,EAAE,MAAM,MAAM;AAAA,IAGvC,CAAC;AAED,UAAM,OAAO,KAAK,UAAU,MAAM,MAAM,CAAC;AACzC,UAAM,UAAe,WAAK,KAAK,gBAAgB;AAG/C,UAAS,cAAU,SAAS,MAAM,EAAE,MAAM,IAAM,CAAC;AAEjD,UAAS,UAAM,SAAS,GAAK;AAC7B,UAAS,WAAO,SAAS,KAAK,QAAQ;AAEtC,UAAS,UAAM,KAAK,UAAU,GAAK;AAAA,EACrC;AACF;;;AF3GA,IAAM,2BAA2B;AAEjC,SAAS,gBAAgB,MAAwC;AAC/D,MAAI,KAAK,SAAU,QAAO,KAAK;AAC/B,QAAM,OAAU,YAAQ;AACxB,MAAI,CAAC,MAAM;AACT,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAY,WAAK,MAAM,cAAc,WAAW;AAClD;AAEA,SAAS,YAAY,KAAmB;AACtC,UAAQ,OAAO,MAAM,MAAM,IAAI;AACjC;AAOA,eAAsB,iBACpB,OAAiC,CAAC,GACb;AACrB,QAAM,WAAW,gBAAgB,IAAI;AACrC,QAAM,UAAU,KAAK,mBAAmB;AACxC,QAAM,OAAO,KAAK,QAAQ;AAG1B,MAAI,KAAK,iBAAiB,QAAQ;AAChC,WAAO,IAAI,eAAe,QAAQ;AAAA,EACpC;AACA,MAAI,KAAK,iBAAiB,YAAY;AACpC,WAAO,IAAI,mBAAmB,OAAO;AAAA,EACvC;AAGA,MAAI;AACF,UAAM,EAAE,OAAAC,OAAM,IAAI,MAAM,OAAO,kBAAkB;AACjD,QAAIA,OAAM,SAAS,qBAAqB,EAAE,YAAY;AAEtD,WAAO,IAAI,mBAAmB,OAAO;AAAA,EACvC,QAAQ;AAIN;AAAA,MACE,uEAAuE,QAAQ;AAAA,IACjF;AACA,WAAO,IAAI,eAAe,QAAQ;AAAA,EACpC;AACF;;;AFtDA,IAAM,aACJ;AAoBF,eAAsB,YAAY,MAAkC;AAClE,QAAM,UAAU,KAAK,SAAS,WAAW;AACzC,QAAM,SAAS,KAAK,WAAW,CAAC,MAAM,QAAQ,OAAO,MAAM,CAAC;AAC5D,QAAM,SAAS,KAAK,WAAW,CAAC,MAAM,QAAQ,OAAO,MAAM,CAAC;AAC5D,QAAM,OAAO,KAAK,SAAS,CAAC,MAAqB,QAAQ,KAAK,CAAC;AAC/D,QAAMC,YAAW,KAAK,aAAa,MAAS,aAAS;AAGrD,MAAI;AACJ,MAAI;AAEJ,MAAI;AACF,QAAI,WAAW,KAAK,KAAK,SAAS,GAAG;AAEnC,cAAQ,KAAK;AACb,YAAM,MAAM,WAAW;AAAA,QACrB,OAAO,EAAE,SAAS,KAAK,SAAS,QAAQ,KAAK,WAAW;AAAA,MAC1D,CAAC;AACD,UAAI,CAAC,IAAI,QAAQ;AACf;AAAA,UACE;AAAA,QACF;AACA,aAAK,CAAC;AACN;AAAA,MACF;AACA,gBAAU,IAAI;AAAA,IAChB,OAAO;AAEL,YAAM,MAAM,IAAI,IAAI,KAAK,SAAS;AAClC,YAAM,IAAI,IAAI,SAAS,MAAM,4BAA4B;AACzD,UAAI,CAAC,KAAK,CAAC,WAAW,KAAK,EAAE,CAAC,CAAE,GAAG;AACjC,cAAM,IAAI,MAAM,UAAU;AAAA,MAC5B;AACA,cAAQ,EAAE,CAAC;AACX,gBAAU,IAAI;AAAA,IAChB;AAAA,EACF,QAAQ;AACN,WAAO,kDAAkD;AACzD,SAAK,CAAC;AACN;AAAA,EACF;AAGA,MAAI;AACJ,MAAI;AACF,eAAW,MAAM,QAAQ,GAAG,OAAO,SAAS,KAAK,IAAI,EAAE,QAAQ,OAAO,CAAC;AAAA,EACzE,SAAS,KAAK;AACZ;AAAA,MACE,2BAA2B,OAAO,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA;AAAA,IACzF;AACA,SAAK,CAAC;AACN;AAAA,EACF;AAGA,MAAI,SAAS,WAAW,KAAK;AAC3B,UAAM,OAAQ,MAAM,SAAS,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAGpD,QAAI,KAAK,UAAU,kBAAkB;AACnC,aAAO,oDAAoD;AAAA,IAC7D,OAAO;AACL,aAAO,6DAA6D;AAAA,IACtE;AACA,SAAK,CAAC;AACN;AAAA,EACF;AAEA,MAAI,SAAS,WAAW,KAAK;AAC3B,WAAO,gCAAgC;AACvC,SAAK,CAAC;AACN;AAAA,EACF;AAEA,MAAI,SAAS,WAAW,KAAK;AAC3B,UAAM,QAAQ,SAAS,QAAQ,IAAI,aAAa,KAAK;AACrD,WAAO,6CAA6C,KAAK;AAAA,CAAM;AAC/D,SAAK,CAAC;AACN;AAAA,EACF;AAEA,MAAI,SAAS,UAAU,KAAK;AAC1B,WAAO,2BAA2B,SAAS,MAAM;AAAA,CAAK;AACtD,SAAK,CAAC;AACN;AAAA,EACF;AAEA,MAAI,CAAC,SAAS,IAAI;AAChB,WAAO,gCAAgC,SAAS,MAAM;AAAA,CAAK;AAC3D,SAAK,CAAC;AACN;AAAA,EACF;AAGA,MAAI;AACJ,MAAI;AACF,cAAU,MAAM,SAAS,KAAK;AAAA,EAChC,QAAQ;AACN,WAAO,iDAAiD;AACxD,SAAK,CAAC;AACN;AAAA,EACF;AAEA,QAAM,IAAI;AAMV,MAAI,OAAO,EAAE,kBAAkB,YAAY,OAAO,EAAE,iBAAiB,UAAU;AAC7E,WAAO,yDAAyD;AAChE,SAAK,CAAC;AACN;AAAA,EACF;AAIA,QAAM,eAAuB,EAAE;AAC/B,QAAM,cAAsB,EAAE;AAE9B,MAAI;AACF,UAAM,QAAQ,OAAO,KAAK,eAAe,kBAAkB;AAC3D,UAAM,MAAM,KAAK,KAAK,SAAS,YAAY;AAG3C,WAAO,mBAAmB,WAAW,SAASA,UAAS,CAAC;AAAA,CAAK;AAC7D,WAAO,0BAA0B,MAAM,OAAO;AAAA,CAAK;AAAA,EACrD,SAAS,KAAK;AACZ;AAAA,MACE,8BAA8B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA;AAAA,IAChF;AACA,SAAK,EAAE;AAAA,EACT;AACF;;;AHzJA,IAAM,UAAU,IAAI,yBAAQ;AAE5B,QACG,KAAK,WAAW,EAChB,YAAY,0EAAqE,EACjF,QAAQ,gBAAI,SAAS,eAAe,EACpC,OAAO,oBAAoB,gCAAgC,SAAS,EACpE,OAAO,mBAAmB,gDAAgD,EAC1E,mBAAmB,0BAA0B;AAEhD,QACG,QAAQ,mBAAmB,EAC3B,YAAY,gDAAgD,EAC5D,OAAO,OAAO,WAAmB,OAAgC,YAAqB;AACrF,QAAM,UAAU,QAAQ,OAAQ,KAA2C;AAC3E,QAAM,YAAY;AAAA,IAChB;AAAA,IACA,SAAS,QAAQ;AAAA,IACjB,YAAY,QAAQ;AAAA,EACtB,CAAC;AACH,CAAC;AAEH,QACG,QAAQ,QAAQ,EAChB,YAAY,kDAAkD,EAC9D,OAAO,YAAY,QAAQ,CAAC;AAE/B,QACG,QAAQ,OAAO,EACf,YAAY,+CAA+C,EAC3D,OAAO,YAAY,OAAO,CAAC;AAE9B,QACG,QAAQ,MAAM,EACd,YAAY,oCAAoC,EAChD,OAAO,YAAY,MAAM,CAAC;AAE7B,QACG,QAAQ,OAAO,EACf,YAAY,+EAA+E,EAC3F,OAAO,YAAY,OAAO,CAAC;AAE9B,KAAK,QAAQ,WAAW,QAAQ,IAAI;","names":["os","os","path","fs","path","import_zod","Entry","hostname"]}
package/dist/cli.d.cts ADDED
@@ -0,0 +1,2 @@
1
+
2
+ export { }
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+
2
+ export { }