natureco-cli 2.23.29 → 2.23.31

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.
Files changed (111) hide show
  1. package/README.md +94 -11
  2. package/bin/natureco.js +495 -94
  3. package/package.json +1 -1
  4. package/src/commands/acp.js +39 -0
  5. package/src/commands/admin-rpc.js +302 -0
  6. package/src/commands/agent.js +280 -0
  7. package/src/commands/agents.js +114 -30
  8. package/src/commands/approvals.js +214 -0
  9. package/src/commands/backup.js +124 -0
  10. package/src/commands/bonjour.js +167 -0
  11. package/src/commands/browser.js +815 -0
  12. package/src/commands/capability.js +237 -0
  13. package/src/commands/channels.js +422 -267
  14. package/src/commands/chat.js +5 -8
  15. package/src/commands/clawbot.js +19 -0
  16. package/src/commands/clickclack.js +130 -0
  17. package/src/commands/code.js +3 -2
  18. package/src/commands/commitments.js +148 -0
  19. package/src/commands/completion.js +84 -0
  20. package/src/commands/config.js +219 -30
  21. package/src/commands/configure.js +110 -0
  22. package/src/commands/crestodian.js +92 -0
  23. package/src/commands/cron.js +239 -19
  24. package/src/commands/daemon.js +90 -0
  25. package/src/commands/dashboard.js +47 -374
  26. package/src/commands/device-pair.js +248 -0
  27. package/src/commands/devices.js +137 -0
  28. package/src/commands/directory.js +179 -0
  29. package/src/commands/dns.js +196 -0
  30. package/src/commands/docs.js +136 -0
  31. package/src/commands/doctor.js +143 -492
  32. package/src/commands/exec-policy.js +80 -0
  33. package/src/commands/gateway-server.js +1155 -24
  34. package/src/commands/gateway.js +492 -249
  35. package/src/commands/health.js +148 -0
  36. package/src/commands/help.js +24 -25
  37. package/src/commands/hooks.js +141 -87
  38. package/src/commands/imessage.js +128 -14
  39. package/src/commands/infer.js +1474 -0
  40. package/src/commands/irc.js +64 -15
  41. package/src/commands/logs.js +122 -99
  42. package/src/commands/mattermost.js +114 -12
  43. package/src/commands/mcp.js +121 -309
  44. package/src/commands/memory-cmd.js +134 -1
  45. package/src/commands/memory.js +128 -0
  46. package/src/commands/message.js +720 -134
  47. package/src/commands/migrate.js +213 -2
  48. package/src/commands/models.js +39 -1
  49. package/src/commands/node.js +98 -0
  50. package/src/commands/nodes.js +362 -0
  51. package/src/commands/oc-path.js +200 -0
  52. package/src/commands/onboard.js +129 -0
  53. package/src/commands/open-prose.js +67 -0
  54. package/src/commands/pairing.js +108 -107
  55. package/src/commands/path.js +206 -0
  56. package/src/commands/plugins.js +35 -1
  57. package/src/commands/policy.js +176 -0
  58. package/src/commands/proxy.js +306 -0
  59. package/src/commands/qr.js +70 -0
  60. package/src/commands/reset.js +101 -94
  61. package/src/commands/sandbox.js +125 -0
  62. package/src/commands/secrets.js +201 -0
  63. package/src/commands/sessions.js +110 -51
  64. package/src/commands/setup.js +102 -543
  65. package/src/commands/signal.js +447 -18
  66. package/src/commands/skills.js +67 -1
  67. package/src/commands/sms.js +123 -19
  68. package/src/commands/status.js +101 -127
  69. package/src/commands/system.js +53 -0
  70. package/src/commands/tasks.js +208 -100
  71. package/src/commands/terminal.js +139 -0
  72. package/src/commands/thread-ownership.js +157 -0
  73. package/src/commands/transcripts.js +95 -0
  74. package/src/commands/tui.js +41 -0
  75. package/src/commands/uninstall.js +73 -92
  76. package/src/commands/update.js +146 -91
  77. package/src/commands/voice.js +82 -0
  78. package/src/commands/vydra.js +98 -0
  79. package/src/commands/webhooks.js +58 -66
  80. package/src/commands/wiki.js +783 -0
  81. package/src/commands/workboard.js +207 -0
  82. package/src/tools/audio_understanding.js +154 -0
  83. package/src/tools/browser.js +112 -0
  84. package/src/tools/canvas.js +104 -0
  85. package/src/tools/document_extract.js +84 -0
  86. package/src/tools/duckduckgo.js +54 -0
  87. package/src/tools/exa_search.js +66 -0
  88. package/src/tools/firecrawl.js +104 -0
  89. package/src/tools/image_generation.js +99 -0
  90. package/src/tools/llm_task.js +118 -0
  91. package/src/tools/media_understanding.js +128 -0
  92. package/src/tools/music_generation.js +113 -0
  93. package/src/tools/parallel_search.js +77 -0
  94. package/src/tools/phone_control.js +80 -0
  95. package/src/tools/phone_control_enhanced.js +184 -0
  96. package/src/tools/searxng.js +61 -0
  97. package/src/tools/speech_to_text.js +135 -0
  98. package/src/tools/text_to_speech.js +105 -0
  99. package/src/tools/thread_ownership.js +88 -0
  100. package/src/tools/video_generation.js +72 -0
  101. package/src/tools/web_readability.js +104 -0
  102. package/src/utils/agents-md.js +85 -0
  103. package/src/utils/api.js +39 -40
  104. package/src/utils/format.js +144 -0
  105. package/src/utils/headless.js +2 -1
  106. package/src/utils/memory.js +200 -0
  107. package/src/utils/parallel-tools.js +106 -0
  108. package/src/utils/sub-agent.js +148 -0
  109. package/src/utils/token-budget.js +304 -0
  110. package/src/utils/tool-runner.js +7 -5
  111. package/src/utils/web-fetch.js +107 -0
