crukx-mcp 0.1.0 → 0.1.2
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/bin/cli.js +110 -44
- package/dist/server.js +75 -41
- package/package.json +13 -4
- package/dist/bin/cli.d.ts +0 -1
- package/dist/chunk-5FGEDZZW.js +0 -55
package/dist/bin/cli.js
CHANGED
|
@@ -1,60 +1,126 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
#!/usr/bin/env node
|
|
3
|
-
import {
|
|
4
|
-
CONFIG_PATH,
|
|
5
|
-
clearAuth,
|
|
6
|
-
getConfig,
|
|
7
|
-
loadAuth,
|
|
8
|
-
saveAuth
|
|
9
|
-
} from "../chunk-5FGEDZZW.js";
|
|
10
2
|
|
|
11
3
|
// src/bin/cli.ts
|
|
12
4
|
import { Command } from "commander";
|
|
13
|
-
import { mkdirSync } from "fs";
|
|
5
|
+
import { mkdirSync as mkdirSync2 } from "fs";
|
|
6
|
+
import { dirname as dirname2 } from "path";
|
|
7
|
+
|
|
8
|
+
// src/auth/index.ts
|
|
9
|
+
import { mkdirSync, writeFileSync, readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
|
|
14
10
|
import { dirname } from "path";
|
|
15
|
-
|
|
11
|
+
|
|
12
|
+
// src/config/index.ts
|
|
13
|
+
import "dotenv/config";
|
|
14
|
+
import { z } from "zod";
|
|
15
|
+
import { homedir } from "os";
|
|
16
|
+
import { join } from "path";
|
|
17
|
+
import { readFileSync, existsSync } from "fs";
|
|
18
|
+
var ConfigSchema = z.object({
|
|
19
|
+
CRUKX_API_URL: z.string().url().default("https://crukx-gateway.salmonisland-7ebc5692.centralindia.azurecontainerapps.io"),
|
|
20
|
+
CRUKX_ACCESS_TOKEN: z.string().optional(),
|
|
21
|
+
CRUKX_WORKSPACE_ID: z.string().optional()
|
|
22
|
+
});
|
|
23
|
+
function loadLocalConfig() {
|
|
24
|
+
const configPath = join(homedir(), ".crukx", "config.json");
|
|
25
|
+
if (!existsSync(configPath)) return {};
|
|
26
|
+
try {
|
|
27
|
+
return JSON.parse(readFileSync(configPath, "utf-8"));
|
|
28
|
+
} catch {
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function getConfig() {
|
|
33
|
+
const local = loadLocalConfig();
|
|
34
|
+
return ConfigSchema.parse({ ...local, ...process.env });
|
|
35
|
+
}
|
|
36
|
+
var CONFIG_PATH = join(homedir(), ".crukx", "config.json");
|
|
37
|
+
|
|
38
|
+
// src/auth/index.ts
|
|
39
|
+
function saveAuth(auth) {
|
|
40
|
+
mkdirSync(dirname(CONFIG_PATH), { recursive: true });
|
|
41
|
+
const existing = loadAuth() ?? {};
|
|
42
|
+
writeFileSync(CONFIG_PATH, JSON.stringify({ ...existing, ...auth }, null, 2));
|
|
43
|
+
}
|
|
44
|
+
function loadAuth() {
|
|
45
|
+
if (!existsSync2(CONFIG_PATH)) return null;
|
|
46
|
+
try {
|
|
47
|
+
return JSON.parse(readFileSync2(CONFIG_PATH, "utf-8"));
|
|
48
|
+
} catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function clearAuth() {
|
|
53
|
+
if (existsSync2(CONFIG_PATH)) writeFileSync(CONFIG_PATH, "{}");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// src/bin/cli.ts
|
|
16
57
|
import { spawn } from "child_process";
|
|
17
58
|
import { fileURLToPath } from "url";
|
|
18
|
-
import { join, dirname as pathDirname } from "path";
|
|
59
|
+
import { join as join2, dirname as pathDirname } from "path";
|
|
19
60
|
var __dirname = pathDirname(fileURLToPath(import.meta.url));
|
|
20
61
|
var program = new Command();
|
|
21
|
-
program.name("crukx").description("Crukx CLI \u2014 reliability control plane for autonomous software engineering").version("0.1.
|
|
22
|
-
program.command("login").description("Authenticate with Crukx").option("--api-url <url>", "Crukx gateway URL", getConfig().CRUKX_API_URL).
|
|
23
|
-
|
|
24
|
-
|
|
62
|
+
program.name("crukx").description("Crukx CLI \u2014 reliability control plane for autonomous software engineering").version("0.1.2");
|
|
63
|
+
program.command("login").description("Authenticate with Crukx via browser").option("--api-url <url>", "Crukx gateway URL", getConfig().CRUKX_API_URL).action(async (opts) => {
|
|
64
|
+
process.stderr.write("Opening browser to complete login\u2026\n");
|
|
65
|
+
let startData;
|
|
25
66
|
try {
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
rl.close();
|
|
30
|
-
process.stderr.write("Authenticating...\n");
|
|
31
|
-
const res = await fetch(`${opts.apiUrl}/v1/mcp/auth/login`, {
|
|
32
|
-
method: "POST",
|
|
33
|
-
headers: { "Content-Type": "application/json" },
|
|
34
|
-
body: JSON.stringify({ email, password, workspace_id: workspaceId })
|
|
35
|
-
});
|
|
36
|
-
if (!res.ok) {
|
|
37
|
-
const err = await res.json();
|
|
38
|
-
process.stderr.write(`Login failed: ${err.error ?? res.status}
|
|
39
|
-
`);
|
|
40
|
-
process.exit(1);
|
|
41
|
-
}
|
|
42
|
-
const data = await res.json();
|
|
43
|
-
mkdirSync(dirname(CONFIG_PATH), { recursive: true });
|
|
44
|
-
saveAuth({
|
|
45
|
-
access_token: data.access_token,
|
|
46
|
-
workspace_id: data.workspace_id,
|
|
47
|
-
expires_at: data.expires_at,
|
|
48
|
-
api_url: opts.apiUrl
|
|
49
|
-
});
|
|
50
|
-
process.stderr.write(`\u2705 Logged in. Config saved to ${CONFIG_PATH}
|
|
51
|
-
`);
|
|
67
|
+
const res = await fetch(`${opts.apiUrl}/v1/mcp/auth/device/start`, { method: "POST" });
|
|
68
|
+
if (!res.ok) throw new Error(`Gateway error: ${res.status}`);
|
|
69
|
+
startData = await res.json();
|
|
52
70
|
} catch (err) {
|
|
53
|
-
|
|
54
|
-
process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
|
|
71
|
+
process.stderr.write(`Failed to start login: ${err instanceof Error ? err.message : String(err)}
|
|
55
72
|
`);
|
|
56
73
|
process.exit(1);
|
|
57
74
|
}
|
|
75
|
+
const { default: open } = await import("open");
|
|
76
|
+
await open(startData.url);
|
|
77
|
+
process.stderr.write(`
|
|
78
|
+
If the browser didn't open, visit:
|
|
79
|
+
${startData.url}
|
|
80
|
+
|
|
81
|
+
Waiting for you to complete login in the browser\u2026
|
|
82
|
+
`);
|
|
83
|
+
const deadline = new Date(startData.expires_at).getTime();
|
|
84
|
+
const interval = startData.poll_interval_ms ?? 2e3;
|
|
85
|
+
while (Date.now() < deadline) {
|
|
86
|
+
await new Promise((r) => setTimeout(r, interval));
|
|
87
|
+
try {
|
|
88
|
+
const pollRes = await fetch(`${opts.apiUrl}/v1/mcp/auth/device/poll/${startData.code}`);
|
|
89
|
+
if (pollRes.status === 410) {
|
|
90
|
+
process.stderr.write("Code expired. Run crukx login again.\n");
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
if (!pollRes.ok) continue;
|
|
94
|
+
const poll = await pollRes.json();
|
|
95
|
+
if (poll.status !== "complete") continue;
|
|
96
|
+
const claimRes = await fetch(`${opts.apiUrl}/v1/mcp/auth/device/claim`, {
|
|
97
|
+
method: "POST",
|
|
98
|
+
headers: { "Content-Type": "application/json" },
|
|
99
|
+
body: JSON.stringify({ code: startData.code })
|
|
100
|
+
});
|
|
101
|
+
if (!claimRes.ok) {
|
|
102
|
+
const err = await claimRes.json();
|
|
103
|
+
process.stderr.write(`Claim failed: ${err.error ?? claimRes.status}
|
|
104
|
+
`);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
const claimed = await claimRes.json();
|
|
108
|
+
mkdirSync2(dirname2(CONFIG_PATH), { recursive: true });
|
|
109
|
+
saveAuth({
|
|
110
|
+
access_token: claimed.access_token,
|
|
111
|
+
workspace_id: claimed.workspace_id,
|
|
112
|
+
expires_at: claimed.expires_at,
|
|
113
|
+
api_url: opts.apiUrl
|
|
114
|
+
});
|
|
115
|
+
process.stderr.write(`
|
|
116
|
+
\u2705 Logged in! Config saved to ${CONFIG_PATH}
|
|
117
|
+
`);
|
|
118
|
+
process.exit(0);
|
|
119
|
+
} catch {
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
process.stderr.write("Login timed out. Run crukx login again.\n");
|
|
123
|
+
process.exit(1);
|
|
58
124
|
});
|
|
59
125
|
program.command("logout").description("Revoke current session").action(() => {
|
|
60
126
|
clearAuth();
|
|
@@ -72,7 +138,7 @@ API: ${auth.api_url}
|
|
|
72
138
|
`);
|
|
73
139
|
});
|
|
74
140
|
program.command("mcp").description("Start the Crukx MCP server (stdio transport)").action(() => {
|
|
75
|
-
const serverPath =
|
|
141
|
+
const serverPath = join2(__dirname, "server.js");
|
|
76
142
|
const child = spawn(process.execPath, [serverPath], {
|
|
77
143
|
stdio: "inherit",
|
|
78
144
|
env: process.env
|
package/dist/server.js
CHANGED
|
@@ -1,47 +1,81 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
getConfig,
|
|
4
|
-
loadAuth
|
|
5
|
-
} from "./chunk-5FGEDZZW.js";
|
|
6
|
-
|
|
7
1
|
// src/server.ts
|
|
8
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
9
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
10
4
|
|
|
11
5
|
// src/tools/index.ts
|
|
12
|
-
import { z as
|
|
6
|
+
import { z as z3 } from "zod";
|
|
13
7
|
|
|
14
|
-
// src/
|
|
8
|
+
// src/auth/index.ts
|
|
9
|
+
import { mkdirSync, writeFileSync, readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
|
|
10
|
+
import { dirname } from "path";
|
|
11
|
+
|
|
12
|
+
// src/config/index.ts
|
|
13
|
+
import "dotenv/config";
|
|
15
14
|
import { z } from "zod";
|
|
15
|
+
import { homedir } from "os";
|
|
16
|
+
import { join } from "path";
|
|
17
|
+
import { readFileSync, existsSync } from "fs";
|
|
18
|
+
var ConfigSchema = z.object({
|
|
19
|
+
CRUKX_API_URL: z.string().url().default("https://crukx-gateway.salmonisland-7ebc5692.centralindia.azurecontainerapps.io"),
|
|
20
|
+
CRUKX_ACCESS_TOKEN: z.string().optional(),
|
|
21
|
+
CRUKX_WORKSPACE_ID: z.string().optional()
|
|
22
|
+
});
|
|
23
|
+
function loadLocalConfig() {
|
|
24
|
+
const configPath = join(homedir(), ".crukx", "config.json");
|
|
25
|
+
if (!existsSync(configPath)) return {};
|
|
26
|
+
try {
|
|
27
|
+
return JSON.parse(readFileSync(configPath, "utf-8"));
|
|
28
|
+
} catch {
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function getConfig() {
|
|
33
|
+
const local = loadLocalConfig();
|
|
34
|
+
return ConfigSchema.parse({ ...local, ...process.env });
|
|
35
|
+
}
|
|
36
|
+
var CONFIG_PATH = join(homedir(), ".crukx", "config.json");
|
|
37
|
+
|
|
38
|
+
// src/auth/index.ts
|
|
39
|
+
function loadAuth() {
|
|
40
|
+
if (!existsSync2(CONFIG_PATH)) return null;
|
|
41
|
+
try {
|
|
42
|
+
return JSON.parse(readFileSync2(CONFIG_PATH, "utf-8"));
|
|
43
|
+
} catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/api/client.ts
|
|
49
|
+
import { z as z2 } from "zod";
|
|
16
50
|
import { randomUUID } from "crypto";
|
|
17
51
|
var TIMEOUT_MS = 6e4;
|
|
18
|
-
var AuditResultSchema =
|
|
19
|
-
auditId:
|
|
20
|
-
findings:
|
|
21
|
-
id:
|
|
22
|
-
rule:
|
|
23
|
-
severity:
|
|
24
|
-
message:
|
|
25
|
-
file:
|
|
26
|
-
line:
|
|
27
|
-
suggestion:
|
|
28
|
-
confidence:
|
|
29
|
-
category:
|
|
52
|
+
var AuditResultSchema = z2.object({
|
|
53
|
+
auditId: z2.string(),
|
|
54
|
+
findings: z2.array(z2.object({
|
|
55
|
+
id: z2.string(),
|
|
56
|
+
rule: z2.string(),
|
|
57
|
+
severity: z2.enum(["critical", "high", "medium", "low", "info"]),
|
|
58
|
+
message: z2.string(),
|
|
59
|
+
file: z2.string(),
|
|
60
|
+
line: z2.number(),
|
|
61
|
+
suggestion: z2.string().optional(),
|
|
62
|
+
confidence: z2.number(),
|
|
63
|
+
category: z2.string()
|
|
30
64
|
})),
|
|
31
|
-
summary:
|
|
32
|
-
totalFindings:
|
|
33
|
-
criticalCount:
|
|
34
|
-
highCount:
|
|
35
|
-
mediumCount:
|
|
36
|
-
lowCount:
|
|
37
|
-
infoCount:
|
|
38
|
-
reliabilityScore:
|
|
39
|
-
confidence:
|
|
65
|
+
summary: z2.object({
|
|
66
|
+
totalFindings: z2.number(),
|
|
67
|
+
criticalCount: z2.number(),
|
|
68
|
+
highCount: z2.number(),
|
|
69
|
+
mediumCount: z2.number(),
|
|
70
|
+
lowCount: z2.number(),
|
|
71
|
+
infoCount: z2.number(),
|
|
72
|
+
reliabilityScore: z2.number(),
|
|
73
|
+
confidence: z2.number()
|
|
40
74
|
}),
|
|
41
|
-
metadata:
|
|
42
|
-
processingTimeMs:
|
|
43
|
-
agentsUsed:
|
|
44
|
-
swarmId:
|
|
75
|
+
metadata: z2.object({
|
|
76
|
+
processingTimeMs: z2.number(),
|
|
77
|
+
agentsUsed: z2.array(z2.string()),
|
|
78
|
+
swarmId: z2.string()
|
|
45
79
|
})
|
|
46
80
|
});
|
|
47
81
|
async function request(path, init = {}) {
|
|
@@ -134,9 +168,9 @@ function registerTools(server2) {
|
|
|
134
168
|
"swarm_audit",
|
|
135
169
|
"Run a full Crukx 7-agent swarm audit on code. Returns reliability score, findings, and recommendations.",
|
|
136
170
|
{
|
|
137
|
-
diff:
|
|
138
|
-
repoPath:
|
|
139
|
-
focus:
|
|
171
|
+
diff: z3.string().optional().describe("Unified diff or code snippet to audit"),
|
|
172
|
+
repoPath: z3.string().optional().describe("Repository path or name for context"),
|
|
173
|
+
focus: z3.string().optional().describe('Specific area to focus on (e.g. "security", "concurrency")')
|
|
140
174
|
},
|
|
141
175
|
async ({ diff, repoPath, focus }) => {
|
|
142
176
|
const result = await swarmAudit({ diff, repoPath, focus });
|
|
@@ -147,7 +181,7 @@ function registerTools(server2) {
|
|
|
147
181
|
"security_scan",
|
|
148
182
|
"Run a targeted security scan using the Red Teamer and Hunter agents.",
|
|
149
183
|
{
|
|
150
|
-
diff:
|
|
184
|
+
diff: z3.string().describe("Code diff or snippet to scan for security issues")
|
|
151
185
|
},
|
|
152
186
|
async ({ diff }) => {
|
|
153
187
|
const result = await swarmAudit({ diff, focus: "security vulnerabilities, injection attacks, secrets, authentication flaws" });
|
|
@@ -164,7 +198,7 @@ ${lines.join("\n")}` }] };
|
|
|
164
198
|
"reliability_score",
|
|
165
199
|
"Get a reliability score for a code change without full findings detail.",
|
|
166
200
|
{
|
|
167
|
-
diff:
|
|
201
|
+
diff: z3.string().describe("Code diff to score")
|
|
168
202
|
},
|
|
169
203
|
async ({ diff }) => {
|
|
170
204
|
const result = await swarmAudit({ diff });
|
|
@@ -183,7 +217,7 @@ ${lines.join("\n")}` }] };
|
|
|
183
217
|
"report_fetch",
|
|
184
218
|
"Fetch a previously generated Crukx audit report by ID.",
|
|
185
219
|
{
|
|
186
|
-
report_id:
|
|
220
|
+
report_id: z3.string().uuid().describe("Audit run ID to fetch")
|
|
187
221
|
},
|
|
188
222
|
async ({ report_id }) => {
|
|
189
223
|
const report = await fetchReport(report_id);
|
|
@@ -194,8 +228,8 @@ ${lines.join("\n")}` }] };
|
|
|
194
228
|
"suggest_fix",
|
|
195
229
|
"Get remediation suggestions for a specific finding or code issue.",
|
|
196
230
|
{
|
|
197
|
-
issue:
|
|
198
|
-
severity:
|
|
231
|
+
issue: z3.string().describe("Description of the issue or paste the problematic code"),
|
|
232
|
+
severity: z3.enum(["critical", "high", "medium", "low"]).optional().describe("Severity level")
|
|
199
233
|
},
|
|
200
234
|
async ({ issue, severity }) => {
|
|
201
235
|
const focus = `remediation and fix suggestions for: ${issue}. Severity: ${severity ?? "unknown"}`;
|
package/package.json
CHANGED
|
@@ -1,22 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "crukx-mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Crukx MCP server — reliability control plane for autonomous software engineering",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/server.js",
|
|
7
7
|
"bin": {
|
|
8
|
-
"crukx": "
|
|
8
|
+
"crukx": "dist/bin/cli.js"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"dist",
|
|
12
12
|
"README.md"
|
|
13
13
|
],
|
|
14
|
-
"keywords": [
|
|
14
|
+
"keywords": [
|
|
15
|
+
"mcp",
|
|
16
|
+
"crukx",
|
|
17
|
+
"reliability",
|
|
18
|
+
"ai",
|
|
19
|
+
"llm",
|
|
20
|
+
"code-review",
|
|
21
|
+
"swarm"
|
|
22
|
+
],
|
|
15
23
|
"author": "Crukx",
|
|
16
24
|
"license": "MIT",
|
|
17
25
|
"repository": {
|
|
18
26
|
"type": "git",
|
|
19
|
-
"url": "https://github.com/Shafwansafi06/observability-hub"
|
|
27
|
+
"url": "git+https://github.com/Shafwansafi06/observability-hub.git"
|
|
20
28
|
},
|
|
21
29
|
"scripts": {
|
|
22
30
|
"build": "tsup",
|
|
@@ -28,6 +36,7 @@
|
|
|
28
36
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
29
37
|
"commander": "^12.1.0",
|
|
30
38
|
"dotenv": "^16.4.5",
|
|
39
|
+
"open": "^10.1.0",
|
|
31
40
|
"zod": "^3.23.8"
|
|
32
41
|
},
|
|
33
42
|
"devDependencies": {
|
package/dist/bin/cli.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
package/dist/chunk-5FGEDZZW.js
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// src/config/index.ts
|
|
4
|
-
import "dotenv/config";
|
|
5
|
-
import { z } from "zod";
|
|
6
|
-
import { homedir } from "os";
|
|
7
|
-
import { join } from "path";
|
|
8
|
-
import { readFileSync, existsSync } from "fs";
|
|
9
|
-
var ConfigSchema = z.object({
|
|
10
|
-
CRUKX_API_URL: z.string().url().default("https://crukx-gateway.salmonisland-7ebc5692.centralindia.azurecontainerapps.io"),
|
|
11
|
-
CRUKX_ACCESS_TOKEN: z.string().optional(),
|
|
12
|
-
CRUKX_WORKSPACE_ID: z.string().optional()
|
|
13
|
-
});
|
|
14
|
-
function loadLocalConfig() {
|
|
15
|
-
const configPath = join(homedir(), ".crukx", "config.json");
|
|
16
|
-
if (!existsSync(configPath)) return {};
|
|
17
|
-
try {
|
|
18
|
-
return JSON.parse(readFileSync(configPath, "utf-8"));
|
|
19
|
-
} catch {
|
|
20
|
-
return {};
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
function getConfig() {
|
|
24
|
-
const local = loadLocalConfig();
|
|
25
|
-
return ConfigSchema.parse({ ...local, ...process.env });
|
|
26
|
-
}
|
|
27
|
-
var CONFIG_PATH = join(homedir(), ".crukx", "config.json");
|
|
28
|
-
|
|
29
|
-
// src/auth/index.ts
|
|
30
|
-
import { mkdirSync, writeFileSync, readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
|
|
31
|
-
import { dirname } from "path";
|
|
32
|
-
function saveAuth(auth) {
|
|
33
|
-
mkdirSync(dirname(CONFIG_PATH), { recursive: true });
|
|
34
|
-
const existing = loadAuth() ?? {};
|
|
35
|
-
writeFileSync(CONFIG_PATH, JSON.stringify({ ...existing, ...auth }, null, 2));
|
|
36
|
-
}
|
|
37
|
-
function loadAuth() {
|
|
38
|
-
if (!existsSync2(CONFIG_PATH)) return null;
|
|
39
|
-
try {
|
|
40
|
-
return JSON.parse(readFileSync2(CONFIG_PATH, "utf-8"));
|
|
41
|
-
} catch {
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
function clearAuth() {
|
|
46
|
-
if (existsSync2(CONFIG_PATH)) writeFileSync(CONFIG_PATH, "{}");
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export {
|
|
50
|
-
getConfig,
|
|
51
|
-
CONFIG_PATH,
|
|
52
|
-
saveAuth,
|
|
53
|
-
loadAuth,
|
|
54
|
-
clearAuth
|
|
55
|
-
};
|