@mcp-s/cli 0.0.15 → 0.0.16
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/SKILL.md +11 -0
- package/dist/SKILL.md +11 -0
- package/dist/daemon.js +1 -1
- package/dist/index.js +162 -80
- package/package.json +1 -1
package/SKILL.md
CHANGED
|
@@ -17,6 +17,17 @@ Access a single MCP server through the command line. MCP enables interaction wit
|
|
|
17
17
|
| `mcp-s-cli call <tool>` | Call tool (reads JSON from stdin if no args) |
|
|
18
18
|
| `mcp-s-cli call <tool> '<json>'` | Call tool with arguments |
|
|
19
19
|
|
|
20
|
+
## Auth Preflight
|
|
21
|
+
|
|
22
|
+
Before the first use of mcp-s-cli in a session, check auth state — this is instant (local file read, no network):
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
mcp-s-cli check-auth
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- **Exit 0**: logged in and token is valid → you may proceed
|
|
29
|
+
- **Exit 4**: not logged in or token expired → run `mcp-s-cli login` before any other use of mcp-s-cli
|
|
30
|
+
|
|
20
31
|
## Workflow
|
|
21
32
|
|
|
22
33
|
1. **Discover**: `mcp-s-cli grep <query>` → find tools by keyword; fall back to `mcp-s-cli` only when you need a full inventory
|
package/dist/SKILL.md
CHANGED
|
@@ -17,6 +17,17 @@ Access a single MCP server through the command line. MCP enables interaction wit
|
|
|
17
17
|
| `mcp-s-cli call <tool>` | Call tool (reads JSON from stdin if no args) |
|
|
18
18
|
| `mcp-s-cli call <tool> '<json>'` | Call tool with arguments |
|
|
19
19
|
|
|
20
|
+
## Auth Preflight
|
|
21
|
+
|
|
22
|
+
Before the first use of mcp-s-cli in a session, check auth state — this is instant (local file read, no network):
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
mcp-s-cli check-auth
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- **Exit 0**: logged in and token is valid → you may proceed
|
|
29
|
+
- **Exit 4**: not logged in or token expired → run `mcp-s-cli login` before any other use of mcp-s-cli
|
|
30
|
+
|
|
20
31
|
## Workflow
|
|
21
32
|
|
|
22
33
|
1. **Discover**: `mcp-s-cli grep <query>` → find tools by keyword; fall back to `mcp-s-cli` only when you need a full inventory
|
package/dist/daemon.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { appendFileSync, mkdirSync as mkdirSync6 } from "fs";
|
|
5
|
-
import { homedir as
|
|
6
|
-
import { join as
|
|
5
|
+
import { homedir as homedir8 } from "os";
|
|
6
|
+
import { join as join9 } from "path";
|
|
7
7
|
|
|
8
8
|
// src/client.ts
|
|
9
9
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
@@ -1300,7 +1300,7 @@ async function cleanupOrphanedDaemons() {
|
|
|
1300
1300
|
}
|
|
1301
1301
|
|
|
1302
1302
|
// src/version.ts
|
|
1303
|
-
var VERSION = "0.0.
|
|
1303
|
+
var VERSION = "0.0.16";
|
|
1304
1304
|
|
|
1305
1305
|
// src/client.ts
|
|
1306
1306
|
function getRetryConfig(settings) {
|
|
@@ -1906,17 +1906,90 @@ async function callCommand(options) {
|
|
|
1906
1906
|
}
|
|
1907
1907
|
}
|
|
1908
1908
|
|
|
1909
|
-
// src/commands/
|
|
1910
|
-
import { existsSync as existsSync4,
|
|
1909
|
+
// src/commands/check-auth.ts
|
|
1910
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
|
|
1911
1911
|
import { homedir as homedir2 } from "os";
|
|
1912
|
-
import {
|
|
1913
|
-
var
|
|
1914
|
-
|
|
1912
|
+
import { join as join3 } from "path";
|
|
1913
|
+
var EXPIRY_MARGIN_MS = 15 * 60 * 1e3;
|
|
1914
|
+
async function checkAuthCommand(options) {
|
|
1915
|
+
const { configPath } = options;
|
|
1916
|
+
let serverConfig;
|
|
1917
|
+
let raw;
|
|
1918
|
+
try {
|
|
1919
|
+
const loaded = await loadConfig(configPath);
|
|
1920
|
+
serverConfig = loaded.serverConfig;
|
|
1921
|
+
raw = loaded.raw;
|
|
1922
|
+
} catch (err) {
|
|
1923
|
+
console.error(`Not configured: ${err.message}`);
|
|
1924
|
+
process.exit(4 /* AUTH_ERROR */);
|
|
1925
|
+
}
|
|
1926
|
+
if (!isHttpServer(serverConfig)) {
|
|
1927
|
+
console.log("stdio server \u2014 no auth required");
|
|
1928
|
+
process.exit(0);
|
|
1929
|
+
}
|
|
1930
|
+
if (raw.token) {
|
|
1931
|
+
console.log("Authenticated (static token)");
|
|
1932
|
+
process.exit(0);
|
|
1933
|
+
}
|
|
1934
|
+
const authFilePath = join3(homedir2(), ".config", "mcp-s-cli", "auth.json");
|
|
1935
|
+
if (!existsSync4(authFilePath)) {
|
|
1936
|
+
console.error("Not logged in (no auth file found). Run: mcp-s-cli login");
|
|
1937
|
+
process.exit(4 /* AUTH_ERROR */);
|
|
1938
|
+
}
|
|
1939
|
+
let data;
|
|
1940
|
+
try {
|
|
1941
|
+
data = JSON.parse(readFileSync3(authFilePath, "utf-8"));
|
|
1942
|
+
} catch {
|
|
1943
|
+
console.error("Not logged in (auth file unreadable). Run: mcp-s-cli login");
|
|
1944
|
+
process.exit(4 /* AUTH_ERROR */);
|
|
1945
|
+
}
|
|
1946
|
+
const tokens = data.tokens ?? {};
|
|
1947
|
+
const serverOrigin = new URL(serverConfig.url).origin;
|
|
1948
|
+
const matchingKey = Object.keys(tokens).find((key) => {
|
|
1949
|
+
try {
|
|
1950
|
+
return new URL(key).origin === serverOrigin;
|
|
1951
|
+
} catch {
|
|
1952
|
+
return key === serverOrigin || key.startsWith(serverOrigin);
|
|
1953
|
+
}
|
|
1954
|
+
});
|
|
1955
|
+
if (!matchingKey || !tokens[matchingKey]?.access_token) {
|
|
1956
|
+
console.error(`Not logged in to ${serverOrigin}. Run: mcp-s-cli login`);
|
|
1957
|
+
process.exit(4 /* AUTH_ERROR */);
|
|
1958
|
+
}
|
|
1959
|
+
const token = tokens[matchingKey];
|
|
1960
|
+
const expiredAt = token.access_token_expired_at;
|
|
1961
|
+
if (expiredAt) {
|
|
1962
|
+
const remaining = expiredAt - Date.now();
|
|
1963
|
+
if (remaining <= EXPIRY_MARGIN_MS) {
|
|
1964
|
+
const reason = remaining <= 0 ? "token expired" : "token expires in < 15 min";
|
|
1965
|
+
console.error(
|
|
1966
|
+
`Not logged in to ${serverOrigin} (${reason}). Run: mcp-s-cli login`
|
|
1967
|
+
);
|
|
1968
|
+
process.exit(4 /* AUTH_ERROR */);
|
|
1969
|
+
}
|
|
1970
|
+
const hours = Math.floor(remaining / (60 * 60 * 1e3));
|
|
1971
|
+
const minutes = Math.floor(remaining % (60 * 60 * 1e3) / 6e4);
|
|
1972
|
+
const display = hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
|
|
1973
|
+
console.log(
|
|
1974
|
+
`Logged in to ${serverOrigin} (token valid, expires in ${display})`
|
|
1975
|
+
);
|
|
1976
|
+
} else {
|
|
1977
|
+
console.log(`Logged in to ${serverOrigin} (token present, no expiry info)`);
|
|
1978
|
+
}
|
|
1979
|
+
process.exit(0);
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1982
|
+
// src/commands/clear.ts
|
|
1983
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync2, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
1984
|
+
import { homedir as homedir3 } from "os";
|
|
1985
|
+
import { dirname as dirname2, join as join4 } from "path";
|
|
1986
|
+
var GLOBAL_CONFIG_PATH = join4(
|
|
1987
|
+
homedir3(),
|
|
1915
1988
|
".config",
|
|
1916
1989
|
"mcp-s-cli",
|
|
1917
1990
|
"config.json"
|
|
1918
1991
|
);
|
|
1919
|
-
var AUTH_PATH =
|
|
1992
|
+
var AUTH_PATH = join4(homedir3(), ".config", "mcp-s-cli", "auth.json");
|
|
1920
1993
|
async function clearCommand() {
|
|
1921
1994
|
mkdirSync2(dirname2(GLOBAL_CONFIG_PATH), { recursive: true });
|
|
1922
1995
|
writeFileSync2(
|
|
@@ -1933,9 +2006,9 @@ async function clearAuthCommand() {
|
|
|
1933
2006
|
`, "utf-8");
|
|
1934
2007
|
console.log(`Cleared auth data from ${AUTH_PATH}`);
|
|
1935
2008
|
}
|
|
1936
|
-
var HISTORY_PATH =
|
|
2009
|
+
var HISTORY_PATH = join4(homedir3(), ".config", "mcp-s-cli", "history.jsonl");
|
|
1937
2010
|
function clearHistoryCommand() {
|
|
1938
|
-
if (!
|
|
2011
|
+
if (!existsSync5(HISTORY_PATH)) {
|
|
1939
2012
|
console.log("No history file found.");
|
|
1940
2013
|
return;
|
|
1941
2014
|
}
|
|
@@ -1944,9 +2017,9 @@ function clearHistoryCommand() {
|
|
|
1944
2017
|
}
|
|
1945
2018
|
|
|
1946
2019
|
// src/commands/config.ts
|
|
1947
|
-
import { existsSync as
|
|
1948
|
-
import { homedir as
|
|
1949
|
-
import { dirname as dirname3, join as
|
|
2020
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
2021
|
+
import { homedir as homedir4 } from "os";
|
|
2022
|
+
import { dirname as dirname3, join as join5, resolve as resolve2 } from "path";
|
|
1950
2023
|
var TOP_LEVEL_KEYS = [
|
|
1951
2024
|
"enabled",
|
|
1952
2025
|
"org",
|
|
@@ -1969,7 +2042,7 @@ var SETTINGS_KEYS = [
|
|
|
1969
2042
|
];
|
|
1970
2043
|
var ALL_KNOWN_KEYS = [...TOP_LEVEL_KEYS, ...SETTINGS_KEYS];
|
|
1971
2044
|
function getDefaultConfigPath() {
|
|
1972
|
-
return
|
|
2045
|
+
return join5(homedir4(), ".config", "mcp-s-cli", "config.json");
|
|
1973
2046
|
}
|
|
1974
2047
|
function resolveConfigPath(explicitPath) {
|
|
1975
2048
|
if (explicitPath) return resolve2(explicitPath);
|
|
@@ -1978,8 +2051,8 @@ function resolveConfigPath(explicitPath) {
|
|
|
1978
2051
|
return getDefaultConfigPath();
|
|
1979
2052
|
}
|
|
1980
2053
|
function readConfigFile(configPath) {
|
|
1981
|
-
if (!
|
|
1982
|
-
const content =
|
|
2054
|
+
if (!existsSync6(configPath)) return {};
|
|
2055
|
+
const content = readFileSync4(configPath, "utf-8").trim();
|
|
1983
2056
|
if (!content) return {};
|
|
1984
2057
|
try {
|
|
1985
2058
|
const parsed = JSON.parse(content);
|
|
@@ -2060,7 +2133,7 @@ function configGetCommand(opts) {
|
|
|
2060
2133
|
const { key, configPath: explicitPath } = opts;
|
|
2061
2134
|
validateKey(key);
|
|
2062
2135
|
const configPath = resolveConfigPath(explicitPath);
|
|
2063
|
-
if (!
|
|
2136
|
+
if (!existsSync6(configPath)) {
|
|
2064
2137
|
console.error(
|
|
2065
2138
|
formatCliError({
|
|
2066
2139
|
code: 1 /* CLIENT_ERROR */,
|
|
@@ -2089,7 +2162,7 @@ function configGetCommand(opts) {
|
|
|
2089
2162
|
}
|
|
2090
2163
|
function configShowCommand(opts) {
|
|
2091
2164
|
const configPath = resolveConfigPath(opts.configPath);
|
|
2092
|
-
if (!
|
|
2165
|
+
if (!existsSync6(configPath)) {
|
|
2093
2166
|
console.error(
|
|
2094
2167
|
formatCliError({
|
|
2095
2168
|
code: 1 /* CLIENT_ERROR */,
|
|
@@ -2288,78 +2361,78 @@ async function infoCommand(options) {
|
|
|
2288
2361
|
}
|
|
2289
2362
|
|
|
2290
2363
|
// src/commands/init.ts
|
|
2291
|
-
import { existsSync as
|
|
2292
|
-
import { homedir as
|
|
2293
|
-
import { dirname as dirname5, join as
|
|
2364
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
2365
|
+
import { homedir as homedir6 } from "os";
|
|
2366
|
+
import { dirname as dirname5, join as join7 } from "path";
|
|
2294
2367
|
import * as readline from "readline";
|
|
2295
2368
|
|
|
2296
2369
|
// src/commands/install-skill.ts
|
|
2297
2370
|
import {
|
|
2298
|
-
existsSync as
|
|
2371
|
+
existsSync as existsSync7,
|
|
2299
2372
|
lstatSync,
|
|
2300
2373
|
mkdirSync as mkdirSync4,
|
|
2301
|
-
readFileSync as
|
|
2374
|
+
readFileSync as readFileSync5,
|
|
2302
2375
|
readlinkSync,
|
|
2303
2376
|
rmSync as rmSync2,
|
|
2304
2377
|
symlinkSync,
|
|
2305
2378
|
writeFileSync as writeFileSync4
|
|
2306
2379
|
} from "fs";
|
|
2307
|
-
import { homedir as
|
|
2308
|
-
import { dirname as dirname4, join as
|
|
2380
|
+
import { homedir as homedir5, platform } from "os";
|
|
2381
|
+
import { dirname as dirname4, join as join6, normalize, relative, resolve as resolve3, sep } from "path";
|
|
2309
2382
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2310
|
-
var home =
|
|
2383
|
+
var home = homedir5();
|
|
2311
2384
|
var AGENTS = {
|
|
2312
2385
|
cursor: {
|
|
2313
2386
|
displayName: "Cursor",
|
|
2314
|
-
globalSkillsDir:
|
|
2315
|
-
detect: () =>
|
|
2387
|
+
globalSkillsDir: join6(home, ".cursor", "skills"),
|
|
2388
|
+
detect: () => existsSync7(join6(home, ".cursor"))
|
|
2316
2389
|
},
|
|
2317
2390
|
codex: {
|
|
2318
2391
|
displayName: "Codex",
|
|
2319
|
-
globalSkillsDir:
|
|
2320
|
-
process.env.CODEX_HOME?.trim() ||
|
|
2392
|
+
globalSkillsDir: join6(
|
|
2393
|
+
process.env.CODEX_HOME?.trim() || join6(home, ".codex"),
|
|
2321
2394
|
"skills"
|
|
2322
2395
|
),
|
|
2323
|
-
detect: () =>
|
|
2396
|
+
detect: () => existsSync7(process.env.CODEX_HOME?.trim() || join6(home, ".codex")) || existsSync7("/etc/codex")
|
|
2324
2397
|
},
|
|
2325
2398
|
"claude-code": {
|
|
2326
2399
|
displayName: "Claude Code",
|
|
2327
|
-
globalSkillsDir:
|
|
2328
|
-
process.env.CLAUDE_CONFIG_DIR?.trim() ||
|
|
2400
|
+
globalSkillsDir: join6(
|
|
2401
|
+
process.env.CLAUDE_CONFIG_DIR?.trim() || join6(home, ".claude"),
|
|
2329
2402
|
"skills"
|
|
2330
2403
|
),
|
|
2331
|
-
detect: () =>
|
|
2332
|
-
process.env.CLAUDE_CONFIG_DIR?.trim() ||
|
|
2404
|
+
detect: () => existsSync7(
|
|
2405
|
+
process.env.CLAUDE_CONFIG_DIR?.trim() || join6(home, ".claude")
|
|
2333
2406
|
)
|
|
2334
2407
|
},
|
|
2335
2408
|
windsurf: {
|
|
2336
2409
|
displayName: "Windsurf",
|
|
2337
|
-
globalSkillsDir:
|
|
2338
|
-
detect: () =>
|
|
2410
|
+
globalSkillsDir: join6(home, ".codeium", "windsurf", "skills"),
|
|
2411
|
+
detect: () => existsSync7(join6(home, ".codeium", "windsurf"))
|
|
2339
2412
|
},
|
|
2340
2413
|
"github-copilot": {
|
|
2341
2414
|
displayName: "GitHub Copilot",
|
|
2342
|
-
globalSkillsDir:
|
|
2343
|
-
detect: () =>
|
|
2415
|
+
globalSkillsDir: join6(home, ".copilot", "skills"),
|
|
2416
|
+
detect: () => existsSync7(join6(home, ".copilot"))
|
|
2344
2417
|
},
|
|
2345
2418
|
cline: {
|
|
2346
2419
|
displayName: "Cline",
|
|
2347
|
-
globalSkillsDir:
|
|
2348
|
-
detect: () =>
|
|
2420
|
+
globalSkillsDir: join6(home, ".cline", "skills"),
|
|
2421
|
+
detect: () => existsSync7(join6(home, ".cline"))
|
|
2349
2422
|
},
|
|
2350
2423
|
roo: {
|
|
2351
2424
|
displayName: "Roo Code",
|
|
2352
|
-
globalSkillsDir:
|
|
2353
|
-
detect: () =>
|
|
2425
|
+
globalSkillsDir: join6(home, ".roo", "skills"),
|
|
2426
|
+
detect: () => existsSync7(join6(home, ".roo"))
|
|
2354
2427
|
},
|
|
2355
2428
|
continue: {
|
|
2356
2429
|
displayName: "Continue",
|
|
2357
|
-
globalSkillsDir:
|
|
2358
|
-
detect: () =>
|
|
2430
|
+
globalSkillsDir: join6(home, ".continue", "skills"),
|
|
2431
|
+
detect: () => existsSync7(join6(home, ".continue")) || existsSync7(join6(process.cwd(), ".continue"))
|
|
2359
2432
|
}
|
|
2360
2433
|
};
|
|
2361
2434
|
function getCanonicalSkillDir(skillName) {
|
|
2362
|
-
return
|
|
2435
|
+
return join6(home, ".agents", "skills", skillName);
|
|
2363
2436
|
}
|
|
2364
2437
|
function getCanonicalSkillPath() {
|
|
2365
2438
|
return getCanonicalSkillDir(SKILL_NAME);
|
|
@@ -2410,13 +2483,13 @@ function getSkillMdContent() {
|
|
|
2410
2483
|
const __filename = fileURLToPath2(import.meta.url);
|
|
2411
2484
|
const __dirname = dirname4(__filename);
|
|
2412
2485
|
const candidates = [
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2486
|
+
join6(__dirname, "SKILL.md"),
|
|
2487
|
+
join6(__dirname, "..", "SKILL.md"),
|
|
2488
|
+
join6(__dirname, "..", "..", "SKILL.md")
|
|
2416
2489
|
];
|
|
2417
2490
|
for (const candidate of candidates) {
|
|
2418
|
-
if (
|
|
2419
|
-
return
|
|
2491
|
+
if (existsSync7(candidate)) {
|
|
2492
|
+
return readFileSync5(candidate, "utf-8");
|
|
2420
2493
|
}
|
|
2421
2494
|
}
|
|
2422
2495
|
throw new Error(
|
|
@@ -2426,12 +2499,12 @@ function getSkillMdContent() {
|
|
|
2426
2499
|
function installSkill() {
|
|
2427
2500
|
const content = getSkillMdContent();
|
|
2428
2501
|
const canonicalDir = getCanonicalSkillDir(SKILL_NAME);
|
|
2429
|
-
if (!isPathSafe(
|
|
2502
|
+
if (!isPathSafe(join6(home, ".agents", "skills"), canonicalDir)) {
|
|
2430
2503
|
throw new Error("Invalid skill name: potential path traversal detected");
|
|
2431
2504
|
}
|
|
2432
2505
|
rmSync2(canonicalDir, { recursive: true, force: true });
|
|
2433
2506
|
mkdirSync4(canonicalDir, { recursive: true });
|
|
2434
|
-
writeFileSync4(
|
|
2507
|
+
writeFileSync4(join6(canonicalDir, "SKILL.md"), content, "utf-8");
|
|
2435
2508
|
const result = {
|
|
2436
2509
|
installed: [],
|
|
2437
2510
|
skipped: [],
|
|
@@ -2443,7 +2516,7 @@ function installSkill() {
|
|
|
2443
2516
|
result.skipped.push(agentName);
|
|
2444
2517
|
continue;
|
|
2445
2518
|
}
|
|
2446
|
-
const agentSkillDir =
|
|
2519
|
+
const agentSkillDir = join6(agent.globalSkillsDir, SKILL_NAME);
|
|
2447
2520
|
if (!isPathSafe(agent.globalSkillsDir, agentSkillDir)) {
|
|
2448
2521
|
result.failed.push({
|
|
2449
2522
|
agent: agentName,
|
|
@@ -2456,7 +2529,7 @@ function installSkill() {
|
|
|
2456
2529
|
if (!symlinkOk) {
|
|
2457
2530
|
rmSync2(agentSkillDir, { recursive: true, force: true });
|
|
2458
2531
|
mkdirSync4(agentSkillDir, { recursive: true });
|
|
2459
|
-
writeFileSync4(
|
|
2532
|
+
writeFileSync4(join6(agentSkillDir, "SKILL.md"), content, "utf-8");
|
|
2460
2533
|
}
|
|
2461
2534
|
result.installed.push(agentName);
|
|
2462
2535
|
} catch (err) {
|
|
@@ -2476,8 +2549,8 @@ function clearSkill() {
|
|
|
2476
2549
|
canonicalRemoved: false
|
|
2477
2550
|
};
|
|
2478
2551
|
for (const [agentName, agent] of Object.entries(AGENTS)) {
|
|
2479
|
-
const agentSkillDir =
|
|
2480
|
-
if (!
|
|
2552
|
+
const agentSkillDir = join6(agent.globalSkillsDir, SKILL_NAME);
|
|
2553
|
+
if (!existsSync7(agentSkillDir)) {
|
|
2481
2554
|
result.skipped.push(agentName);
|
|
2482
2555
|
continue;
|
|
2483
2556
|
}
|
|
@@ -2492,7 +2565,7 @@ function clearSkill() {
|
|
|
2492
2565
|
}
|
|
2493
2566
|
}
|
|
2494
2567
|
const canonicalDir = getCanonicalSkillDir(SKILL_NAME);
|
|
2495
|
-
if (
|
|
2568
|
+
if (existsSync7(canonicalDir)) {
|
|
2496
2569
|
try {
|
|
2497
2570
|
rmSync2(canonicalDir, { recursive: true, force: true });
|
|
2498
2571
|
result.canonicalRemoved = true;
|
|
@@ -2503,12 +2576,12 @@ function clearSkill() {
|
|
|
2503
2576
|
}
|
|
2504
2577
|
function getSkillInstallInfo() {
|
|
2505
2578
|
return Object.entries(AGENTS).filter(([, agent]) => agent.detect()).map(([agentName, agent]) => {
|
|
2506
|
-
const agentSkillDir =
|
|
2579
|
+
const agentSkillDir = join6(agent.globalSkillsDir, SKILL_NAME);
|
|
2507
2580
|
return {
|
|
2508
2581
|
agent: agentName,
|
|
2509
2582
|
displayName: agent.displayName,
|
|
2510
2583
|
path: agentSkillDir,
|
|
2511
|
-
installed:
|
|
2584
|
+
installed: existsSync7(join6(agentSkillDir, "SKILL.md"))
|
|
2512
2585
|
};
|
|
2513
2586
|
});
|
|
2514
2587
|
}
|
|
@@ -2708,16 +2781,16 @@ ${BAR} ${c(A.cyan, "\u25C6")} `
|
|
|
2708
2781
|
}
|
|
2709
2782
|
}
|
|
2710
2783
|
var p = { intro, outro, cancel, isCancel, select, text };
|
|
2711
|
-
var GLOBAL_CONFIG_PATH2 =
|
|
2712
|
-
|
|
2784
|
+
var GLOBAL_CONFIG_PATH2 = join7(
|
|
2785
|
+
homedir6(),
|
|
2713
2786
|
".config",
|
|
2714
2787
|
"mcp-s-cli",
|
|
2715
2788
|
"config.json"
|
|
2716
2789
|
);
|
|
2717
2790
|
function readExistingConfig() {
|
|
2718
2791
|
try {
|
|
2719
|
-
if (
|
|
2720
|
-
return JSON.parse(
|
|
2792
|
+
if (existsSync8(GLOBAL_CONFIG_PATH2)) {
|
|
2793
|
+
return JSON.parse(readFileSync6(GLOBAL_CONFIG_PATH2, "utf-8"));
|
|
2721
2794
|
}
|
|
2722
2795
|
} catch {
|
|
2723
2796
|
}
|
|
@@ -2846,10 +2919,10 @@ async function initInteractive() {
|
|
|
2846
2919
|
}
|
|
2847
2920
|
|
|
2848
2921
|
// src/commands/kill-daemon.ts
|
|
2849
|
-
import { existsSync as
|
|
2922
|
+
import { existsSync as existsSync9, readdirSync as readdirSync2 } from "fs";
|
|
2850
2923
|
function killDaemonCommand() {
|
|
2851
2924
|
const socketDir = getSocketDir();
|
|
2852
|
-
if (!
|
|
2925
|
+
if (!existsSync9(socketDir)) {
|
|
2853
2926
|
console.log("No daemons running.");
|
|
2854
2927
|
return;
|
|
2855
2928
|
}
|
|
@@ -2948,9 +3021,9 @@ async function logoutCommand(options) {
|
|
|
2948
3021
|
}
|
|
2949
3022
|
|
|
2950
3023
|
// src/commands/whoami.ts
|
|
2951
|
-
import { existsSync as
|
|
2952
|
-
import { homedir as
|
|
2953
|
-
import { join as
|
|
3024
|
+
import { existsSync as existsSync10, readFileSync as readFileSync7, statSync } from "fs";
|
|
3025
|
+
import { homedir as homedir7 } from "os";
|
|
3026
|
+
import { join as join8, resolve as resolve4 } from "path";
|
|
2954
3027
|
function getResolvedConfigPath(explicitPath) {
|
|
2955
3028
|
if (explicitPath) {
|
|
2956
3029
|
return resolve4(explicitPath);
|
|
@@ -2958,8 +3031,8 @@ function getResolvedConfigPath(explicitPath) {
|
|
|
2958
3031
|
if (process.env.MCP_S_CLI_CONFIG_PATH) {
|
|
2959
3032
|
return resolve4(process.env.MCP_S_CLI_CONFIG_PATH);
|
|
2960
3033
|
}
|
|
2961
|
-
const defaultPath =
|
|
2962
|
-
if (
|
|
3034
|
+
const defaultPath = join8(homedir7(), ".config", "mcp-s-cli", "config.json");
|
|
3035
|
+
if (existsSync10(defaultPath)) {
|
|
2963
3036
|
return defaultPath;
|
|
2964
3037
|
}
|
|
2965
3038
|
return null;
|
|
@@ -2987,15 +3060,15 @@ async function whoamiCommand(options) {
|
|
|
2987
3060
|
console.log(` Error loading config: ${err.message}`);
|
|
2988
3061
|
return;
|
|
2989
3062
|
}
|
|
2990
|
-
const authFilePath =
|
|
3063
|
+
const authFilePath = join8(homedir7(), ".config", "mcp-s-cli", "auth.json");
|
|
2991
3064
|
console.log("");
|
|
2992
3065
|
console.log("OAuth Tokens");
|
|
2993
3066
|
console.log(` Path: ${authFilePath}`);
|
|
2994
|
-
if (!
|
|
3067
|
+
if (!existsSync10(authFilePath)) {
|
|
2995
3068
|
console.log(" (no tokens stored)");
|
|
2996
3069
|
} else {
|
|
2997
3070
|
try {
|
|
2998
|
-
const raw2 =
|
|
3071
|
+
const raw2 = readFileSync7(authFilePath, "utf-8");
|
|
2999
3072
|
const data = JSON.parse(raw2);
|
|
3000
3073
|
const tokenEntries = Object.entries(data.tokens ?? {});
|
|
3001
3074
|
if (tokenEntries.length === 0) {
|
|
@@ -3005,9 +3078,9 @@ async function whoamiCommand(options) {
|
|
|
3005
3078
|
console.log(" (could not read auth file)");
|
|
3006
3079
|
}
|
|
3007
3080
|
}
|
|
3008
|
-
const historyPath =
|
|
3009
|
-
if (
|
|
3010
|
-
const lines =
|
|
3081
|
+
const historyPath = join8(homedir7(), ".config", "mcp-s-cli", "history.jsonl");
|
|
3082
|
+
if (existsSync10(historyPath)) {
|
|
3083
|
+
const lines = readFileSync7(historyPath, "utf-8").split("\n").filter(Boolean);
|
|
3011
3084
|
const size = statSync(historyPath).size;
|
|
3012
3085
|
const sizeStr = size >= 1024 * 1024 ? `${(size / (1024 * 1024)).toFixed(1)} MB` : size >= 1024 ? `${(size / 1024).toFixed(1)} KB` : `${size} B`;
|
|
3013
3086
|
console.log("");
|
|
@@ -3216,6 +3289,10 @@ function parseArgs2(args) {
|
|
|
3216
3289
|
result.command = "logout";
|
|
3217
3290
|
return result;
|
|
3218
3291
|
}
|
|
3292
|
+
if (firstArg === "check-auth") {
|
|
3293
|
+
result.command = "check-auth";
|
|
3294
|
+
return result;
|
|
3295
|
+
}
|
|
3219
3296
|
if (firstArg === "clear") {
|
|
3220
3297
|
result.command = "clear";
|
|
3221
3298
|
return result;
|
|
@@ -3307,6 +3384,7 @@ Usage:
|
|
|
3307
3384
|
mcp-s-cli whoami Show config location and auth state
|
|
3308
3385
|
mcp-s-cli login Log in to the configured server via OAuth
|
|
3309
3386
|
mcp-s-cli logout Log out (remove stored OAuth tokens)
|
|
3387
|
+
mcp-s-cli check-auth Check auth state offline (no network); exits 0=ok, 4=needs login
|
|
3310
3388
|
mcp-s-cli config set <key> <value> Set a value in config.json
|
|
3311
3389
|
mcp-s-cli config get <key> Get a value from config.json
|
|
3312
3390
|
mcp-s-cli config show Print full config.json
|
|
@@ -3348,6 +3426,7 @@ Examples:
|
|
|
3348
3426
|
mcp-s-cli whoami # Show config and auth state
|
|
3349
3427
|
mcp-s-cli login # Authenticate via OAuth
|
|
3350
3428
|
mcp-s-cli logout # Remove stored OAuth tokens
|
|
3429
|
+
mcp-s-cli check-auth # Check auth state offline (fast preflight)
|
|
3351
3430
|
mcp-s-cli config set settings.timeout 30 # Set request timeout to 30s
|
|
3352
3431
|
mcp-s-cli clear # Reset server config
|
|
3353
3432
|
mcp-s-cli clear-auth # Clear stored auth data
|
|
@@ -3371,10 +3450,10 @@ Config File:
|
|
|
3371
3450
|
function appendHistory(argv, history) {
|
|
3372
3451
|
if (!history) return;
|
|
3373
3452
|
try {
|
|
3374
|
-
const dir =
|
|
3453
|
+
const dir = join9(homedir8(), ".config", "mcp-s-cli");
|
|
3375
3454
|
mkdirSync6(dir, { recursive: true });
|
|
3376
3455
|
const entry = JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), args: argv });
|
|
3377
|
-
appendFileSync(
|
|
3456
|
+
appendFileSync(join9(dir, "history.jsonl"), `${entry}
|
|
3378
3457
|
`, "utf8");
|
|
3379
3458
|
} catch (err) {
|
|
3380
3459
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -3473,6 +3552,9 @@ async function main() {
|
|
|
3473
3552
|
case "logout":
|
|
3474
3553
|
await logoutCommand({ configPath: args.configPath });
|
|
3475
3554
|
break;
|
|
3555
|
+
case "check-auth":
|
|
3556
|
+
await checkAuthCommand({ configPath: args.configPath });
|
|
3557
|
+
break;
|
|
3476
3558
|
case "clear":
|
|
3477
3559
|
await clearCommand();
|
|
3478
3560
|
break;
|