natureco-cli 2.23.29 → 2.23.30
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 +94 -11
- package/bin/natureco.js +402 -4
- package/package.json +1 -1
- package/src/commands/admin-rpc.js +219 -0
- package/src/commands/agent.js +89 -0
- package/src/commands/approvals.js +53 -0
- package/src/commands/backup.js +124 -0
- package/src/commands/bonjour.js +167 -0
- package/src/commands/capability.js +64 -0
- package/src/commands/clickclack.js +130 -0
- package/src/commands/commitments.js +32 -0
- package/src/commands/completion.js +76 -0
- package/src/commands/configure.js +93 -0
- package/src/commands/crestodian.js +92 -0
- package/src/commands/daemon.js +60 -0
- package/src/commands/device-pair.js +248 -0
- package/src/commands/devices.js +110 -0
- package/src/commands/directory.js +47 -0
- package/src/commands/dns.js +58 -0
- package/src/commands/docs.js +43 -0
- package/src/commands/exec-policy.js +71 -0
- package/src/commands/gateway-server.js +1155 -24
- package/src/commands/health.js +18 -0
- package/src/commands/imessage.js +128 -14
- package/src/commands/infer.js +73 -0
- package/src/commands/irc.js +64 -15
- package/src/commands/mattermost.js +114 -12
- package/src/commands/memory-cmd.js +134 -1
- package/src/commands/message.js +9 -3
- package/src/commands/migrate.js +213 -2
- package/src/commands/node.js +98 -0
- package/src/commands/nodes.js +106 -0
- package/src/commands/oc-path.js +200 -0
- package/src/commands/onboard.js +70 -0
- package/src/commands/open-prose.js +67 -0
- package/src/commands/policy.js +176 -0
- package/src/commands/proxy.js +155 -0
- package/src/commands/qr.js +28 -0
- package/src/commands/sandbox.js +125 -0
- package/src/commands/secrets.js +118 -0
- package/src/commands/setup.js +113 -7
- package/src/commands/signal.js +447 -18
- package/src/commands/sms.js +123 -19
- package/src/commands/system.js +53 -0
- package/src/commands/terminal.js +21 -0
- package/src/commands/thread-ownership.js +157 -0
- package/src/commands/transcripts.js +72 -0
- package/src/commands/voice.js +82 -0
- package/src/commands/vydra.js +98 -0
- package/src/commands/workboard.js +207 -0
- package/src/tools/audio_understanding.js +154 -0
- package/src/tools/browser.js +112 -0
- package/src/tools/canvas.js +104 -0
- package/src/tools/document_extract.js +84 -0
- package/src/tools/duckduckgo.js +54 -0
- package/src/tools/exa_search.js +66 -0
- package/src/tools/firecrawl.js +104 -0
- package/src/tools/image_generation.js +99 -0
- package/src/tools/llm_task.js +118 -0
- package/src/tools/media_understanding.js +128 -0
- package/src/tools/music_generation.js +113 -0
- package/src/tools/parallel_search.js +77 -0
- package/src/tools/phone_control.js +80 -0
- package/src/tools/phone_control_enhanced.js +184 -0
- package/src/tools/searxng.js +61 -0
- package/src/tools/speech_to_text.js +135 -0
- package/src/tools/text_to_speech.js +105 -0
- package/src/tools/thread_ownership.js +88 -0
- package/src/tools/video_generation.js +72 -0
- package/src/tools/web_readability.js +104 -0
- package/src/utils/memory.js +200 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
|
|
6
|
+
function normalizeNcPath(uri) {
|
|
7
|
+
if (!uri) return null;
|
|
8
|
+
|
|
9
|
+
const str = uri.trim();
|
|
10
|
+
|
|
11
|
+
if (str.startsWith('nc://')) return str.slice(5);
|
|
12
|
+
if (str.startsWith('natureco://')) return str.slice(10);
|
|
13
|
+
|
|
14
|
+
return str;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function resolveNcPath(ncPath) {
|
|
18
|
+
if (!ncPath) return null;
|
|
19
|
+
|
|
20
|
+
const parts = ncPath.split('/').filter(Boolean);
|
|
21
|
+
const scope = parts[0];
|
|
22
|
+
const rest = parts.slice(1);
|
|
23
|
+
|
|
24
|
+
if (scope === 'workspace' || scope === 'w') {
|
|
25
|
+
return { type: 'workspace', path: rest.join('/') || '.', description: 'Workspace path' };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (scope === 'home' || scope === 'h') {
|
|
29
|
+
return { type: 'home', path: path.join(os.homedir(), ...rest), description: 'Home directory' };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (scope === 'config' || scope === 'c') {
|
|
33
|
+
const configDir = path.join(os.homedir(), '.natureco');
|
|
34
|
+
return { type: 'config', path: rest.length ? path.join(configDir, ...rest) : configDir, description: 'Config directory' };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (scope === 'tmp' || scope === 't') {
|
|
38
|
+
return { type: 'tmp', path: path.join(os.tmpdir(), ...rest), description: 'Temp directory' };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (scope === 'tools' || scope === 'tool') {
|
|
42
|
+
const toolsDir = path.join(__dirname, '..', 'tools');
|
|
43
|
+
return { type: 'tools', path: path.join(toolsDir, ...rest), description: 'Tools directory' };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (scope === 'commands' || scope === 'cmd') {
|
|
47
|
+
const cmdsDir = path.join(__dirname, '..', 'commands');
|
|
48
|
+
return { type: 'commands', path: path.join(cmdsDir, ...rest), description: 'Commands directory' };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (scope === 'project' || scope === 'p') {
|
|
52
|
+
return { type: 'project', path: rest.join('/') || '.', description: 'Project path (CWD)' };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (scope === 'skills' || scope === 's') {
|
|
56
|
+
const skillsDir = path.join(__dirname, '..', '..', 'skills');
|
|
57
|
+
return { type: 'skills', path: path.join(skillsDir, ...rest), description: 'Skills directory' };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (scope === 'data' || scope === 'd') {
|
|
61
|
+
const dataDir = path.join(os.homedir(), '.natureco', 'data');
|
|
62
|
+
return { type: 'data', path: rest.length ? path.join(dataDir, ...rest) : dataDir, description: 'Data directory' };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return { type: 'unknown', path: ncPath, description: 'Unresolved path' };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function ocPath(args) {
|
|
69
|
+
const [action, ...params] = args || [];
|
|
70
|
+
|
|
71
|
+
if (!action || action === 'resolve') return resolvePath(params.join('/'));
|
|
72
|
+
if (action === 'list') return listScopes();
|
|
73
|
+
if (action === 'cat') return catFile(params.join('/'));
|
|
74
|
+
if (action === 'ls') return lsPath(params.join('/'));
|
|
75
|
+
|
|
76
|
+
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
77
|
+
console.log(chalk.gray(' Kullanım: natureco oc-path [resolve|list|cat|ls] <path>\n'));
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function resolvePath(uri) {
|
|
82
|
+
const ncPath = normalizeNcPath(uri);
|
|
83
|
+
if (!ncPath) {
|
|
84
|
+
console.log(chalk.red('\n ❌ Path gerekli\n'));
|
|
85
|
+
console.log(chalk.cyan(' natureco oc-path resolve nc://config\n'));
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const resolved = resolveNcPath(ncPath);
|
|
90
|
+
if (!resolved) {
|
|
91
|
+
console.log(chalk.red(`\n ❌ Çözümlenemedi: ${ncPath}\n`));
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const exists = fs.existsSync(resolved.path);
|
|
96
|
+
|
|
97
|
+
console.log(chalk.cyan('\n 📍 nc:// Path Resolution\n'));
|
|
98
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
99
|
+
console.log(` ${chalk.white('Scope:')} ${chalk.cyan(resolved.type)}`);
|
|
100
|
+
console.log(` ${chalk.white('Path:')} ${chalk.white(resolved.path)}`);
|
|
101
|
+
console.log(` ${chalk.white('Description:')} ${chalk.gray(resolved.description)}`);
|
|
102
|
+
console.log(` ${chalk.white('Exists:')} ${exists ? chalk.green('Yes') : chalk.red('No')}`);
|
|
103
|
+
console.log();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function listScopes() {
|
|
107
|
+
console.log(chalk.cyan('\n 📍 nc:// Path Scopes\n'));
|
|
108
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
109
|
+
|
|
110
|
+
const scopes = [
|
|
111
|
+
{ alias: 'w', scope: 'workspace', desc: 'CWD altındaki dosyalar' },
|
|
112
|
+
{ alias: 'p', scope: 'project', desc: 'Proje kökü (CWD)' },
|
|
113
|
+
{ alias: 'h', scope: 'home', desc: 'Kullanıcı ana dizini (~)' },
|
|
114
|
+
{ alias: 'c', scope: 'config', desc: '~/.natureco yapılandırma' },
|
|
115
|
+
{ alias: 'd', scope: 'data', desc: '~/.natureco/data veri dizini' },
|
|
116
|
+
{ alias: 't', scope: 'tmp', desc: 'Geçici dizin' },
|
|
117
|
+
{ alias: 's', scope: 'skills', desc: 'Skill dizini' },
|
|
118
|
+
{ alias: 'tool', scope: 'tools', desc: 'Araçlar dizini' },
|
|
119
|
+
{ alias: 'cmd', scope: 'commands', desc: 'Komutlar dizini' }
|
|
120
|
+
];
|
|
121
|
+
|
|
122
|
+
for (const s of scopes) {
|
|
123
|
+
console.log(` ${chalk.cyan(`nc://${s.scope}`)} ${chalk.gray(`(${s.alias})`)} ${chalk.white('-')} ${chalk.gray(s.desc)}`);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
console.log(chalk.gray('\n Examples:'));
|
|
127
|
+
console.log(chalk.cyan(' natureco oc-path resolve nc://config'));
|
|
128
|
+
console.log(chalk.cyan(' natureco oc-path ls nc://tools'));
|
|
129
|
+
console.log(chalk.cyan(' natureco oc-path cat nc://c/settings.json'));
|
|
130
|
+
console.log();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function catFile(uri) {
|
|
134
|
+
const ncPath = normalizeNcPath(uri);
|
|
135
|
+
if (!ncPath) {
|
|
136
|
+
console.log(chalk.red('\n ❌ Path gerekli\n'));
|
|
137
|
+
process.exit(1);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const resolved = resolveNcPath(ncPath);
|
|
141
|
+
if (!resolved) {
|
|
142
|
+
console.log(chalk.red(`\n ❌ Çözümlenemedi: ${ncPath}\n`));
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (!fs.existsSync(resolved.path)) {
|
|
147
|
+
console.log(chalk.red(`\n ❌ Dosya bulunamadı: ${resolved.path}\n`));
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const stat = fs.statSync(resolved.path);
|
|
152
|
+
if (stat.isDirectory()) {
|
|
153
|
+
console.log(chalk.yellow(`\n ⚠️ Bu bir dizin, dosya değil: ${resolved.path}\n`));
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const content = fs.readFileSync(resolved.path, 'utf8');
|
|
158
|
+
console.log(chalk.gray(`\n 📄 ${resolved.path}\n`));
|
|
159
|
+
console.log(content);
|
|
160
|
+
if (!content.endsWith('\n')) console.log();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function lsPath(uri) {
|
|
164
|
+
const ncPath = normalizeNcPath(uri || 'nc://w');
|
|
165
|
+
if (!ncPath) {
|
|
166
|
+
console.log(chalk.red('\n ❌ Path gerekli\n'));
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const resolved = resolveNcPath(ncPath);
|
|
171
|
+
if (!resolved) {
|
|
172
|
+
console.log(chalk.red(`\n ❌ Çözümlenemedi: ${ncPath}\n`));
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (!fs.existsSync(resolved.path)) {
|
|
177
|
+
console.log(chalk.red(`\n ❌ Dizin bulunamadı: ${resolved.path}\n`));
|
|
178
|
+
process.exit(1);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const stat = fs.statSync(resolved.path);
|
|
182
|
+
if (!stat.isDirectory()) {
|
|
183
|
+
console.log(chalk.yellow(`\n ⚠️ Bu bir dosya: ${resolved.path}\n`));
|
|
184
|
+
process.exit(1);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const items = fs.readdirSync(resolved.path);
|
|
188
|
+
console.log(chalk.cyan(`\n 📂 ${resolved.path}\n`));
|
|
189
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
190
|
+
|
|
191
|
+
for (const item of items) {
|
|
192
|
+
const fullPath = path.join(resolved.path, item);
|
|
193
|
+
const isDir = fs.statSync(fullPath).isDirectory();
|
|
194
|
+
console.log(` ${isDir ? chalk.blue('📁') : chalk.gray('📄')} ${isDir ? chalk.cyan(item + '/') : chalk.white(item)}`);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
console.log();
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
module.exports = ocPath;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const readline = require('readline');
|
|
3
|
+
|
|
4
|
+
function rlQuestion(query) {
|
|
5
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
6
|
+
return new Promise(resolve => {
|
|
7
|
+
rl.question(query, answer => { rl.close(); resolve(answer.trim()); });
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async function onboard(args) {
|
|
12
|
+
console.log(chalk.cyan('\n 🚀 NatureCo Onboarding\n'));
|
|
13
|
+
console.log(chalk.gray(' Welcome! Let\'s get you set up step by step.\n'));
|
|
14
|
+
|
|
15
|
+
const { getConfig, saveConfig } = require('../utils/config');
|
|
16
|
+
const config = getConfig();
|
|
17
|
+
|
|
18
|
+
const start = await rlQuestion(' Begin onboarding? [Y/n]: ');
|
|
19
|
+
if (start.toLowerCase() === 'n') {
|
|
20
|
+
console.log(chalk.gray('\n Skipped. You can always run: natureco onboard\n'));
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Step 1: Provider
|
|
25
|
+
console.log(chalk.cyan('\n Step 1: AI Provider\n'));
|
|
26
|
+
const provider = await rlQuestion(` Provider (${config.provider || 'openai'}): `);
|
|
27
|
+
const model = await rlQuestion(` Model (${config.model || 'gpt-4o'}): `);
|
|
28
|
+
config.provider = provider || config.provider || 'openai';
|
|
29
|
+
config.model = model || config.model || 'gpt-4o';
|
|
30
|
+
saveConfig(config);
|
|
31
|
+
console.log(chalk.green(` ✅ ${config.provider}/${config.model}`));
|
|
32
|
+
|
|
33
|
+
// Step 2: API Key
|
|
34
|
+
if (!config.openaiApiKey && !config.anthropicApiKey) {
|
|
35
|
+
console.log(chalk.cyan('\n Step 2: API Key\n'));
|
|
36
|
+
const apiKey = await rlQuestion(` Enter your ${config.provider} API key: `);
|
|
37
|
+
if (apiKey) {
|
|
38
|
+
config[`${config.provider}ApiKey`] = apiKey;
|
|
39
|
+
saveConfig(config);
|
|
40
|
+
console.log(chalk.green(' ✅ API Key saved'));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Step 3: Gateway
|
|
45
|
+
console.log(chalk.cyan('\n Step 3: Gateway\n'));
|
|
46
|
+
const gUrl = await rlQuestion(` Gateway URL (${config.gatewayUrl || 'ws://localhost:3848'}): `);
|
|
47
|
+
const gPort = await rlQuestion(` Port (${config.gatewayPort || 3848}): `);
|
|
48
|
+
config.gatewayUrl = gUrl || config.gatewayUrl || 'ws://localhost:3848';
|
|
49
|
+
config.gatewayPort = parseInt(gPort) || config.gatewayPort || 3848;
|
|
50
|
+
saveConfig(config);
|
|
51
|
+
console.log(chalk.green(' ✅ Gateway configured'));
|
|
52
|
+
|
|
53
|
+
// Step 4: Workspace
|
|
54
|
+
console.log(chalk.cyan('\n Step 4: Workspace\n'));
|
|
55
|
+
const wsPath = await rlQuestion(` Workspace path (${process.cwd()}): `);
|
|
56
|
+
if (wsPath) {
|
|
57
|
+
config.workspacePath = wsPath;
|
|
58
|
+
saveConfig(config);
|
|
59
|
+
}
|
|
60
|
+
console.log(chalk.green(' ✅ Workspace set'));
|
|
61
|
+
|
|
62
|
+
console.log(chalk.green('\n 🎉 Onboarding complete!\n'));
|
|
63
|
+
console.log(chalk.gray(' Next steps:'));
|
|
64
|
+
console.log(chalk.cyan(' natureco chat') + chalk.gray(' Start chatting'));
|
|
65
|
+
console.log(chalk.cyan(' natureco channels add') + chalk.gray(' Connect messaging channels'));
|
|
66
|
+
console.log(chalk.cyan(' natureco doctor') + chalk.gray(' Health check'));
|
|
67
|
+
console.log(chalk.cyan(' natureco configure') + chalk.gray(' More settings\n'));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = onboard;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
|
|
5
|
+
function openProse(args) {
|
|
6
|
+
const [action, ...params] = args || [];
|
|
7
|
+
|
|
8
|
+
if (!action || action === 'list') return listBundles();
|
|
9
|
+
if (action === 'info') return showInfo();
|
|
10
|
+
|
|
11
|
+
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
12
|
+
console.log(chalk.gray(' Kullanım: natureco open-prose [list|info]\n'));
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function listBundles() {
|
|
17
|
+
const skillsDir = path.join(__dirname, '..', '..', 'skills');
|
|
18
|
+
console.log(chalk.cyan('\n 📦 OpenProse Skills Bundles\n'));
|
|
19
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
20
|
+
|
|
21
|
+
let bundles = [];
|
|
22
|
+
if (fs.existsSync(skillsDir)) {
|
|
23
|
+
try {
|
|
24
|
+
bundles = fs.readdirSync(skillsDir).filter(f => f.endsWith('.md'));
|
|
25
|
+
} catch {}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
bundles = bundles.length > 0 ? bundles : [
|
|
29
|
+
'writing-style.md',
|
|
30
|
+
'code-review.md',
|
|
31
|
+
'documentation.md',
|
|
32
|
+
'prompt-engineering.md'
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
for (const bundle of bundles) {
|
|
36
|
+
console.log(` ${chalk.cyan('●')} ${chalk.white(bundle.replace('.md', ''))}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (bundles.length === 0) {
|
|
40
|
+
console.log(chalk.gray(' Yüklü bundle bulunamadı.\n'));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
console.log(chalk.gray('\n OpenProse, NatureCo\'nun prose skills paketidir.\n'));
|
|
44
|
+
console.log(chalk.gray(' Skills yüklemek için:'));
|
|
45
|
+
console.log(chalk.cyan(' natureco skills install <name>\n'));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function showInfo() {
|
|
49
|
+
console.log(chalk.cyan('\n 📖 OpenProse\n'));
|
|
50
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
51
|
+
console.log(chalk.gray(' OpenProse — Prose skills bundle for NatureCo CLI.'));
|
|
52
|
+
console.log(chalk.gray(' Provides writing, review, documentation, and prompt'));
|
|
53
|
+
console.log(chalk.gray(' engineering skill definitions.'));
|
|
54
|
+
console.log();
|
|
55
|
+
console.log(chalk.gray(' Version: 1.0.0'));
|
|
56
|
+
console.log(chalk.gray(' ID: open-prose'));
|
|
57
|
+
console.log(chalk.gray(' Type: skills-bundle'));
|
|
58
|
+
console.log();
|
|
59
|
+
console.log(chalk.gray(' Included skills:'));
|
|
60
|
+
console.log(chalk.cyan(' writing-style') + chalk.gray(' Writing style guide'));
|
|
61
|
+
console.log(chalk.cyan(' code-review') + chalk.gray(' Code review guidelines'));
|
|
62
|
+
console.log(chalk.cyan(' documentation') + chalk.gray(' Documentation best practices'));
|
|
63
|
+
console.log(chalk.cyan(' prompt-engineering') + chalk.gray(' Prompt engineering techniques'));
|
|
64
|
+
console.log();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
module.exports = openProse;
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const { getConfig, saveConfig } = require('../utils/config');
|
|
6
|
+
|
|
7
|
+
function policy(args) {
|
|
8
|
+
const [action, ...params] = (args || []);
|
|
9
|
+
|
|
10
|
+
if (!action || action === 'check') return checkPolicy();
|
|
11
|
+
if (action === 'set') return setPolicy(params[0], params.slice(1).join(' '));
|
|
12
|
+
if (action === 'list') return listPolicies();
|
|
13
|
+
if (action === 'remove') return removePolicy(params[0]);
|
|
14
|
+
|
|
15
|
+
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
16
|
+
console.log(chalk.gray(' Kullanım: natureco policy [check|set|list|remove]\n'));
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const POLICY_CHECKS = [
|
|
21
|
+
{
|
|
22
|
+
id: 'node-version',
|
|
23
|
+
name: 'Node.js Versiyonu',
|
|
24
|
+
check: () => {
|
|
25
|
+
const v = process.version.slice(1).split('.')[0];
|
|
26
|
+
return parseInt(v) >= 18
|
|
27
|
+
? { status: 'pass', message: `Node.js ${process.version}` }
|
|
28
|
+
: { status: 'fail', message: `Node.js ${process.version} (18+ gerekli)`, fix: 'Node.js güncelleyin' };
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: 'config-exists',
|
|
33
|
+
name: 'Config Dosyası',
|
|
34
|
+
check: () => {
|
|
35
|
+
const configFile = path.join(os.homedir(), '.natureco', 'config.json');
|
|
36
|
+
if (!fs.existsSync(configFile)) {
|
|
37
|
+
return { status: 'fail', message: 'config.json bulunamadı', fix: 'natureco setup çalıştırın' };
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
JSON.parse(fs.readFileSync(configFile, 'utf-8'));
|
|
41
|
+
return { status: 'pass', message: 'Config geçerli JSON' };
|
|
42
|
+
} catch {
|
|
43
|
+
return { status: 'fail', message: 'Config bozuk JSON', fix: '~/.natureco/config.json düzeltin' };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: 'api-key',
|
|
49
|
+
name: 'API Key',
|
|
50
|
+
check: () => {
|
|
51
|
+
const config = getConfig();
|
|
52
|
+
if (config.providerApiKey || config.apiKey || process.env.GROQ_API_KEY) {
|
|
53
|
+
return { status: 'pass', message: 'API key mevcut' };
|
|
54
|
+
}
|
|
55
|
+
return { status: 'warn', message: 'API key eksik', fix: 'natureco login veya GROQ_API_KEY env' };
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'provider-url',
|
|
60
|
+
name: 'Provider URL',
|
|
61
|
+
check: () => {
|
|
62
|
+
const config = getConfig();
|
|
63
|
+
if (config.providerUrl) {
|
|
64
|
+
return { status: 'pass', message: config.providerUrl };
|
|
65
|
+
}
|
|
66
|
+
return { status: 'warn', message: 'Provider ayarlanmamış', fix: 'natureco setup' };
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: 'git-config',
|
|
71
|
+
name: 'Git Yapılandırması',
|
|
72
|
+
check: () => {
|
|
73
|
+
try {
|
|
74
|
+
const { execSync } = require('child_process');
|
|
75
|
+
const name = execSync('git config user.name', { encoding: 'utf-8', stdio: 'pipe' }).trim();
|
|
76
|
+
const email = execSync('git config user.email', { encoding: 'utf-8', stdio: 'pipe' }).trim();
|
|
77
|
+
if (name && email) return { status: 'pass', message: `${name} <${email}>` };
|
|
78
|
+
return { status: 'warn', message: 'Git user.name/email eksik', fix: 'git config --global user.name "Adınız"' };
|
|
79
|
+
} catch {
|
|
80
|
+
return { status: 'warn', message: 'Git repo değil', fix: 'git init' };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: 'disk-space',
|
|
86
|
+
name: 'Disk Alanı',
|
|
87
|
+
check: () => {
|
|
88
|
+
try {
|
|
89
|
+
const drive = path.parse(os.homedir()).root.replace(':', '');
|
|
90
|
+
const { execSync } = require('child_process');
|
|
91
|
+
const output = execSync(`powershell -Command "Get-PSDrive -Name ${drive} | Select-Object -ExpandProperty Free"`, { encoding: 'utf-8' }).trim();
|
|
92
|
+
const free = parseInt(output);
|
|
93
|
+
if (isNaN(free)) return { status: 'pass', message: 'Kontrol edilemedi' };
|
|
94
|
+
const freeGB = free / 1e9;
|
|
95
|
+
if (freeGB < 0.5) return { status: 'fail', message: `Sadece ${freeGB.toFixed(1)}GB boş`, fix: 'Disk temizliği yapın' };
|
|
96
|
+
return { status: 'pass', message: `${freeGB.toFixed(1)}GB boş alan` };
|
|
97
|
+
} catch {
|
|
98
|
+
return { status: 'pass', message: 'Kontrol edilemedi' };
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
function checkPolicy() {
|
|
105
|
+
console.log(chalk.cyan.bold('\n Workspace Uyumluluk Politikası\n'));
|
|
106
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
107
|
+
|
|
108
|
+
let passed = 0;
|
|
109
|
+
let failed = 0;
|
|
110
|
+
let warnings = 0;
|
|
111
|
+
|
|
112
|
+
for (const check of POLICY_CHECKS) {
|
|
113
|
+
const result = check.check();
|
|
114
|
+
if (result.status === 'pass') {
|
|
115
|
+
console.log(` ${chalk.green('✓')} ${check.name}: ${chalk.white(result.message)}`);
|
|
116
|
+
passed++;
|
|
117
|
+
} else if (result.status === 'fail') {
|
|
118
|
+
console.log(` ${chalk.red('✗')} ${check.name}: ${chalk.white(result.message)}`);
|
|
119
|
+
console.log(chalk.gray(` Düzeltme: ${result.fix}`));
|
|
120
|
+
failed++;
|
|
121
|
+
} else {
|
|
122
|
+
console.log(` ${chalk.yellow('⚠')} ${check.name}: ${chalk.white(result.message)}`);
|
|
123
|
+
if (result.fix) console.log(chalk.gray(` Öneri: ${result.fix}`));
|
|
124
|
+
warnings++;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
129
|
+
console.log(chalk.gray(` Geçti: ${passed} | Uyarı: ${warnings} | Hata: ${failed}\n`));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function setPolicy(key, value) {
|
|
133
|
+
if (!key) {
|
|
134
|
+
console.log(chalk.red('\n ❌ Politika adı gerekli\n'));
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const config = getConfig();
|
|
138
|
+
if (!config.policies) config.policies = {};
|
|
139
|
+
config.policies[key] = value;
|
|
140
|
+
saveConfig(config);
|
|
141
|
+
console.log(chalk.green(`\n ✓ Politika ayarlandı: ${key} = ${value}\n`));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function listPolicies() {
|
|
145
|
+
const config = getConfig();
|
|
146
|
+
const policies = config.policies || {};
|
|
147
|
+
|
|
148
|
+
if (Object.keys(policies).length === 0) {
|
|
149
|
+
console.log(chalk.gray('\n Tanımlı politika yok.\n'));
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
console.log(chalk.cyan.bold('\n Tanımlı Politikalar\n'));
|
|
154
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
155
|
+
for (const [key, value] of Object.entries(policies)) {
|
|
156
|
+
console.log(` ${chalk.white(key)}: ${chalk.cyan(value)}`);
|
|
157
|
+
}
|
|
158
|
+
console.log('');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function removePolicy(key) {
|
|
162
|
+
if (!key) {
|
|
163
|
+
console.log(chalk.red('\n ❌ Politika adı gerekli\n'));
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const config = getConfig();
|
|
167
|
+
if (config.policies?.[key]) {
|
|
168
|
+
delete config.policies[key];
|
|
169
|
+
saveConfig(config);
|
|
170
|
+
console.log(chalk.green(`\n ✓ Politika silindi: ${key}\n`));
|
|
171
|
+
} else {
|
|
172
|
+
console.log(chalk.yellow(`\n ⚠ Politika bulunamadı: ${key}\n`));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
module.exports = policy;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const http = require('http');
|
|
3
|
+
const https = require('https');
|
|
4
|
+
const { URL } = require('url');
|
|
5
|
+
|
|
6
|
+
let proxyInstance = null;
|
|
7
|
+
let captured = [];
|
|
8
|
+
let forwardUrl = null;
|
|
9
|
+
|
|
10
|
+
function proxy(args) {
|
|
11
|
+
const [action, ...params] = args || [];
|
|
12
|
+
|
|
13
|
+
if (!action || action === 'status') return statusProxy();
|
|
14
|
+
if (action === 'start') return startProxy(params);
|
|
15
|
+
if (action === 'stop') return stopProxy();
|
|
16
|
+
if (action === 'capture') return showCapture();
|
|
17
|
+
if (action === 'clear') return clearCapture();
|
|
18
|
+
|
|
19
|
+
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
20
|
+
console.log(chalk.gray(' Kullanım: natureco proxy [status|start|stop|capture|clear]\n'));
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function statusProxy() {
|
|
25
|
+
console.log(chalk.cyan('\n 🔍 Debug Proxy\n'));
|
|
26
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
27
|
+
console.log(` ${chalk.white('Status:')} ${proxyInstance ? chalk.green('Running') : chalk.red('Stopped')}`);
|
|
28
|
+
if (proxyInstance) {
|
|
29
|
+
console.log(` ${chalk.white('Port:')} ${proxyInstance.port}`);
|
|
30
|
+
console.log(` ${chalk.white('Forward:')} ${forwardUrl ? chalk.cyan(forwardUrl) : chalk.gray('(none)')}`);
|
|
31
|
+
console.log(` ${chalk.white('Captured:')} ${captured.length} request(s)`);
|
|
32
|
+
}
|
|
33
|
+
console.log(chalk.gray('\n Examples:'));
|
|
34
|
+
console.log(chalk.gray(' ') + chalk.cyan('natureco proxy start'));
|
|
35
|
+
console.log(chalk.gray(' ') + chalk.cyan('natureco proxy start 9090'));
|
|
36
|
+
console.log(chalk.gray(' ') + chalk.cyan('natureco proxy start 8080 --forward http://localhost:3000'));
|
|
37
|
+
console.log(chalk.gray(' ') + chalk.cyan('natureco proxy capture'));
|
|
38
|
+
console.log(chalk.gray(' ') + chalk.cyan('natureco proxy clear'));
|
|
39
|
+
console.log(chalk.gray(' ') + chalk.cyan('natureco proxy stop'));
|
|
40
|
+
console.log();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function startProxy(params) {
|
|
44
|
+
if (proxyInstance) {
|
|
45
|
+
console.log(chalk.yellow('\n ⚠️ Proxy already running\n'));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const port = parseInt(params[0], 10) || 8080;
|
|
50
|
+
const fwdIdx = params.indexOf('--forward');
|
|
51
|
+
if (fwdIdx !== -1 && params[fwdIdx + 1]) {
|
|
52
|
+
forwardUrl = params[fwdIdx + 1];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
captured = [];
|
|
56
|
+
|
|
57
|
+
const server = http.createServer((req, res) => {
|
|
58
|
+
const chunks = [];
|
|
59
|
+
req.on('data', chunk => chunks.push(chunk));
|
|
60
|
+
req.on('end', () => {
|
|
61
|
+
const body = Buffer.concat(chunks).toString();
|
|
62
|
+
const entry = {
|
|
63
|
+
id: captured.length + 1,
|
|
64
|
+
timestamp: new Date().toISOString(),
|
|
65
|
+
method: req.method,
|
|
66
|
+
url: req.url,
|
|
67
|
+
headers: req.headers,
|
|
68
|
+
body: body ? body.substring(0, 2000) : null
|
|
69
|
+
};
|
|
70
|
+
captured.push(entry);
|
|
71
|
+
if (captured.length > 200) captured.shift();
|
|
72
|
+
|
|
73
|
+
console.log(chalk.gray(` [${entry.id}] ${chalk.cyan(req.method)} ${req.url}`));
|
|
74
|
+
|
|
75
|
+
if (forwardUrl) {
|
|
76
|
+
try {
|
|
77
|
+
const target = new URL(req.url, forwardUrl);
|
|
78
|
+
const proxyReq = http.request({
|
|
79
|
+
hostname: target.hostname,
|
|
80
|
+
port: target.port || 80,
|
|
81
|
+
path: target.pathname + target.search,
|
|
82
|
+
method: req.method,
|
|
83
|
+
headers: { ...req.headers, host: target.host }
|
|
84
|
+
}, proxyRes => {
|
|
85
|
+
let proxyBody = '';
|
|
86
|
+
proxyRes.on('data', c => proxyBody += c);
|
|
87
|
+
proxyRes.on('end', () => {
|
|
88
|
+
res.writeHead(proxyRes.statusCode, proxyRes.headers);
|
|
89
|
+
res.end(proxyBody);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
proxyReq.on('error', () => {
|
|
93
|
+
res.writeHead(502);
|
|
94
|
+
res.end('Bad Gateway');
|
|
95
|
+
});
|
|
96
|
+
if (body) proxyReq.write(body);
|
|
97
|
+
proxyReq.end();
|
|
98
|
+
} catch {
|
|
99
|
+
res.writeHead(502);
|
|
100
|
+
res.end('Bad Gateway');
|
|
101
|
+
}
|
|
102
|
+
} else {
|
|
103
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
104
|
+
res.end(JSON.stringify({ ok: true, id: entry.id, captured: captured.length }));
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
proxyInstance = server;
|
|
110
|
+
proxyInstance.port = port;
|
|
111
|
+
server.listen(port, () => {
|
|
112
|
+
console.log(chalk.green(`\n 🔍 Debug proxy on http://localhost:${port}\n`));
|
|
113
|
+
if (forwardUrl) console.log(chalk.gray(` Forwarding to: ${forwardUrl}\n`));
|
|
114
|
+
console.log(chalk.gray(' Captured requests shown below. Press Ctrl+C to stop.\n'));
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function stopProxy() {
|
|
119
|
+
if (!proxyInstance) {
|
|
120
|
+
console.log(chalk.yellow('\n ⚠️ Proxy not running\n'));
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
proxyInstance.close(() => {
|
|
124
|
+
console.log(chalk.gray('\n 🛑 Proxy stopped\n'));
|
|
125
|
+
proxyInstance = null;
|
|
126
|
+
forwardUrl = null;
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function showCapture() {
|
|
131
|
+
if (captured.length === 0) {
|
|
132
|
+
console.log(chalk.gray('\n No captured requests.\n'));
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
console.log(chalk.cyan(`\n 📋 Captured Requests (${captured.length})\n`));
|
|
137
|
+
console.log(chalk.gray(' ' + '─'.repeat(64)));
|
|
138
|
+
|
|
139
|
+
for (const entry of captured.slice(-20)) {
|
|
140
|
+
const time = entry.timestamp.slice(11, 19);
|
|
141
|
+
console.log(` ${chalk.gray(`[${entry.id}]`)} ${chalk.cyan(entry.method)} ${chalk.white(entry.url)} ${chalk.gray(time)}`);
|
|
142
|
+
if (entry.body) {
|
|
143
|
+
const preview = entry.body.length > 200 ? entry.body.substring(0, 200) + '…' : entry.body;
|
|
144
|
+
console.log(` ${chalk.gray(preview)}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
console.log();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function clearCapture() {
|
|
151
|
+
captured = [];
|
|
152
|
+
console.log(chalk.gray('\n 🗑️ Captured requests cleared\n'));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
module.exports = proxy;
|