@naia-team/cli 0.1.1 → 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/README.md +7 -0
- package/package.json +1 -1
- package/src/commands/auth-login.js +13 -1
- package/src/commands/uninstall.js +127 -0
- package/src/commands/utils.js +6 -0
- package/src/lib/auth-store.js +28 -0
- package/src/main.js +12 -1
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ npx @naia-team/cli install
|
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
14
|
npx @naia-team/cli auth login --org-slug <org-slug> --webapp-url <webapp-url>
|
|
15
|
+
npx @naia-team/cli auth logout --profile default
|
|
15
16
|
```
|
|
16
17
|
|
|
17
18
|
## Verify
|
|
@@ -33,3 +34,9 @@ npx @naia-team/cli platform invoices issue --invoice-id <id>
|
|
|
33
34
|
```bash
|
|
34
35
|
npx @naia-team/cli mcp serve
|
|
35
36
|
```
|
|
37
|
+
|
|
38
|
+
## Uninstall
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npx @naia-team/cli uninstall
|
|
42
|
+
```
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { createServer } from "node:http";
|
|
3
3
|
import { URL } from "node:url";
|
|
4
|
-
import { writeAuthProfile } from "../lib/auth-store.js";
|
|
4
|
+
import { removeAuthProfile, writeAuthProfile } from "../lib/auth-store.js";
|
|
5
5
|
import { parseArgVector } from "../lib/args.js";
|
|
6
6
|
import { readCliConfig } from "../lib/config-store.js";
|
|
7
7
|
|
|
@@ -27,6 +27,18 @@ export async function runAuthLogin(args) {
|
|
|
27
27
|
console.log(`memberId: ${callback.memberId}`);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
export async function runAuthLogout(args) {
|
|
31
|
+
const { options } = parseArgVector(args);
|
|
32
|
+
const defaults = await readCliConfig();
|
|
33
|
+
const profile = options.profile ?? defaults.defaultProfile ?? "default";
|
|
34
|
+
const removed = await removeAuthProfile(profile);
|
|
35
|
+
if (!removed) {
|
|
36
|
+
console.log(`No auth profile found for '${profile}'.`);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
console.log(`Logged out profile '${profile}'.`);
|
|
40
|
+
}
|
|
41
|
+
|
|
30
42
|
async function waitForCallback(config, state) {
|
|
31
43
|
return new Promise((resolve, reject) => {
|
|
32
44
|
const server = createServer((req, res) => {
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { readFile, writeFile, copyFile } from "node:fs/promises";
|
|
3
|
+
import { join, dirname } from "node:path";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { parseArgVector } from "../lib/args.js";
|
|
6
|
+
import { ensureDir } from "./utils.js";
|
|
7
|
+
|
|
8
|
+
const ALL_TARGETS = ["codex", "claude-code", "claude-desktop"];
|
|
9
|
+
|
|
10
|
+
export async function runUninstall(args) {
|
|
11
|
+
const { options } = parseArgVector(args);
|
|
12
|
+
const targets = parseTargets(options.targets);
|
|
13
|
+
const selected = targets.length > 0 ? targets : ALL_TARGETS;
|
|
14
|
+
const results = [];
|
|
15
|
+
|
|
16
|
+
for (const target of selected) {
|
|
17
|
+
if (target === "codex") {
|
|
18
|
+
results.push(await uninstallCodex());
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if (target === "claude-code") {
|
|
22
|
+
results.push(await uninstallClaudeCode());
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (target === "claude-desktop") {
|
|
26
|
+
results.push(await uninstallClaudeDesktop());
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
console.log("Naia CLI uninstall completed.");
|
|
32
|
+
for (const item of results) {
|
|
33
|
+
console.log(`- ${item.target}: ${item.status}${item.detail ? ` -> ${item.detail}` : ""}`);
|
|
34
|
+
}
|
|
35
|
+
console.log("");
|
|
36
|
+
console.log("Optional cleanup:");
|
|
37
|
+
console.log("- npx @naia-team/cli auth logout --profile default");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function parseTargets(raw) {
|
|
41
|
+
if (!raw) return [];
|
|
42
|
+
return raw
|
|
43
|
+
.split(",")
|
|
44
|
+
.map((item) => item.trim().toLowerCase())
|
|
45
|
+
.filter((item) => ALL_TARGETS.includes(item));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function uninstallCodex() {
|
|
49
|
+
const filePath = join(homedir(), ".codex", "config.toml");
|
|
50
|
+
if (!existsSync(filePath)) {
|
|
51
|
+
return { target: "codex", status: "skipped", detail: "No ~/.codex/config.toml" };
|
|
52
|
+
}
|
|
53
|
+
const existing = await readFile(filePath, "utf8");
|
|
54
|
+
const cleaned = stripCodexNaiaBlock(existing);
|
|
55
|
+
if (cleaned === existing) {
|
|
56
|
+
return { target: "codex", status: "skipped", detail: "No naia MCP block found." };
|
|
57
|
+
}
|
|
58
|
+
await backupFile(filePath);
|
|
59
|
+
await writeFile(filePath, cleaned.trimEnd() + "\n", "utf8");
|
|
60
|
+
return { target: "codex", status: "removed", detail: filePath };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function uninstallClaudeCode() {
|
|
64
|
+
const remove = await import("node:child_process").then(({ spawnSync }) =>
|
|
65
|
+
spawnSync("claude", ["mcp", "remove", "-s", "user", "naia"], {
|
|
66
|
+
stdio: "pipe",
|
|
67
|
+
encoding: "utf8",
|
|
68
|
+
})
|
|
69
|
+
);
|
|
70
|
+
if (remove.status === 0) {
|
|
71
|
+
return { target: "claude-code", status: "removed", detail: "Removed user-scope MCP server 'naia'." };
|
|
72
|
+
}
|
|
73
|
+
return { target: "claude-code", status: "skipped", detail: "Could not remove (not configured or CLI unavailable)." };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async function uninstallClaudeDesktop() {
|
|
77
|
+
const filePath = resolveClaudeDesktopPath();
|
|
78
|
+
if (!existsSync(filePath)) {
|
|
79
|
+
return { target: "claude-desktop", status: "skipped", detail: "No desktop config file found." };
|
|
80
|
+
}
|
|
81
|
+
const existing = JSON.parse(await readFile(filePath, "utf8"));
|
|
82
|
+
if (!existing?.mcpServers?.naia) {
|
|
83
|
+
return { target: "claude-desktop", status: "skipped", detail: "No naia MCP server found." };
|
|
84
|
+
}
|
|
85
|
+
delete existing.mcpServers.naia;
|
|
86
|
+
await ensureDir(dirname(filePath));
|
|
87
|
+
await backupFile(filePath);
|
|
88
|
+
await writeFile(filePath, JSON.stringify(existing, null, 2), "utf8");
|
|
89
|
+
return { target: "claude-desktop", status: "removed", detail: filePath };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function resolveClaudeDesktopPath() {
|
|
93
|
+
if (process.platform === "darwin") {
|
|
94
|
+
return join(homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
95
|
+
}
|
|
96
|
+
if (process.platform === "win32") {
|
|
97
|
+
const appData = process.env.APPDATA ?? join(homedir(), "AppData", "Roaming");
|
|
98
|
+
return join(appData, "Claude", "claude_desktop_config.json");
|
|
99
|
+
}
|
|
100
|
+
return join(homedir(), ".config", "Claude", "claude_desktop_config.json");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function stripCodexNaiaBlock(source) {
|
|
104
|
+
const lines = source.split("\n");
|
|
105
|
+
const result = [];
|
|
106
|
+
let skipping = false;
|
|
107
|
+
for (const line of lines) {
|
|
108
|
+
const trimmed = line.trim();
|
|
109
|
+
if (trimmed === "[mcp_servers.naia]" || trimmed === "[mcp_servers.naia.env]") {
|
|
110
|
+
skipping = true;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (skipping && trimmed.startsWith("[") && trimmed.endsWith("]")) {
|
|
114
|
+
skipping = false;
|
|
115
|
+
}
|
|
116
|
+
if (!skipping) {
|
|
117
|
+
result.push(line);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return result.join("\n");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function backupFile(path) {
|
|
124
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
125
|
+
await copyFile(path, `${path}.${timestamp}.bak`);
|
|
126
|
+
}
|
|
127
|
+
|
package/src/lib/auth-store.js
CHANGED
|
@@ -39,6 +39,34 @@ export async function writeAuthProfile(input) {
|
|
|
39
39
|
await writeFile(filePath, JSON.stringify(next, null, 2), { mode: 0o600 });
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
export async function removeAuthProfile(profile = "default") {
|
|
43
|
+
const filePath = getAuthStorePath();
|
|
44
|
+
const existing = await readStore(filePath);
|
|
45
|
+
if (!existing?.profiles || typeof existing.profiles !== "object") {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
const resolvedProfile = profile === "default"
|
|
49
|
+
? (existing.defaultProfile || "default")
|
|
50
|
+
: profile;
|
|
51
|
+
if (!existing.profiles[resolvedProfile]) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
const nextProfiles = { ...existing.profiles };
|
|
55
|
+
delete nextProfiles[resolvedProfile];
|
|
56
|
+
|
|
57
|
+
const nextDefault = existing.defaultProfile === resolvedProfile
|
|
58
|
+
? (Object.keys(nextProfiles)[0] ?? "default")
|
|
59
|
+
: (existing.defaultProfile || "default");
|
|
60
|
+
|
|
61
|
+
const next = {
|
|
62
|
+
defaultProfile: nextDefault,
|
|
63
|
+
profiles: nextProfiles,
|
|
64
|
+
};
|
|
65
|
+
await mkdir(dirname(filePath), { recursive: true });
|
|
66
|
+
await writeFile(filePath, JSON.stringify(next, null, 2), { mode: 0o600 });
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
|
|
42
70
|
async function readStore(filePath) {
|
|
43
71
|
try {
|
|
44
72
|
const raw = await readFile(filePath, "utf8");
|
package/src/main.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { runAuthLogin } from "./commands/auth-login.js";
|
|
1
|
+
import { runAuthLogin, runAuthLogout } from "./commands/auth-login.js";
|
|
2
2
|
import { runInstall } from "./commands/install.js";
|
|
3
3
|
import { runDoctor } from "./commands/doctor.js";
|
|
4
4
|
import { runPlatform } from "./commands/platform.js";
|
|
5
5
|
import { runMcpServe } from "./commands/mcp-serve.js";
|
|
6
6
|
import { runSession } from "./commands/session-run.js";
|
|
7
|
+
import { runUninstall } from "./commands/uninstall.js";
|
|
7
8
|
|
|
8
9
|
export async function main() {
|
|
9
10
|
const args = process.argv.slice(2);
|
|
@@ -17,10 +18,18 @@ export async function main() {
|
|
|
17
18
|
await runAuthLogin(rest);
|
|
18
19
|
return;
|
|
19
20
|
}
|
|
21
|
+
if (group === "auth" && action === "logout") {
|
|
22
|
+
await runAuthLogout(rest);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
20
25
|
if (group === "install") {
|
|
21
26
|
await runInstall([action, ...rest].filter(Boolean));
|
|
22
27
|
return;
|
|
23
28
|
}
|
|
29
|
+
if (group === "uninstall") {
|
|
30
|
+
await runUninstall([action, ...rest].filter(Boolean));
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
24
33
|
if (group === "doctor") {
|
|
25
34
|
await runDoctor([action, ...rest].filter(Boolean));
|
|
26
35
|
return;
|
|
@@ -49,8 +58,10 @@ export async function main() {
|
|
|
49
58
|
function printUsage() {
|
|
50
59
|
console.log(`Usage:
|
|
51
60
|
naia install [--targets codex,claude-code,claude-desktop,manual] [--local true]
|
|
61
|
+
naia uninstall [--targets codex,claude-code,claude-desktop]
|
|
52
62
|
naia doctor [--runtime-url <url>] [--profile default]
|
|
53
63
|
naia auth login --org-slug <slug> [--webapp-url <url>] [--profile default]
|
|
64
|
+
naia auth logout [--profile default]
|
|
54
65
|
naia session run --message "hola" [--runtime-url <url>]
|
|
55
66
|
naia platform invoices list [--runtime-url <url>]
|
|
56
67
|
naia mcp serve
|