@skillguard/cli 0.4.0 → 0.5.0
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/CHANGELOG.md +8 -0
- package/README.md +21 -0
- package/dist/cli.js +10 -0
- package/dist/commands/auth.d.ts +7 -0
- package/dist/commands/auth.js +103 -0
- package/dist/lib/config.d.ts +1 -0
- package/dist/lib/config.js +20 -1
- package/dist/lib/help.js +27 -0
- package/dist/lib/version.d.ts +1 -1
- package/dist/lib/version.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.0
|
|
4
|
+
|
|
5
|
+
- Added `skillguard auth` command group:
|
|
6
|
+
- `auth login` (store key),
|
|
7
|
+
- `auth status` (show effective auth source),
|
|
8
|
+
- `auth logout` (remove local config key)
|
|
9
|
+
- Added auth help/man coverage in CLI help pages
|
|
10
|
+
|
|
3
11
|
## 0.4.0
|
|
4
12
|
|
|
5
13
|
- Added `skillguard workflow` command to generate ready-to-use GitHub Actions CI gate workflow
|
package/README.md
CHANGED
|
@@ -34,6 +34,12 @@ npx @skillguard/cli help scan
|
|
|
34
34
|
npx @skillguard/cli init
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
+
Or via auth command:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx @skillguard/cli auth login
|
|
41
|
+
```
|
|
42
|
+
|
|
37
43
|
You can also provide the key via env:
|
|
38
44
|
|
|
39
45
|
```bash
|
|
@@ -72,6 +78,13 @@ npx @skillguard/cli gate ./skills
|
|
|
72
78
|
npx @skillguard/cli limits
|
|
73
79
|
```
|
|
74
80
|
|
|
81
|
+
### Auth status and logout
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
npx @skillguard/cli auth status
|
|
85
|
+
npx @skillguard/cli auth logout
|
|
86
|
+
```
|
|
87
|
+
|
|
75
88
|
### Generate and push workflow in one command
|
|
76
89
|
|
|
77
90
|
```bash
|
|
@@ -119,6 +132,12 @@ npx @skillguard/cli verify ./SKILL.md
|
|
|
119
132
|
- `--api-key <key>` (optional)
|
|
120
133
|
- `--no-color`
|
|
121
134
|
|
|
135
|
+
### auth
|
|
136
|
+
|
|
137
|
+
- `auth login [--api-key <key>] [--base-url <url>]`
|
|
138
|
+
- `auth status [--json] [--api-key <key>] [--base-url <url>]`
|
|
139
|
+
- `auth logout`
|
|
140
|
+
|
|
122
141
|
### workflow
|
|
123
142
|
|
|
124
143
|
- `--path <file>` (default: `.github/workflows/skillguard.yml`)
|
|
@@ -158,6 +177,8 @@ npx @skillguard/cli verify ./SKILL.md
|
|
|
158
177
|
- `1` threshold exceeded
|
|
159
178
|
- `workflow`:
|
|
160
179
|
- `0` success
|
|
180
|
+
- `auth`:
|
|
181
|
+
- `0` success
|
|
161
182
|
- all commands:
|
|
162
183
|
- `4` usage/input/config error
|
|
163
184
|
- `5` network/API/runtime external failure
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { parseArgs } from 'node:util';
|
|
3
|
+
import { runAuth } from './commands/auth.js';
|
|
3
4
|
import { runInit } from './commands/init.js';
|
|
4
5
|
import { runGate } from './commands/gate.js';
|
|
5
6
|
import { runLimits } from './commands/limits.js';
|
|
@@ -115,6 +116,15 @@ async function run() {
|
|
|
115
116
|
baseUrl: typeof options['base-url'] === 'string' ? options['base-url'] : undefined,
|
|
116
117
|
});
|
|
117
118
|
}
|
|
119
|
+
if (command === 'auth') {
|
|
120
|
+
const authOptions = {
|
|
121
|
+
subcommand: positionals[0],
|
|
122
|
+
json: options.json === true,
|
|
123
|
+
baseUrl: typeof options['base-url'] === 'string' ? options['base-url'] : undefined,
|
|
124
|
+
apiKey: typeof options['api-key'] === 'string' ? options['api-key'] : undefined,
|
|
125
|
+
};
|
|
126
|
+
return await runAuth(authOptions);
|
|
127
|
+
}
|
|
118
128
|
if (command === 'scan') {
|
|
119
129
|
const pathArg = positionals[0];
|
|
120
130
|
let parsedTimeout;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { clearConfig, DEFAULT_BASE_URL, getConfigPath, normalizeBaseUrl, readConfig, resolveApiKey } from '../lib/config.js';
|
|
2
|
+
import { runInit } from './init.js';
|
|
3
|
+
function toAuthSubcommand(raw) {
|
|
4
|
+
if (!raw) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
const value = raw.trim().toLowerCase();
|
|
8
|
+
if (value === 'login')
|
|
9
|
+
return 'login';
|
|
10
|
+
if (value === 'status')
|
|
11
|
+
return 'status';
|
|
12
|
+
if (value === 'logout')
|
|
13
|
+
return 'logout';
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
function renderStatusHuman(input) {
|
|
17
|
+
const lines = [
|
|
18
|
+
`Auth: ${input.authenticated ? 'configured' : 'not configured'}`,
|
|
19
|
+
`Source: ${input.source}`,
|
|
20
|
+
`Base URL: ${input.baseUrl}`,
|
|
21
|
+
`Config file: ${input.configPath}`,
|
|
22
|
+
];
|
|
23
|
+
if (!input.authenticated) {
|
|
24
|
+
lines.push('No API key found. Use "skillguard auth login" or set SKILLGUARD_API_KEY.');
|
|
25
|
+
}
|
|
26
|
+
if (input.hasEnvKey) {
|
|
27
|
+
lines.push('Env key detected: SKILLGUARD_API_KEY');
|
|
28
|
+
}
|
|
29
|
+
if (input.hasConfigKey) {
|
|
30
|
+
lines.push('Config key detected.');
|
|
31
|
+
}
|
|
32
|
+
return lines.join('\n');
|
|
33
|
+
}
|
|
34
|
+
async function runStatus(options) {
|
|
35
|
+
const configPath = getConfigPath();
|
|
36
|
+
let config = null;
|
|
37
|
+
try {
|
|
38
|
+
config = await readConfig(configPath);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
console.error(error.message);
|
|
42
|
+
return 4;
|
|
43
|
+
}
|
|
44
|
+
const resolvedApiKey = resolveApiKey({
|
|
45
|
+
apiKeyFlag: options.apiKey,
|
|
46
|
+
env: process.env,
|
|
47
|
+
config,
|
|
48
|
+
});
|
|
49
|
+
let baseUrl;
|
|
50
|
+
try {
|
|
51
|
+
baseUrl = normalizeBaseUrl(options.baseUrl || config?.apiUrl || DEFAULT_BASE_URL);
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
console.error(error.message);
|
|
55
|
+
return 4;
|
|
56
|
+
}
|
|
57
|
+
const payload = {
|
|
58
|
+
authenticated: Boolean(resolvedApiKey),
|
|
59
|
+
source: (resolvedApiKey?.source || 'none'),
|
|
60
|
+
baseUrl,
|
|
61
|
+
configPath,
|
|
62
|
+
hasConfigKey: typeof config?.apiKey === 'string' && config.apiKey.trim().length > 0,
|
|
63
|
+
hasEnvKey: typeof process.env.SKILLGUARD_API_KEY === 'string' && process.env.SKILLGUARD_API_KEY.trim().length > 0,
|
|
64
|
+
};
|
|
65
|
+
if (options.json) {
|
|
66
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
69
|
+
console.log(renderStatusHuman(payload));
|
|
70
|
+
return 0;
|
|
71
|
+
}
|
|
72
|
+
async function runLogout() {
|
|
73
|
+
const configPath = getConfigPath();
|
|
74
|
+
try {
|
|
75
|
+
const removed = await clearConfig(configPath);
|
|
76
|
+
console.log(removed ? `Logged out. Removed ${configPath}` : `No config found at ${configPath}`);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
console.error(error.message);
|
|
80
|
+
return 4;
|
|
81
|
+
}
|
|
82
|
+
if (typeof process.env.SKILLGUARD_API_KEY === 'string' && process.env.SKILLGUARD_API_KEY.trim().length > 0) {
|
|
83
|
+
console.log('Note: SKILLGUARD_API_KEY is set in environment and will still be used by this shell.');
|
|
84
|
+
}
|
|
85
|
+
return 0;
|
|
86
|
+
}
|
|
87
|
+
export async function runAuth(options) {
|
|
88
|
+
const subcommand = toAuthSubcommand(options.subcommand);
|
|
89
|
+
if (!subcommand) {
|
|
90
|
+
console.error('Auth subcommand is required: login | status | logout');
|
|
91
|
+
return 4;
|
|
92
|
+
}
|
|
93
|
+
if (subcommand === 'login') {
|
|
94
|
+
return runInit({
|
|
95
|
+
apiKey: options.apiKey,
|
|
96
|
+
baseUrl: options.baseUrl,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
if (subcommand === 'status') {
|
|
100
|
+
return runStatus(options);
|
|
101
|
+
}
|
|
102
|
+
return runLogout();
|
|
103
|
+
}
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -15,5 +15,6 @@ export interface ApiKeyResolutionInput {
|
|
|
15
15
|
export declare function getConfigPath(home?: string): string;
|
|
16
16
|
export declare function readConfig(configPath?: string): Promise<SkillguardCliConfig | null>;
|
|
17
17
|
export declare function writeConfig(config: SkillguardCliConfig, configPath?: string): Promise<void>;
|
|
18
|
+
export declare function clearConfig(configPath?: string): Promise<boolean>;
|
|
18
19
|
export declare function normalizeBaseUrl(value?: string): string;
|
|
19
20
|
export declare function resolveApiKey(input: ApiKeyResolutionInput): ResolvedApiKey | null;
|
package/dist/lib/config.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdir, readFile,
|
|
1
|
+
import { access, chmod, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
3
|
import { dirname, join } from 'node:path';
|
|
4
4
|
export const DEFAULT_BASE_URL = 'https://skillguard.ai';
|
|
@@ -39,6 +39,25 @@ export async function writeConfig(config, configPath = getConfigPath()) {
|
|
|
39
39
|
await writeFile(configPath, `${body}\n`, { encoding: 'utf8', mode: 0o600 });
|
|
40
40
|
await chmod(configPath, 0o600);
|
|
41
41
|
}
|
|
42
|
+
export async function clearConfig(configPath = getConfigPath()) {
|
|
43
|
+
try {
|
|
44
|
+
await access(configPath);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
const typed = error;
|
|
48
|
+
if (typed?.code === 'ENOENT') {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
throw new Error('Failed to clear CLI config.');
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
await rm(configPath, { force: true });
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
throw new Error('Failed to clear CLI config.');
|
|
59
|
+
}
|
|
60
|
+
}
|
|
42
61
|
export function normalizeBaseUrl(value) {
|
|
43
62
|
const raw = (value || DEFAULT_BASE_URL).trim();
|
|
44
63
|
const withoutTrailingSlash = raw.replace(/\/+$/, '');
|
package/dist/lib/help.js
CHANGED
|
@@ -8,6 +8,7 @@ function normalizeTopic(topic) {
|
|
|
8
8
|
const normalized = topic.trim().toLowerCase();
|
|
9
9
|
const aliased = COMMAND_ALIASES[normalized] || normalized;
|
|
10
10
|
if (aliased === 'help' ||
|
|
11
|
+
aliased === 'auth' ||
|
|
11
12
|
aliased === 'init' ||
|
|
12
13
|
aliased === 'scan' ||
|
|
13
14
|
aliased === 'gate' ||
|
|
@@ -25,6 +26,7 @@ Usage:
|
|
|
25
26
|
skillguard <command> [options]
|
|
26
27
|
|
|
27
28
|
Core commands:
|
|
29
|
+
auth API-key auth commands (login/status/logout)
|
|
28
30
|
init Save API key in local CLI config
|
|
29
31
|
scan Scan one file or recursively scan a directory
|
|
30
32
|
gate CI gate mode (0 pass, 1 fail)
|
|
@@ -38,6 +40,7 @@ Help commands:
|
|
|
38
40
|
|
|
39
41
|
Quick start:
|
|
40
42
|
skillguard scan SKILL.md
|
|
43
|
+
skillguard auth status
|
|
41
44
|
skillguard gate .
|
|
42
45
|
skillguard workflow
|
|
43
46
|
skillguard workflow --auto-gh-push
|
|
@@ -80,6 +83,28 @@ OPTIONS
|
|
|
80
83
|
--api-key <key> API key to persist
|
|
81
84
|
--base-url <url> API base URL (default: https://skillguard.ai)
|
|
82
85
|
|
|
86
|
+
EXIT CODES
|
|
87
|
+
0 success
|
|
88
|
+
4 usage/input/config error
|
|
89
|
+
5 external runtime error`;
|
|
90
|
+
}
|
|
91
|
+
function renderAuthHelp() {
|
|
92
|
+
return `NAME
|
|
93
|
+
skillguard auth - manage CLI authentication state
|
|
94
|
+
|
|
95
|
+
SYNOPSIS
|
|
96
|
+
skillguard auth login [--api-key <key>] [--base-url <url>]
|
|
97
|
+
skillguard auth status [--json] [--api-key <key>] [--base-url <url>]
|
|
98
|
+
skillguard auth logout
|
|
99
|
+
|
|
100
|
+
DESCRIPTION
|
|
101
|
+
login Save API key in local config (interactive if key omitted)
|
|
102
|
+
status Show effective auth source (flag/env/config/none)
|
|
103
|
+
logout Remove local CLI config key
|
|
104
|
+
|
|
105
|
+
NOTES
|
|
106
|
+
logout cannot unset SKILLGUARD_API_KEY environment variables from parent shell.
|
|
107
|
+
|
|
83
108
|
EXIT CODES
|
|
84
109
|
0 success
|
|
85
110
|
4 usage/input/config error
|
|
@@ -222,6 +247,8 @@ export function renderTopicHelp(command) {
|
|
|
222
247
|
switch (topic) {
|
|
223
248
|
case 'help':
|
|
224
249
|
return renderHelpCommandHelp();
|
|
250
|
+
case 'auth':
|
|
251
|
+
return renderAuthHelp();
|
|
225
252
|
case 'init':
|
|
226
253
|
return renderInitHelp();
|
|
227
254
|
case 'scan':
|
package/dist/lib/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const CLI_VERSION = "0.
|
|
1
|
+
export declare const CLI_VERSION = "0.5.0";
|
package/dist/lib/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const CLI_VERSION = '0.
|
|
1
|
+
export const CLI_VERSION = '0.5.0';
|