@@ -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,306 @@
1
+ const chalk = require('chalk');
2
+ const http = require('http');
3
+ const https = require('https');
4
+ const path = require('path');
5
+ const fs = require('fs');
6
+ const os = require('os');
7
+ const { URL } = require('url');
8
+
9
+ const PROXY_STATE_FILE = path.join(os.homedir(), '.natureco', 'proxy-state.json');
10
+
11
+ function getState() {
12
+ if (!fs.existsSync(PROXY_STATE_FILE)) {
13
+ return { coverage: {}, sessions: [], blobCache: {}, queryLogs: [] };
14
+ }
15
+ try {
16
+ return JSON.parse(fs.readFileSync(PROXY_STATE_FILE, 'utf8'));
17
+ } catch {
18
+ return { coverage: {}, sessions: [], blobCache: {}, queryLogs: [] };
19
+ }
20
+ }
21
+
22
+ function saveState(state) {
23
+ const dir = path.dirname(PROXY_STATE_FILE);
24
+ if (!fs.existsSync(dir)) {
25
+ fs.mkdirSync(dir, { recursive: true });
26
+ }
27
+ fs.writeFileSync(PROXY_STATE_FILE, JSON.stringify(state, null, 2), 'utf8');
28
+ }
29
+
30
+ let proxyInstance = null;
31
+ let captured = [];
32
+ let forwardUrl = null;
33
+
34
+ function proxy(args) {
35
+ const [action, ...params] = args || [];
36
+
37
+ if (!action || action === 'status') return statusProxy();
38
+ if (action === 'start') return startProxy(params);
39
+ if (action === 'stop') return stopProxy();
40
+ if (action === 'capture') return showCapture();
41
+ if (action === 'clear') return clearCapture();
42
+ if (action === 'run') return cmdRun();
43
+ if (action === 'coverage') return cmdCoverage();
44
+ if (action === 'sessions') return cmdSessions();
45
+ if (action === 'query') return cmdQuery(params[0]);
46
+ if (action === 'blob') return cmdBlob(params[0]);
47
+ if (action === 'purge') return cmdPurge();
48
+
49
+ console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
50
+ console.log(chalk.gray(' Kullanım: natureco proxy [status|start|stop|capture|clear|run|coverage|sessions|query|blob|purge]\n'));
51
+ process.exit(1);
52
+ }
53
+
54
+ function statusProxy() {
55
+ console.log(chalk.cyan('\n 🔍 Debug Proxy\n'));
56
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
57
+ console.log(` ${chalk.white('Status:')} ${proxyInstance ? chalk.green('Running') : chalk.red('Stopped')}`);
58
+ if (proxyInstance) {
59
+ console.log(` ${chalk.white('Port:')} ${proxyInstance.port}`);
60
+ console.log(` ${chalk.white('Forward:')} ${forwardUrl ? chalk.cyan(forwardUrl) : chalk.gray('(none)')}`);
61
+ console.log(` ${chalk.white('Captured:')} ${captured.length} request(s)`);
62
+ }
63
+ console.log(chalk.gray('\n Commands:'));
64
+ console.log(chalk.gray(' status Show proxy status'));
65
+ console.log(chalk.gray(' start [port] [--forward <url>] Start proxy server'));
66
+ console.log(chalk.gray(' stop Stop proxy server'));
67
+ console.log(chalk.gray(' capture Show captured requests'));
68
+ console.log(chalk.gray(' clear Clear captured requests'));
69
+ console.log(chalk.gray(' run Run proxy (stub)'));
70
+ console.log(chalk.gray(' coverage Show proxy coverage stats'));
71
+ console.log(chalk.gray(' sessions List proxy sessions'));
72
+ console.log(chalk.gray(' query <pattern> Query proxy logs'));
73
+ console.log(chalk.gray(' blob <hash> Get blob by hash'));
74
+ console.log(chalk.gray(' purge Purge proxy cache'));
75
+ console.log();
76
+ }
77
+
78
+ function startProxy(params) {
79
+ if (proxyInstance) {
80
+ console.log(chalk.yellow('\n ⚠️ Proxy already running\n'));
81
+ return;
82
+ }
83
+
84
+ const port = parseInt(params[0], 10) || 8080;
85
+ const fwdIdx = params.indexOf('--forward');
86
+ if (fwdIdx !== -1 && params[fwdIdx + 1]) {
87
+ forwardUrl = params[fwdIdx + 1];
88
+ }
89
+
90
+ captured = [];
91
+
92
+ const server = http.createServer((req, res) => {
93
+ const chunks = [];
94
+ req.on('data', chunk => chunks.push(chunk));
95
+ req.on('end', () => {
96
+ const body = Buffer.concat(chunks).toString();
97
+ const entry = {
98
+ id: captured.length + 1,
99
+ timestamp: new Date().toISOString(),
100
+ method: req.method,
101
+ url: req.url,
102
+ headers: req.headers,
103
+ body: body ? body.substring(0, 2000) : null
104
+ };
105
+ captured.push(entry);
106
+ if (captured.length > 200) captured.shift();
107
+
108
+ console.log(chalk.gray(` [${entry.id}] ${chalk.cyan(req.method)} ${req.url}`));
109
+
110
+ if (forwardUrl) {
111
+ try {
112
+ const target = new URL(req.url, forwardUrl);
113
+ const proxyReq = http.request({
114
+ hostname: target.hostname,
115
+ port: target.port || 80,
116
+ path: target.pathname + target.search,
117
+ method: req.method,
118
+ headers: { ...req.headers, host: target.host }
119
+ }, proxyRes => {
120
+ let proxyBody = '';
121
+ proxyRes.on('data', c => proxyBody += c);
122
+ proxyRes.on('end', () => {
123
+ res.writeHead(proxyRes.statusCode, proxyRes.headers);
124
+ res.end(proxyBody);
125
+ });
126
+ });
127
+ proxyReq.on('error', () => {
128
+ res.writeHead(502);
129
+ res.end('Bad Gateway');
130
+ });
131
+ if (body) proxyReq.write(body);
132
+ proxyReq.end();
133
+ } catch {
134
+ res.writeHead(502);
135
+ res.end('Bad Gateway');
136
+ }
137
+ } else {
138
+ res.writeHead(200, { 'Content-Type': 'application/json' });
139
+ res.end(JSON.stringify({ ok: true, id: entry.id, captured: captured.length }));
140
+ }
141
+ });
142
+ });
143
+
144
+ proxyInstance = server;
145
+ proxyInstance.port = port;
146
+ server.listen(port, () => {
147
+ console.log(chalk.green(`\n 🔍 Debug proxy on http://localhost:${port}\n`));
148
+ if (forwardUrl) console.log(chalk.gray(` Forwarding to: ${forwardUrl}\n`));
149
+ console.log(chalk.gray(' Captured requests shown below. Press Ctrl+C to stop.\n'));
150
+ });
151
+ }
152
+
153
+ function stopProxy() {
154
+ if (!proxyInstance) {
155
+ console.log(chalk.yellow('\n ⚠️ Proxy not running\n'));
156
+ return;
157
+ }
158
+ proxyInstance.close(() => {
159
+ console.log(chalk.gray('\n 🛑 Proxy stopped\n'));
160
+ proxyInstance = null;
161
+ forwardUrl = null;
162
+ });
163
+ }
164
+
165
+ function showCapture() {
166
+ if (captured.length === 0) {
167
+ console.log(chalk.gray('\n No captured requests.\n'));
168
+ return;
169
+ }
170
+
171
+ console.log(chalk.cyan(`\n 📋 Captured Requests (${captured.length})\n`));
172
+ console.log(chalk.gray(' ' + '─'.repeat(64)));
173
+
174
+ for (const entry of captured.slice(-20)) {
175
+ const time = entry.timestamp.slice(11, 19);
176
+ console.log(` ${chalk.gray(`[${entry.id}]`)} ${chalk.cyan(entry.method)} ${chalk.white(entry.url)} ${chalk.gray(time)}`);
177
+ if (entry.body) {
178
+ const preview = entry.body.length > 200 ? entry.body.substring(0, 200) + '…' : entry.body;
179
+ console.log(` ${chalk.gray(preview)}`);
180
+ }
181
+ }
182
+ console.log();
183
+ }
184
+
185
+ function clearCapture() {
186
+ captured = [];
187
+ console.log(chalk.gray('\n 🗑️ Captured requests cleared\n'));
188
+ }
189
+
190
+ function cmdRun() {
191
+ console.log(chalk.green('\n ▶️ Proxy run would start proxy server\n'));
192
+ console.log(chalk.gray(' (Stub — implement actual proxy server startup here)\n'));
193
+ }
194
+
195
+ function cmdCoverage() {
196
+ const state = getState();
197
+
198
+ console.log(chalk.cyan('\n 📊 Proxy Coverage Stats\n'));
199
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
200
+
201
+ const coverage = state.coverage || {};
202
+ const keys = Object.keys(coverage);
203
+
204
+ if (keys.length === 0) {
205
+ console.log(chalk.gray(' No coverage data recorded yet.\n'));
206
+ return;
207
+ }
208
+
209
+ for (const key of keys) {
210
+ const c = coverage[key];
211
+ console.log(chalk.white(` ${key}`));
212
+ console.log(chalk.gray(` Count: ${c.count || 0}`));
213
+ if (c.lastSeen) console.log(chalk.gray(` Last seen: ${c.lastSeen}`));
214
+ if (c.avgResponseTime) console.log(chalk.gray(` Avg response time: ${c.avgResponseTime}ms`));
215
+ console.log();
216
+ }
217
+ }
218
+
219
+ function cmdSessions() {
220
+ const state = getState();
221
+
222
+ console.log(chalk.cyan('\n 🔌 Proxy Sessions\n'));
223
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
224
+
225
+ const sessions = state.sessions || [];
226
+
227
+ if (sessions.length === 0) {
228
+ console.log(chalk.gray(' No sessions recorded.\n'));
229
+ return;
230
+ }
231
+
232
+ for (const s of sessions) {
233
+ console.log(chalk.white(` [${s.id}]`), chalk.gray(`${s.host || 'unknown'} — ${s.started || '?'}`));
234
+ }
235
+ console.log();
236
+ }
237
+
238
+ function cmdQuery(pattern) {
239
+ const state = getState();
240
+
241
+ if (!pattern) {
242
+ console.log(chalk.red('\n ❌ Query pattern is required.\n'));
243
+ console.log(chalk.gray(' Usage: natureco proxy query <pattern>\n'));
244
+ process.exit(1);
245
+ }
246
+
247
+ console.log(chalk.cyan(`\n 🔎 Proxy Logs matching: ${pattern}\n`));
248
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
249
+
250
+ const logs = state.queryLogs || [];
251
+ const matching = logs.filter(l =>
252
+ (l.url && l.url.includes(pattern)) ||
253
+ (l.method && l.method.includes(pattern)) ||
254
+ (l.body && l.body.includes(pattern))
255
+ );
256
+
257
+ if (matching.length === 0) {
258
+ console.log(chalk.gray(' No matching logs found.\n'));
259
+ return;
260
+ }
261
+
262
+ for (const log of matching.slice(-20)) {
263
+ console.log(` ${chalk.gray(`[${log.id}]`)} ${chalk.cyan(log.method)} ${chalk.white(log.url)}`);
264
+ }
265
+ console.log(chalk.gray(` Showing ${Math.min(matching.length, 20)} of ${matching.length} result(s)\n`));
266
+ }
267
+
268
+ function cmdBlob(hash) {
269
+ const state = getState();
270
+
271
+ if (!hash) {
272
+ console.log(chalk.red('\n ❌ Blob hash is required.\n'));
273
+ console.log(chalk.gray(' Usage: natureco proxy blob <hash>\n'));
274
+ process.exit(1);
275
+ }
276
+
277
+ const blobCache = state.blobCache || {};
278
+ const blob = blobCache[hash];
279
+
280
+ if (!blob) {
281
+ console.log(chalk.yellow(`\n ⚠️ Blob not found: ${hash}\n`));
282
+ return;
283
+ }
284
+
285
+ console.log(chalk.cyan('\n 💾 Blob\n'));
286
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
287
+ console.log(chalk.white(` Hash: ${hash}`));
288
+ console.log(chalk.white(` Size: ${blob.size || 'unknown'} bytes`));
289
+ console.log(chalk.white(` Type: ${blob.type || 'unknown'}`));
290
+ console.log(chalk.white(` Cached: ${blob.cached || 'unknown'}`));
291
+ console.log(chalk.gray(' (Stub — actual blob retrieval requires blob storage backend)\n'));
292
+ }
293
+
294
+ function cmdPurge() {
295
+ const state = getState();
296
+
297
+ state.coverage = {};
298
+ state.sessions = [];
299
+ state.blobCache = {};
300
+ state.queryLogs = [];
301
+ saveState(state);
302
+
303
+ console.log(chalk.green('\n 🧹 Proxy cache purged\n'));
304
+ }
305
+
306
+ module.exports = proxy;
@@ -0,0 +1,70 @@
1
+ const chalk = require('chalk');
2
+ const crypto = require('crypto');
3
+ const qrcode = require('qrcode-terminal');
4
+
5
+ function qr(args) {
6
+ const [action, ...params] = args || [];
7
+
8
+ if (!action || action === 'show') return showQR(params.join(' '));
9
+ if (action === 'generate') return generateQR(params.join(' '));
10
+ if (action === 'verify') return verifyCode(params[0]);
11
+
12
+ console.log(chalk.cyan('\n 📱 QR Code\n'));
13
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
14
+
15
+ const code = crypto.randomBytes(4).toString('hex').toUpperCase();
16
+ const data = JSON.stringify({ id: crypto.randomBytes(8).toString('hex'), code, timestamp: Date.now() });
17
+ const expiresAt = new Date(Date.now() + 15 * 60 * 1000);
18
+
19
+ qrcode.generate(data, { small: true }, qrCode => {
20
+ console.log(qrCode);
21
+ console.log(` ${chalk.white('Pairing Code:')} ${chalk.bold.yellow(code)}`);
22
+ console.log(` ${chalk.white('Expires:')} ${chalk.gray(expiresAt.toLocaleString())}`);
23
+ console.log();
24
+ console.log(chalk.gray(' To pair a device, run on the device:'));
25
+ console.log(chalk.cyan(' natureco device-pair verify ') + chalk.yellow(code));
26
+ console.log();
27
+ console.log(chalk.gray(' Or scan the QR code with the NatureCo mobile app.'));
28
+ console.log();
29
+ });
30
+ }
31
+
32
+ function showQR(data) {
33
+ const content = data || JSON.stringify({
34
+ id: crypto.randomBytes(8).toString('hex'),
35
+ timestamp: Date.now(),
36
+ type: 'pairing',
37
+ version: 1,
38
+ });
39
+ console.log(chalk.cyan('\n 📱 QR Code\n'));
40
+ qrcode.generate(content, { small: true }, qrCode => {
41
+ console.log(qrCode);
42
+ if (data) {
43
+ console.log(` ${chalk.gray('Data:')} ${chalk.white(data.substring(0, 80))}`);
44
+ }
45
+ console.log();
46
+ });
47
+ }
48
+
49
+ function generateQR(text) {
50
+ if (!text) {
51
+ console.log(chalk.red('\n ❌ QR için veri gerekli\n'));
52
+ console.log(chalk.gray(' Örnek: natureco qr generate "https://natureco.me/pair?code=ABC"\n'));
53
+ process.exit(1);
54
+ }
55
+ console.log(chalk.cyan('\n 📱 QR: ') + chalk.white(text) + '\n');
56
+ qrcode.generate(text, { small: false }, qrCode => {
57
+ console.log(qrCode);
58
+ console.log();
59
+ });
60
+ }
61
+
62
+ function verifyCode(code) {
63
+ if (!code) {
64
+ console.log(chalk.red('\n ❌ Kod gerekli\n'));
65
+ process.exit(1);
66
+ }
67
+ console.log(chalk.cyan('\n ✅ Pairing code verified: ') + chalk.bold.yellow(code) + '\n');
68
+ }
69
+
70
+ module.exports = qr;