@safenest/cli 1.0.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/.github/workflows/ci.yml +28 -0
- package/.github/workflows/publish.yml +29 -0
- package/README.md +118 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +294 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -0
- package/src/index.ts +306 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- name: Setup Node.js
|
|
17
|
+
uses: actions/setup-node@v4
|
|
18
|
+
with:
|
|
19
|
+
node-version: 20
|
|
20
|
+
|
|
21
|
+
- name: Install dependencies
|
|
22
|
+
run: npm install
|
|
23
|
+
|
|
24
|
+
- name: Build
|
|
25
|
+
run: npm run build
|
|
26
|
+
|
|
27
|
+
- name: Check package
|
|
28
|
+
run: npm pack --dry-run
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Publish to npm
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
|
|
14
|
+
- name: Setup Node.js
|
|
15
|
+
uses: actions/setup-node@v4
|
|
16
|
+
with:
|
|
17
|
+
node-version: 20
|
|
18
|
+
registry-url: 'https://registry.npmjs.org'
|
|
19
|
+
|
|
20
|
+
- name: Install dependencies
|
|
21
|
+
run: npm install
|
|
22
|
+
|
|
23
|
+
- name: Build
|
|
24
|
+
run: npm run build
|
|
25
|
+
|
|
26
|
+
- name: Publish to npm
|
|
27
|
+
run: npm publish --access public
|
|
28
|
+
env:
|
|
29
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/README.md
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# SafeNest CLI
|
|
2
|
+
|
|
3
|
+
AI-powered child safety analysis from your terminal. Detect bullying, grooming, and unsafe content.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
### Homebrew (macOS/Linux)
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
brew install safenest/tap/safenest
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### npm
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g @safenest/cli
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Login with your API key
|
|
23
|
+
safenest login <your-api-key>
|
|
24
|
+
|
|
25
|
+
# Analyze text for safety
|
|
26
|
+
safenest analyze "Some text to check"
|
|
27
|
+
|
|
28
|
+
# Detect bullying
|
|
29
|
+
safenest detect-bullying "You're so stupid"
|
|
30
|
+
|
|
31
|
+
# Detect unsafe content
|
|
32
|
+
safenest detect-unsafe "I want to hurt myself"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Commands
|
|
36
|
+
|
|
37
|
+
### Authentication
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
safenest login <api-key> # Save your API key
|
|
41
|
+
safenest logout # Remove saved API key
|
|
42
|
+
safenest whoami # Show login status
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Safety Detection
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Quick analysis (bullying + unsafe)
|
|
49
|
+
safenest analyze "Text to analyze"
|
|
50
|
+
|
|
51
|
+
# Detect bullying/harassment
|
|
52
|
+
safenest detect-bullying "Text to check"
|
|
53
|
+
safenest bullying "Text to check" # alias
|
|
54
|
+
|
|
55
|
+
# Detect unsafe content (self-harm, violence, etc.)
|
|
56
|
+
safenest detect-unsafe "Text to check"
|
|
57
|
+
safenest unsafe "Text to check" # alias
|
|
58
|
+
|
|
59
|
+
# Detect grooming patterns in conversation
|
|
60
|
+
safenest detect-grooming -m '[{"role":"adult","content":"..."},{"role":"child","content":"..."}]'
|
|
61
|
+
safenest grooming -m '...' --age 12 # with child age
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Analysis & Guidance
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# Analyze emotions
|
|
68
|
+
safenest emotions "I'm feeling really sad today"
|
|
69
|
+
|
|
70
|
+
# Get action plan for a situation
|
|
71
|
+
safenest action-plan "Child is being bullied at school"
|
|
72
|
+
safenest plan "..." --age 12 --audience parent --severity high
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Examples
|
|
76
|
+
|
|
77
|
+
### Check a message for bullying
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
$ safenest bullying "You're worthless and nobody likes you"
|
|
81
|
+
|
|
82
|
+
⚠ BULLYING DETECTED
|
|
83
|
+
|
|
84
|
+
Severity: HIGH
|
|
85
|
+
Confidence: 92%
|
|
86
|
+
Risk Score: 85%
|
|
87
|
+
Types: verbal, exclusion
|
|
88
|
+
|
|
89
|
+
Rationale:
|
|
90
|
+
The message contains degrading language and exclusionary statements...
|
|
91
|
+
|
|
92
|
+
Action: flag_for_moderator
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Analyze emotional content
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
$ safenest emotions "I don't want to go to school anymore, everyone hates me"
|
|
99
|
+
|
|
100
|
+
Emotion Analysis
|
|
101
|
+
|
|
102
|
+
Dominant: sadness, anxiety, isolation
|
|
103
|
+
Trend: 📉 worsening
|
|
104
|
+
|
|
105
|
+
Summary:
|
|
106
|
+
The text indicates feelings of social rejection and school avoidance...
|
|
107
|
+
|
|
108
|
+
Recommended Follow-up:
|
|
109
|
+
Consider having a supportive conversation about their school experience...
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Get an API Key
|
|
113
|
+
|
|
114
|
+
Sign up at [safenest.dev](https://safenest.dev) to get your API key.
|
|
115
|
+
|
|
116
|
+
## License
|
|
117
|
+
|
|
118
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import ora from 'ora';
|
|
5
|
+
import Conf from 'conf';
|
|
6
|
+
import { SafeNestClient } from '@safenest/sdk';
|
|
7
|
+
const config = new Conf({ projectName: 'safenest' });
|
|
8
|
+
const VERSION = '1.0.0';
|
|
9
|
+
function getClient() {
|
|
10
|
+
const apiKey = config.get('apiKey');
|
|
11
|
+
if (!apiKey) {
|
|
12
|
+
console.error(chalk.red('Not logged in. Run: safenest login <api-key>'));
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
return new SafeNestClient(apiKey);
|
|
16
|
+
}
|
|
17
|
+
function formatSeverity(severity) {
|
|
18
|
+
const colors = {
|
|
19
|
+
low: chalk.yellow,
|
|
20
|
+
medium: chalk.hex('#FFA500'),
|
|
21
|
+
high: chalk.red,
|
|
22
|
+
critical: chalk.bgRed.white,
|
|
23
|
+
};
|
|
24
|
+
return (colors[severity] || chalk.white)(severity.toUpperCase());
|
|
25
|
+
}
|
|
26
|
+
function formatRisk(risk) {
|
|
27
|
+
const colors = {
|
|
28
|
+
none: chalk.green,
|
|
29
|
+
safe: chalk.green,
|
|
30
|
+
low: chalk.yellow,
|
|
31
|
+
medium: chalk.hex('#FFA500'),
|
|
32
|
+
high: chalk.red,
|
|
33
|
+
critical: chalk.bgRed.white,
|
|
34
|
+
};
|
|
35
|
+
return (colors[risk] || chalk.white)(risk.toUpperCase());
|
|
36
|
+
}
|
|
37
|
+
const program = new Command();
|
|
38
|
+
program
|
|
39
|
+
.name('safenest')
|
|
40
|
+
.description('SafeNest CLI - AI-powered child safety analysis')
|
|
41
|
+
.version(VERSION);
|
|
42
|
+
// Login command
|
|
43
|
+
program
|
|
44
|
+
.command('login <api-key>')
|
|
45
|
+
.description('Save your API key')
|
|
46
|
+
.action((apiKey) => {
|
|
47
|
+
config.set('apiKey', apiKey);
|
|
48
|
+
console.log(chalk.green('✓ API key saved successfully!'));
|
|
49
|
+
console.log(chalk.dim('Your key is stored locally at: ' + config.path));
|
|
50
|
+
});
|
|
51
|
+
// Logout command
|
|
52
|
+
program
|
|
53
|
+
.command('logout')
|
|
54
|
+
.description('Remove saved API key')
|
|
55
|
+
.action(() => {
|
|
56
|
+
config.delete('apiKey');
|
|
57
|
+
console.log(chalk.green('✓ Logged out successfully!'));
|
|
58
|
+
});
|
|
59
|
+
// Whoami command
|
|
60
|
+
program
|
|
61
|
+
.command('whoami')
|
|
62
|
+
.description('Show current login status')
|
|
63
|
+
.action(() => {
|
|
64
|
+
const apiKey = config.get('apiKey');
|
|
65
|
+
if (apiKey) {
|
|
66
|
+
const masked = apiKey.slice(0, 8) + '...' + apiKey.slice(-4);
|
|
67
|
+
console.log(chalk.green('✓ Logged in'));
|
|
68
|
+
console.log(chalk.dim('API Key: ' + masked));
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
console.log(chalk.yellow('Not logged in'));
|
|
72
|
+
console.log(chalk.dim('Run: safenest login <api-key>'));
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
// Detect bullying
|
|
76
|
+
program
|
|
77
|
+
.command('detect-bullying <text>')
|
|
78
|
+
.alias('bullying')
|
|
79
|
+
.description('Analyze text for bullying or harassment')
|
|
80
|
+
.action(async (text) => {
|
|
81
|
+
const spinner = ora('Analyzing...').start();
|
|
82
|
+
try {
|
|
83
|
+
const client = getClient();
|
|
84
|
+
const result = await client.detectBullying({ content: text });
|
|
85
|
+
spinner.stop();
|
|
86
|
+
console.log();
|
|
87
|
+
if (result.is_bullying) {
|
|
88
|
+
console.log(chalk.red.bold('⚠ BULLYING DETECTED'));
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
console.log(chalk.green.bold('✓ No bullying detected'));
|
|
92
|
+
}
|
|
93
|
+
console.log();
|
|
94
|
+
console.log(`Severity: ${formatSeverity(result.severity)}`);
|
|
95
|
+
console.log(`Confidence: ${chalk.cyan((result.confidence * 100).toFixed(0) + '%')}`);
|
|
96
|
+
console.log(`Risk Score: ${chalk.cyan((result.risk_score * 100).toFixed(0) + '%')}`);
|
|
97
|
+
if (result.bullying_type?.length > 0) {
|
|
98
|
+
console.log(`Types: ${result.bullying_type.join(', ')}`);
|
|
99
|
+
}
|
|
100
|
+
console.log();
|
|
101
|
+
console.log(chalk.dim('Rationale:'));
|
|
102
|
+
console.log(result.rationale);
|
|
103
|
+
console.log();
|
|
104
|
+
console.log(`Action: ${chalk.yellow(result.recommended_action)}`);
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
spinner.stop();
|
|
108
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
// Detect grooming
|
|
113
|
+
program
|
|
114
|
+
.command('detect-grooming')
|
|
115
|
+
.alias('grooming')
|
|
116
|
+
.description('Analyze conversation for grooming patterns')
|
|
117
|
+
.requiredOption('-m, --messages <json>', 'Messages as JSON array: [{"role":"adult","content":"..."}]')
|
|
118
|
+
.option('-a, --age <number>', 'Child age')
|
|
119
|
+
.action(async (options) => {
|
|
120
|
+
const spinner = ora('Analyzing...').start();
|
|
121
|
+
try {
|
|
122
|
+
const client = getClient();
|
|
123
|
+
const messages = JSON.parse(options.messages);
|
|
124
|
+
const result = await client.detectGrooming({
|
|
125
|
+
messages,
|
|
126
|
+
childAge: options.age ? parseInt(options.age) : undefined,
|
|
127
|
+
});
|
|
128
|
+
spinner.stop();
|
|
129
|
+
console.log();
|
|
130
|
+
if (result.grooming_risk !== 'none') {
|
|
131
|
+
console.log(chalk.red.bold('⚠ GROOMING RISK DETECTED'));
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
console.log(chalk.green.bold('✓ No grooming detected'));
|
|
135
|
+
}
|
|
136
|
+
console.log();
|
|
137
|
+
console.log(`Risk Level: ${formatRisk(result.grooming_risk)}`);
|
|
138
|
+
console.log(`Confidence: ${chalk.cyan((result.confidence * 100).toFixed(0) + '%')}`);
|
|
139
|
+
console.log(`Risk Score: ${chalk.cyan((result.risk_score * 100).toFixed(0) + '%')}`);
|
|
140
|
+
if (result.flags?.length > 0) {
|
|
141
|
+
console.log();
|
|
142
|
+
console.log(chalk.dim('Warning Flags:'));
|
|
143
|
+
result.flags.forEach((flag) => console.log(chalk.yellow(` • ${flag}`)));
|
|
144
|
+
}
|
|
145
|
+
console.log();
|
|
146
|
+
console.log(chalk.dim('Rationale:'));
|
|
147
|
+
console.log(result.rationale);
|
|
148
|
+
console.log();
|
|
149
|
+
console.log(`Action: ${chalk.yellow(result.recommended_action)}`);
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
spinner.stop();
|
|
153
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
// Detect unsafe content
|
|
158
|
+
program
|
|
159
|
+
.command('detect-unsafe <text>')
|
|
160
|
+
.alias('unsafe')
|
|
161
|
+
.description('Detect self-harm, violence, or other unsafe content')
|
|
162
|
+
.action(async (text) => {
|
|
163
|
+
const spinner = ora('Analyzing...').start();
|
|
164
|
+
try {
|
|
165
|
+
const client = getClient();
|
|
166
|
+
const result = await client.detectUnsafe({ content: text });
|
|
167
|
+
spinner.stop();
|
|
168
|
+
console.log();
|
|
169
|
+
if (result.unsafe) {
|
|
170
|
+
console.log(chalk.red.bold('⚠ UNSAFE CONTENT DETECTED'));
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
console.log(chalk.green.bold('✓ Content is safe'));
|
|
174
|
+
}
|
|
175
|
+
console.log();
|
|
176
|
+
console.log(`Severity: ${formatSeverity(result.severity)}`);
|
|
177
|
+
console.log(`Confidence: ${chalk.cyan((result.confidence * 100).toFixed(0) + '%')}`);
|
|
178
|
+
console.log(`Risk Score: ${chalk.cyan((result.risk_score * 100).toFixed(0) + '%')}`);
|
|
179
|
+
if (result.categories?.length > 0) {
|
|
180
|
+
console.log(`Categories: ${result.categories.join(', ')}`);
|
|
181
|
+
}
|
|
182
|
+
console.log();
|
|
183
|
+
console.log(chalk.dim('Rationale:'));
|
|
184
|
+
console.log(result.rationale);
|
|
185
|
+
console.log();
|
|
186
|
+
console.log(`Action: ${chalk.yellow(result.recommended_action)}`);
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
spinner.stop();
|
|
190
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
191
|
+
process.exit(1);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
// Quick analyze
|
|
195
|
+
program
|
|
196
|
+
.command('analyze <text>')
|
|
197
|
+
.description('Quick safety analysis (bullying + unsafe)')
|
|
198
|
+
.action(async (text) => {
|
|
199
|
+
const spinner = ora('Analyzing...').start();
|
|
200
|
+
try {
|
|
201
|
+
const client = getClient();
|
|
202
|
+
const result = await client.analyze({ content: text });
|
|
203
|
+
spinner.stop();
|
|
204
|
+
console.log();
|
|
205
|
+
if (result.risk_level === 'safe') {
|
|
206
|
+
console.log(chalk.green.bold('✓ Content appears safe'));
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
console.log(chalk.red.bold('⚠ SAFETY CONCERNS DETECTED'));
|
|
210
|
+
}
|
|
211
|
+
console.log();
|
|
212
|
+
console.log(`Risk Level: ${formatRisk(result.risk_level)}`);
|
|
213
|
+
console.log(`Risk Score: ${chalk.cyan((result.risk_score * 100).toFixed(0) + '%')}`);
|
|
214
|
+
console.log();
|
|
215
|
+
console.log(chalk.dim('Summary:'));
|
|
216
|
+
console.log(result.summary);
|
|
217
|
+
console.log();
|
|
218
|
+
console.log(`Action: ${chalk.yellow(result.recommended_action)}`);
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
spinner.stop();
|
|
222
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
// Analyze emotions
|
|
227
|
+
program
|
|
228
|
+
.command('emotions <text>')
|
|
229
|
+
.description('Analyze emotional content')
|
|
230
|
+
.action(async (text) => {
|
|
231
|
+
const spinner = ora('Analyzing...').start();
|
|
232
|
+
try {
|
|
233
|
+
const client = getClient();
|
|
234
|
+
const result = await client.analyzeEmotions({ content: text });
|
|
235
|
+
spinner.stop();
|
|
236
|
+
const trendEmoji = {
|
|
237
|
+
improving: '📈',
|
|
238
|
+
stable: '➡️',
|
|
239
|
+
worsening: '📉',
|
|
240
|
+
};
|
|
241
|
+
console.log();
|
|
242
|
+
console.log(chalk.bold('Emotion Analysis'));
|
|
243
|
+
console.log();
|
|
244
|
+
console.log(`Dominant: ${chalk.cyan(result.dominant_emotions.join(', '))}`);
|
|
245
|
+
console.log(`Trend: ${trendEmoji[result.trend] || ''} ${result.trend}`);
|
|
246
|
+
console.log();
|
|
247
|
+
console.log(chalk.dim('Summary:'));
|
|
248
|
+
console.log(result.summary);
|
|
249
|
+
console.log();
|
|
250
|
+
console.log(chalk.dim('Recommended Follow-up:'));
|
|
251
|
+
console.log(result.recommended_followup);
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
spinner.stop();
|
|
255
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
256
|
+
process.exit(1);
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
// Get action plan
|
|
260
|
+
program
|
|
261
|
+
.command('action-plan <situation>')
|
|
262
|
+
.alias('plan')
|
|
263
|
+
.description('Get guidance for handling a situation')
|
|
264
|
+
.option('-a, --age <number>', 'Child age')
|
|
265
|
+
.option('-t, --audience <type>', 'Audience: child, parent, educator, platform', 'parent')
|
|
266
|
+
.option('-s, --severity <level>', 'Severity: low, medium, high, critical')
|
|
267
|
+
.action(async (situation, options) => {
|
|
268
|
+
const spinner = ora('Generating action plan...').start();
|
|
269
|
+
try {
|
|
270
|
+
const client = getClient();
|
|
271
|
+
const result = await client.getActionPlan({
|
|
272
|
+
situation,
|
|
273
|
+
childAge: options.age ? parseInt(options.age) : undefined,
|
|
274
|
+
audience: options.audience,
|
|
275
|
+
severity: options.severity,
|
|
276
|
+
});
|
|
277
|
+
spinner.stop();
|
|
278
|
+
console.log();
|
|
279
|
+
console.log(chalk.bold('Action Plan'));
|
|
280
|
+
console.log(chalk.dim(`For: ${result.audience} | Tone: ${result.tone}`));
|
|
281
|
+
console.log();
|
|
282
|
+
console.log(chalk.dim('Steps:'));
|
|
283
|
+
result.steps.forEach((step, i) => {
|
|
284
|
+
console.log(chalk.cyan(` ${i + 1}. `) + step);
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
catch (error) {
|
|
288
|
+
spinner.stop();
|
|
289
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
290
|
+
process.exit(1);
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
program.parse();
|
|
294
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@safenest/cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "SafeNest CLI - AI-powered child safety analysis from your terminal",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"safenest": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"dev": "tsx src/index.ts",
|
|
12
|
+
"prepublishOnly": "npm run build"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"safenest",
|
|
16
|
+
"cli",
|
|
17
|
+
"child-safety",
|
|
18
|
+
"content-moderation",
|
|
19
|
+
"ai"
|
|
20
|
+
],
|
|
21
|
+
"author": "SafeNest <sales@safenest.dev>",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/SafeNestSDK/cli.git"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://safenest.dev",
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@safenest/sdk": "^1.0.0",
|
|
30
|
+
"chalk": "^5.3.0",
|
|
31
|
+
"commander": "^12.0.0",
|
|
32
|
+
"conf": "^12.0.0",
|
|
33
|
+
"ora": "^8.0.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/node": "^22.10.2",
|
|
37
|
+
"tsx": "^4.19.2",
|
|
38
|
+
"typescript": "^5.7.2"
|
|
39
|
+
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=18.0.0"
|
|
42
|
+
}
|
|
43
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import ora from 'ora';
|
|
6
|
+
import Conf from 'conf';
|
|
7
|
+
import { SafeNestClient } from '@safenest/sdk';
|
|
8
|
+
|
|
9
|
+
const config = new Conf({ projectName: 'safenest' });
|
|
10
|
+
const VERSION = '1.0.0';
|
|
11
|
+
|
|
12
|
+
function getClient(): SafeNestClient {
|
|
13
|
+
const apiKey = config.get('apiKey') as string;
|
|
14
|
+
if (!apiKey) {
|
|
15
|
+
console.error(chalk.red('Not logged in. Run: safenest login <api-key>'));
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
return new SafeNestClient(apiKey);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function formatSeverity(severity: string): string {
|
|
22
|
+
const colors: Record<string, (s: string) => string> = {
|
|
23
|
+
low: chalk.yellow,
|
|
24
|
+
medium: chalk.hex('#FFA500'),
|
|
25
|
+
high: chalk.red,
|
|
26
|
+
critical: chalk.bgRed.white,
|
|
27
|
+
};
|
|
28
|
+
return (colors[severity] || chalk.white)(severity.toUpperCase());
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function formatRisk(risk: string): string {
|
|
32
|
+
const colors: Record<string, (s: string) => string> = {
|
|
33
|
+
none: chalk.green,
|
|
34
|
+
safe: chalk.green,
|
|
35
|
+
low: chalk.yellow,
|
|
36
|
+
medium: chalk.hex('#FFA500'),
|
|
37
|
+
high: chalk.red,
|
|
38
|
+
critical: chalk.bgRed.white,
|
|
39
|
+
};
|
|
40
|
+
return (colors[risk] || chalk.white)(risk.toUpperCase());
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const program = new Command();
|
|
44
|
+
|
|
45
|
+
program
|
|
46
|
+
.name('safenest')
|
|
47
|
+
.description('SafeNest CLI - AI-powered child safety analysis')
|
|
48
|
+
.version(VERSION);
|
|
49
|
+
|
|
50
|
+
// Login command
|
|
51
|
+
program
|
|
52
|
+
.command('login <api-key>')
|
|
53
|
+
.description('Save your API key')
|
|
54
|
+
.action((apiKey: string) => {
|
|
55
|
+
config.set('apiKey', apiKey);
|
|
56
|
+
console.log(chalk.green('✓ API key saved successfully!'));
|
|
57
|
+
console.log(chalk.dim('Your key is stored locally at: ' + config.path));
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Logout command
|
|
61
|
+
program
|
|
62
|
+
.command('logout')
|
|
63
|
+
.description('Remove saved API key')
|
|
64
|
+
.action(() => {
|
|
65
|
+
config.delete('apiKey');
|
|
66
|
+
console.log(chalk.green('✓ Logged out successfully!'));
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Whoami command
|
|
70
|
+
program
|
|
71
|
+
.command('whoami')
|
|
72
|
+
.description('Show current login status')
|
|
73
|
+
.action(() => {
|
|
74
|
+
const apiKey = config.get('apiKey') as string;
|
|
75
|
+
if (apiKey) {
|
|
76
|
+
const masked = apiKey.slice(0, 8) + '...' + apiKey.slice(-4);
|
|
77
|
+
console.log(chalk.green('✓ Logged in'));
|
|
78
|
+
console.log(chalk.dim('API Key: ' + masked));
|
|
79
|
+
} else {
|
|
80
|
+
console.log(chalk.yellow('Not logged in'));
|
|
81
|
+
console.log(chalk.dim('Run: safenest login <api-key>'));
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Detect bullying
|
|
86
|
+
program
|
|
87
|
+
.command('detect-bullying <text>')
|
|
88
|
+
.alias('bullying')
|
|
89
|
+
.description('Analyze text for bullying or harassment')
|
|
90
|
+
.action(async (text: string) => {
|
|
91
|
+
const spinner = ora('Analyzing...').start();
|
|
92
|
+
try {
|
|
93
|
+
const client = getClient();
|
|
94
|
+
const result = await client.detectBullying({ content: text });
|
|
95
|
+
spinner.stop();
|
|
96
|
+
|
|
97
|
+
console.log();
|
|
98
|
+
if (result.is_bullying) {
|
|
99
|
+
console.log(chalk.red.bold('⚠ BULLYING DETECTED'));
|
|
100
|
+
} else {
|
|
101
|
+
console.log(chalk.green.bold('✓ No bullying detected'));
|
|
102
|
+
}
|
|
103
|
+
console.log();
|
|
104
|
+
console.log(`Severity: ${formatSeverity(result.severity)}`);
|
|
105
|
+
console.log(`Confidence: ${chalk.cyan((result.confidence * 100).toFixed(0) + '%')}`);
|
|
106
|
+
console.log(`Risk Score: ${chalk.cyan((result.risk_score * 100).toFixed(0) + '%')}`);
|
|
107
|
+
if (result.bullying_type?.length > 0) {
|
|
108
|
+
console.log(`Types: ${result.bullying_type.join(', ')}`);
|
|
109
|
+
}
|
|
110
|
+
console.log();
|
|
111
|
+
console.log(chalk.dim('Rationale:'));
|
|
112
|
+
console.log(result.rationale);
|
|
113
|
+
console.log();
|
|
114
|
+
console.log(`Action: ${chalk.yellow(result.recommended_action)}`);
|
|
115
|
+
} catch (error) {
|
|
116
|
+
spinner.stop();
|
|
117
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Detect grooming
|
|
123
|
+
program
|
|
124
|
+
.command('detect-grooming')
|
|
125
|
+
.alias('grooming')
|
|
126
|
+
.description('Analyze conversation for grooming patterns')
|
|
127
|
+
.requiredOption('-m, --messages <json>', 'Messages as JSON array: [{"role":"adult","content":"..."}]')
|
|
128
|
+
.option('-a, --age <number>', 'Child age')
|
|
129
|
+
.action(async (options) => {
|
|
130
|
+
const spinner = ora('Analyzing...').start();
|
|
131
|
+
try {
|
|
132
|
+
const client = getClient();
|
|
133
|
+
const messages = JSON.parse(options.messages);
|
|
134
|
+
const result = await client.detectGrooming({
|
|
135
|
+
messages,
|
|
136
|
+
childAge: options.age ? parseInt(options.age) : undefined,
|
|
137
|
+
});
|
|
138
|
+
spinner.stop();
|
|
139
|
+
|
|
140
|
+
console.log();
|
|
141
|
+
if (result.grooming_risk !== 'none') {
|
|
142
|
+
console.log(chalk.red.bold('⚠ GROOMING RISK DETECTED'));
|
|
143
|
+
} else {
|
|
144
|
+
console.log(chalk.green.bold('✓ No grooming detected'));
|
|
145
|
+
}
|
|
146
|
+
console.log();
|
|
147
|
+
console.log(`Risk Level: ${formatRisk(result.grooming_risk)}`);
|
|
148
|
+
console.log(`Confidence: ${chalk.cyan((result.confidence * 100).toFixed(0) + '%')}`);
|
|
149
|
+
console.log(`Risk Score: ${chalk.cyan((result.risk_score * 100).toFixed(0) + '%')}`);
|
|
150
|
+
if (result.flags?.length > 0) {
|
|
151
|
+
console.log();
|
|
152
|
+
console.log(chalk.dim('Warning Flags:'));
|
|
153
|
+
result.flags.forEach((flag: string) => console.log(chalk.yellow(` • ${flag}`)));
|
|
154
|
+
}
|
|
155
|
+
console.log();
|
|
156
|
+
console.log(chalk.dim('Rationale:'));
|
|
157
|
+
console.log(result.rationale);
|
|
158
|
+
console.log();
|
|
159
|
+
console.log(`Action: ${chalk.yellow(result.recommended_action)}`);
|
|
160
|
+
} catch (error) {
|
|
161
|
+
spinner.stop();
|
|
162
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// Detect unsafe content
|
|
168
|
+
program
|
|
169
|
+
.command('detect-unsafe <text>')
|
|
170
|
+
.alias('unsafe')
|
|
171
|
+
.description('Detect self-harm, violence, or other unsafe content')
|
|
172
|
+
.action(async (text: string) => {
|
|
173
|
+
const spinner = ora('Analyzing...').start();
|
|
174
|
+
try {
|
|
175
|
+
const client = getClient();
|
|
176
|
+
const result = await client.detectUnsafe({ content: text });
|
|
177
|
+
spinner.stop();
|
|
178
|
+
|
|
179
|
+
console.log();
|
|
180
|
+
if (result.unsafe) {
|
|
181
|
+
console.log(chalk.red.bold('⚠ UNSAFE CONTENT DETECTED'));
|
|
182
|
+
} else {
|
|
183
|
+
console.log(chalk.green.bold('✓ Content is safe'));
|
|
184
|
+
}
|
|
185
|
+
console.log();
|
|
186
|
+
console.log(`Severity: ${formatSeverity(result.severity)}`);
|
|
187
|
+
console.log(`Confidence: ${chalk.cyan((result.confidence * 100).toFixed(0) + '%')}`);
|
|
188
|
+
console.log(`Risk Score: ${chalk.cyan((result.risk_score * 100).toFixed(0) + '%')}`);
|
|
189
|
+
if (result.categories?.length > 0) {
|
|
190
|
+
console.log(`Categories: ${result.categories.join(', ')}`);
|
|
191
|
+
}
|
|
192
|
+
console.log();
|
|
193
|
+
console.log(chalk.dim('Rationale:'));
|
|
194
|
+
console.log(result.rationale);
|
|
195
|
+
console.log();
|
|
196
|
+
console.log(`Action: ${chalk.yellow(result.recommended_action)}`);
|
|
197
|
+
} catch (error) {
|
|
198
|
+
spinner.stop();
|
|
199
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
200
|
+
process.exit(1);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// Quick analyze
|
|
205
|
+
program
|
|
206
|
+
.command('analyze <text>')
|
|
207
|
+
.description('Quick safety analysis (bullying + unsafe)')
|
|
208
|
+
.action(async (text: string) => {
|
|
209
|
+
const spinner = ora('Analyzing...').start();
|
|
210
|
+
try {
|
|
211
|
+
const client = getClient();
|
|
212
|
+
const result = await client.analyze({ content: text });
|
|
213
|
+
spinner.stop();
|
|
214
|
+
|
|
215
|
+
console.log();
|
|
216
|
+
if (result.risk_level === 'safe') {
|
|
217
|
+
console.log(chalk.green.bold('✓ Content appears safe'));
|
|
218
|
+
} else {
|
|
219
|
+
console.log(chalk.red.bold('⚠ SAFETY CONCERNS DETECTED'));
|
|
220
|
+
}
|
|
221
|
+
console.log();
|
|
222
|
+
console.log(`Risk Level: ${formatRisk(result.risk_level)}`);
|
|
223
|
+
console.log(`Risk Score: ${chalk.cyan((result.risk_score * 100).toFixed(0) + '%')}`);
|
|
224
|
+
console.log();
|
|
225
|
+
console.log(chalk.dim('Summary:'));
|
|
226
|
+
console.log(result.summary);
|
|
227
|
+
console.log();
|
|
228
|
+
console.log(`Action: ${chalk.yellow(result.recommended_action)}`);
|
|
229
|
+
} catch (error) {
|
|
230
|
+
spinner.stop();
|
|
231
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
232
|
+
process.exit(1);
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// Analyze emotions
|
|
237
|
+
program
|
|
238
|
+
.command('emotions <text>')
|
|
239
|
+
.description('Analyze emotional content')
|
|
240
|
+
.action(async (text: string) => {
|
|
241
|
+
const spinner = ora('Analyzing...').start();
|
|
242
|
+
try {
|
|
243
|
+
const client = getClient();
|
|
244
|
+
const result = await client.analyzeEmotions({ content: text });
|
|
245
|
+
spinner.stop();
|
|
246
|
+
|
|
247
|
+
const trendEmoji: Record<string, string> = {
|
|
248
|
+
improving: '📈',
|
|
249
|
+
stable: '➡️',
|
|
250
|
+
worsening: '📉',
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
console.log();
|
|
254
|
+
console.log(chalk.bold('Emotion Analysis'));
|
|
255
|
+
console.log();
|
|
256
|
+
console.log(`Dominant: ${chalk.cyan(result.dominant_emotions.join(', '))}`);
|
|
257
|
+
console.log(`Trend: ${trendEmoji[result.trend] || ''} ${result.trend}`);
|
|
258
|
+
console.log();
|
|
259
|
+
console.log(chalk.dim('Summary:'));
|
|
260
|
+
console.log(result.summary);
|
|
261
|
+
console.log();
|
|
262
|
+
console.log(chalk.dim('Recommended Follow-up:'));
|
|
263
|
+
console.log(result.recommended_followup);
|
|
264
|
+
} catch (error) {
|
|
265
|
+
spinner.stop();
|
|
266
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
267
|
+
process.exit(1);
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// Get action plan
|
|
272
|
+
program
|
|
273
|
+
.command('action-plan <situation>')
|
|
274
|
+
.alias('plan')
|
|
275
|
+
.description('Get guidance for handling a situation')
|
|
276
|
+
.option('-a, --age <number>', 'Child age')
|
|
277
|
+
.option('-t, --audience <type>', 'Audience: child, parent, educator, platform', 'parent')
|
|
278
|
+
.option('-s, --severity <level>', 'Severity: low, medium, high, critical')
|
|
279
|
+
.action(async (situation: string, options) => {
|
|
280
|
+
const spinner = ora('Generating action plan...').start();
|
|
281
|
+
try {
|
|
282
|
+
const client = getClient();
|
|
283
|
+
const result = await client.getActionPlan({
|
|
284
|
+
situation,
|
|
285
|
+
childAge: options.age ? parseInt(options.age) : undefined,
|
|
286
|
+
audience: options.audience,
|
|
287
|
+
severity: options.severity,
|
|
288
|
+
});
|
|
289
|
+
spinner.stop();
|
|
290
|
+
|
|
291
|
+
console.log();
|
|
292
|
+
console.log(chalk.bold('Action Plan'));
|
|
293
|
+
console.log(chalk.dim(`For: ${result.audience} | Tone: ${result.tone}`));
|
|
294
|
+
console.log();
|
|
295
|
+
console.log(chalk.dim('Steps:'));
|
|
296
|
+
result.steps.forEach((step: string, i: number) => {
|
|
297
|
+
console.log(chalk.cyan(` ${i + 1}. `) + step);
|
|
298
|
+
});
|
|
299
|
+
} catch (error) {
|
|
300
|
+
spinner.stop();
|
|
301
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
302
|
+
process.exit(1);
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
program.parse();
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"rootDir": "./src",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"declarationMap": true,
|
|
15
|
+
"sourceMap": true
|
|
16
|
+
},
|
|
17
|
+
"include": ["src/**/*"],
|
|
18
|
+
"exclude": ["node_modules", "dist"]
|
|
19
|
+
}
|