natureco-cli 2.23.28 → 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.
Files changed (96) hide show
  1. package/README.md +94 -11
  2. package/bin/natureco.js +470 -10
  3. package/package.json +10 -6
  4. package/src/commands/admin-rpc.js +219 -0
  5. package/src/commands/agent.js +89 -0
  6. package/src/commands/approvals.js +53 -0
  7. package/src/commands/backup.js +124 -0
  8. package/src/commands/bonjour.js +167 -0
  9. package/src/commands/capability.js +64 -0
  10. package/src/commands/channels.js +94 -4
  11. package/src/commands/chat.js +11 -25
  12. package/src/commands/clickclack.js +130 -0
  13. package/src/commands/commitments.js +32 -0
  14. package/src/commands/completion.js +76 -0
  15. package/src/commands/config.js +111 -68
  16. package/src/commands/configure.js +93 -0
  17. package/src/commands/crestodian.js +92 -0
  18. package/src/commands/daemon.js +60 -0
  19. package/src/commands/device-pair.js +248 -0
  20. package/src/commands/devices.js +110 -0
  21. package/src/commands/directory.js +47 -0
  22. package/src/commands/dns.js +58 -0
  23. package/src/commands/docs.js +43 -0
  24. package/src/commands/doctor.js +121 -16
  25. package/src/commands/exec-policy.js +71 -0
  26. package/src/commands/gateway-server.js +1175 -30
  27. package/src/commands/gateway.js +11 -20
  28. package/src/commands/health.js +18 -0
  29. package/src/commands/help.js +6 -0
  30. package/src/commands/imessage.js +169 -0
  31. package/src/commands/infer.js +73 -0
  32. package/src/commands/irc.js +119 -0
  33. package/src/commands/mattermost.js +164 -0
  34. package/src/commands/memory-cmd.js +134 -1
  35. package/src/commands/message.js +30 -4
  36. package/src/commands/migrate.js +213 -2
  37. package/src/commands/models.js +584 -216
  38. package/src/commands/node.js +98 -0
  39. package/src/commands/nodes.js +106 -0
  40. package/src/commands/oc-path.js +200 -0
  41. package/src/commands/onboard.js +70 -0
  42. package/src/commands/open-prose.js +67 -0
  43. package/src/commands/plugins.js +415 -172
  44. package/src/commands/policy.js +176 -0
  45. package/src/commands/proxy.js +155 -0
  46. package/src/commands/qr.js +28 -0
  47. package/src/commands/sandbox.js +125 -0
  48. package/src/commands/secrets.js +118 -0
  49. package/src/commands/security.js +149 -1
  50. package/src/commands/setup.js +114 -10
  51. package/src/commands/signal.js +495 -0
  52. package/src/commands/skills.js +20 -29
  53. package/src/commands/sms.js +168 -0
  54. package/src/commands/system.js +53 -0
  55. package/src/commands/tasks.js +328 -79
  56. package/src/commands/terminal.js +21 -0
  57. package/src/commands/thread-ownership.js +157 -0
  58. package/src/commands/transcripts.js +72 -0
  59. package/src/commands/voice.js +82 -0
  60. package/src/commands/vydra.js +98 -0
  61. package/src/commands/webhooks.js +79 -0
  62. package/src/commands/whatsapp.js +7 -21
  63. package/src/commands/workboard.js +207 -0
  64. package/src/tools/audio_understanding.js +154 -0
  65. package/src/tools/bash.js +63 -29
  66. package/src/tools/browser.js +112 -0
  67. package/src/tools/canvas.js +104 -0
  68. package/src/tools/document_extract.js +84 -0
  69. package/src/tools/duckduckgo.js +54 -0
  70. package/src/tools/exa_search.js +66 -0
  71. package/src/tools/firecrawl.js +104 -0
  72. package/src/tools/image_generation.js +99 -0
  73. package/src/tools/llm_task.js +118 -0
  74. package/src/tools/media_understanding.js +128 -0
  75. package/src/tools/music_generation.js +113 -0
  76. package/src/tools/parallel_search.js +77 -0
  77. package/src/tools/phone_control.js +80 -0
  78. package/src/tools/phone_control_enhanced.js +184 -0
  79. package/src/tools/searxng.js +61 -0
  80. package/src/tools/speech_to_text.js +135 -0
  81. package/src/tools/text_to_speech.js +105 -0
  82. package/src/tools/thread_ownership.js +88 -0
  83. package/src/tools/video_generation.js +72 -0
  84. package/src/tools/web_readability.js +104 -0
  85. package/src/utils/api.js +3 -20
  86. package/src/utils/approvals.js +297 -0
  87. package/src/utils/background.js +223 -66
  88. package/src/utils/baileys.js +21 -0
  89. package/src/utils/config.js +141 -10
  90. package/src/utils/errors.js +148 -0
  91. package/src/utils/inquirer-wrapper.js +1 -2
  92. package/src/utils/memory.js +200 -0
  93. package/src/utils/path-utils.js +13 -13
  94. package/src/utils/plugin-registry.js +238 -0
  95. package/src/utils/secrets.js +177 -0
  96. package/src/utils/skills.js +10 -23
@@ -1,172 +1,415 @@
1
- const chalk = require('chalk');
2
- const fs = require('fs');
3
- const path = require('path');
4
- const os = require('os');
5
-
6
- const PLUGINS_DIR = path.join(os.homedir(), '.natureco', 'plugins');
7
-
8
- function ensurePluginsDir() {
9
- if (!fs.existsSync(PLUGINS_DIR)) fs.mkdirSync(PLUGINS_DIR, { recursive: true });
10
- }
11
-
12
- function loadPlugins() {
13
- ensurePluginsDir();
14
- if (!fs.existsSync(PLUGINS_DIR)) return [];
15
- return fs.readdirSync(PLUGINS_DIR, { withFileTypes: true })
16
- .filter(d => d.isDirectory())
17
- .map(d => {
18
- const metaFile = path.join(PLUGINS_DIR, d.name, 'plugin.json');
19
- let meta = { name: d.name, description: '', version: '1.0.0', enabled: true };
20
- if (fs.existsSync(metaFile)) {
21
- try { meta = { ...meta, ...JSON.parse(fs.readFileSync(metaFile, 'utf-8')) }; } catch {}
22
- }
23
- // enabled durumu
24
- const disabledFile = path.join(PLUGINS_DIR, d.name, '.disabled');
25
- meta.enabled = !fs.existsSync(disabledFile);
26
- return { ...meta, slug: d.name, path: path.join(PLUGINS_DIR, d.name) };
27
- });
28
- }
29
-
30
- async function plugins(args) {
31
- const [action, ...params] = (args || []);
32
-
33
- if (!action || action === 'list') return listPlugins();
34
- if (action === 'install') return installPlugin(params[0]);
35
- if (action === 'enable') return togglePlugin(params[0], true);
36
- if (action === 'disable') return togglePlugin(params[0], false);
37
- if (action === 'info') return pluginInfo(params[0]);
38
- if (action === 'doctor') return pluginDoctor();
39
-
40
- console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
41
- console.log(chalk.gray(' Kullanım: natureco plugins [list|install|enable|disable|info|doctor]\n'));
42
- process.exit(1);
43
- }
44
-
45
- function listPlugins() {
46
- const list = loadPlugins();
47
-
48
- console.log('');
49
- console.log(chalk.gray(' ' + '─'.repeat(48)));
50
- console.log(chalk.cyan.bold('\n Plugins\n'));
51
-
52
- if (list.length === 0) {
53
- console.log(chalk.gray(' Yüklü plugin yok.\n'));
54
- console.log(chalk.gray(' Yüklemek için: ') + chalk.cyan('natureco plugins install <npm-paketi>\n'));
55
- return;
56
- }
57
-
58
- list.forEach(p => {
59
- const status = p.enabled ? chalk.green('✓ aktif') : chalk.gray('○ pasif');
60
- console.log(chalk.white(` ${p.name}`) + chalk.gray(` v${p.version} `) + status);
61
- if (p.description) console.log(chalk.gray(` ${p.description}`));
62
- console.log('');
63
- });
64
-
65
- console.log(chalk.gray(' ' + '─'.repeat(48)));
66
- console.log(chalk.gray(` Toplam: ${list.length} plugin`));
67
- console.log(chalk.gray(' Devre dışı: ') + chalk.cyan('natureco plugins disable <slug>\n'));
68
- }
69
-
70
- async function installPlugin(pkg) {
71
- if (!pkg) {
72
- console.log(chalk.red('\n ❌ Paket adı gerekli\n'));
73
- console.log(chalk.gray(' Kullanım: natureco plugins install <npm-paketi|./yerel-yol>\n'));
74
- process.exit(1);
75
- }
76
-
77
- ensurePluginsDir();
78
- console.log(chalk.gray(`\n "${pkg}" yükleniyor...\n`));
79
-
80
- // Yerel path
81
- if (pkg.startsWith('./') || pkg.startsWith('/')) {
82
- const src = path.resolve(pkg);
83
- if (!fs.existsSync(src)) {
84
- console.log(chalk.red(`\n ❌ Yol bulunamadı: ${src}\n`));
85
- process.exit(1);
86
- }
87
- const slug = path.basename(src);
88
- const dest = path.join(PLUGINS_DIR, slug);
89
- fs.cpSync(src, dest, { recursive: true });
90
- console.log(chalk.green(`\n ✓ Plugin yüklendi: ${slug}\n`));
91
- return;
92
- }
93
-
94
- // npm paketi basit indirme
95
- try {
96
- const { execSync } = require('child_process');
97
- const tmpDir = path.join(os.tmpdir(), `nc-plugin-${Date.now()}`);
98
- fs.mkdirSync(tmpDir, { recursive: true });
99
- execSync(`npm install ${pkg} --prefix ${tmpDir} --no-save`, { stdio: 'pipe' });
100
- const pkgDir = path.join(tmpDir, 'node_modules', pkg.split('/').pop());
101
- if (fs.existsSync(pkgDir)) {
102
- const slug = pkg.replace(/[@\/]/g, '-').replace(/^-/, '');
103
- const dest = path.join(PLUGINS_DIR, slug);
104
- fs.cpSync(pkgDir, dest, { recursive: true });
105
- fs.rmSync(tmpDir, { recursive: true, force: true });
106
- console.log(chalk.green(`\n ✓ Plugin yüklendi: ${slug}\n`));
107
- } else {
108
- console.log(chalk.yellow('\n Paket yüklendi ama plugin dizini bulunamadı.\n'));
109
- }
110
- } catch (e) {
111
- console.log(chalk.red(`\n ❌ Yükleme başarısız: ${e.message}\n`));
112
- process.exit(1);
113
- }
114
- }
115
-
116
- function togglePlugin(slug, enable) {
117
- if (!slug) {
118
- console.log(chalk.red(`\n ❌ Plugin adı gerekli\n`));
119
- process.exit(1);
120
- }
121
- const pluginDir = path.join(PLUGINS_DIR, slug);
122
- if (!fs.existsSync(pluginDir)) {
123
- console.log(chalk.red(`\n ❌ Plugin bulunamadı: ${slug}\n`));
124
- process.exit(1);
125
- }
126
- const disabledFile = path.join(pluginDir, '.disabled');
127
- if (enable) {
128
- if (fs.existsSync(disabledFile)) fs.unlinkSync(disabledFile);
129
- console.log(chalk.green(`\n ✓ Plugin aktif: ${slug}\n`));
130
- } else {
131
- fs.writeFileSync(disabledFile, '');
132
- console.log(chalk.gray(`\n Plugin pasif: ${slug}\n`));
133
- }
134
- }
135
-
136
- function pluginInfo(slug) {
137
- if (!slug) {
138
- console.log(chalk.red('\n Plugin adı gerekli\n'));
139
- process.exit(1);
140
- }
141
- const list = loadPlugins();
142
- const p = list.find(x => x.slug === slug);
143
- if (!p) {
144
- console.log(chalk.red(`\n ❌ Plugin bulunamadı: ${slug}\n`));
145
- process.exit(1);
146
- }
147
- console.log('');
148
- console.log(chalk.gray(' ' + '─'.repeat(48)));
149
- console.log(chalk.cyan.bold(`\n Plugin: ${p.name}\n`));
150
- console.log(chalk.gray(' Versiyon: ') + chalk.white(p.version));
151
- console.log(chalk.gray(' Durum : ') + (p.enabled ? chalk.green('aktif') : chalk.gray('pasif')));
152
- if (p.description) console.log(chalk.gray(' Açıklama: ') + chalk.white(p.description));
153
- console.log(chalk.gray(' Yol : ') + chalk.gray(p.path));
154
- console.log('');
155
- }
156
-
157
- function pluginDoctor() {
158
- const list = loadPlugins();
159
- console.log(chalk.cyan.bold('\n Plugin Tanılama\n'));
160
- if (list.length === 0) {
161
- console.log(chalk.gray(' Yüklü plugin yok.\n'));
162
- return;
163
- }
164
- list.forEach(p => {
165
- const hasIndex = fs.existsSync(path.join(p.path, 'index.js'));
166
- const icon = hasIndex ? chalk.green('✓') : chalk.yellow('⚠');
167
- console.log(` ${icon} ${p.name} ${hasIndex ? '' : chalk.yellow('(index.js bulunamadı)')}`);
168
- });
169
- console.log('');
170
- }
171
-
172
- module.exports = plugins;
1
+ const chalk = require('chalk');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const os = require('os');
5
+ const { execSync } = require('child_process');
6
+ const { PluginError, handleError } = require('../utils/errors');
7
+ const { loadRegistry, saveRegistry, scanInstalled, getPlugin, installPlugin, uninstallPlugin, updatePlugin, searchRegistry, validateManifest, PLUGINS_DIR } = require('../utils/plugin-registry');
8
+
9
+ async function plugins(args) {
10
+ const [action, ...params] = (args || []);
11
+ const opts = parseFlags(params);
12
+
13
+ try {
14
+ if (!action || action === 'list') return listPlugins(opts);
15
+ if (action === 'install') return installHandler(params[0], opts);
16
+ if (action === 'uninstall' || action === 'remove') return uninstallHandler(params[0], opts);
17
+ if (action === 'enable') return toggleHandler(params[0], true);
18
+ if (action === 'disable') return toggleHandler(params[0], false);
19
+ if (action === 'info' || action === 'inspect') return infoHandler(params[0], opts);
20
+ if (action === 'update') return updateHandler(params[0], opts);
21
+ if (action === 'search') return searchHandler(params.join(' '), opts);
22
+ if (action === 'doctor') return doctorHandler();
23
+ if (action === 'registry') return registryHandler(opts);
24
+
25
+ console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
26
+ console.log(chalk.gray(' Kullanım: natureco plugins [list|install|uninstall|enable|disable|info|update|search|doctor|registry]\n'));
27
+ process.exit(1);
28
+ } catch (err) {
29
+ handleError(err);
30
+ }
31
+ }
32
+
33
+ function parseFlags(params) {
34
+ return {
35
+ json: params.includes('--json') || params.includes('-j'),
36
+ verbose: params.includes('--verbose') || params.includes('-v'),
37
+ all: params.includes('--all') || params.includes('-a'),
38
+ enabled: params.includes('--enabled'),
39
+ force: params.includes('--force') || params.includes('-f'),
40
+ keepFiles: params.includes('--keep-files'),
41
+ dryRun: params.includes('--dry-run'),
42
+ limit: extractInt(params, '--limit', 20),
43
+ directory: extractFlag(params, '--directory'),
44
+ };
45
+ }
46
+
47
+ function extractFlag(params, name) {
48
+ const idx = params.indexOf(name);
49
+ return idx >= 0 && idx + 1 < params.length ? params[idx + 1] : null;
50
+ }
51
+
52
+ function extractInt(params, name, def) {
53
+ const v = extractFlag(params, name);
54
+ return v ? parseInt(v, 10) || def : def;
55
+ }
56
+
57
+ function listPlugins(opts) {
58
+ const allPlugins = scanInstalled();
59
+ const registry = loadRegistry();
60
+ const filtered = opts.enabled ? allPlugins.filter(p => p.enabled) : allPlugins;
61
+
62
+ if (opts.json) {
63
+ console.log(JSON.stringify({
64
+ plugins: filtered.map(p => ({
65
+ slug: p.slug, name: p.name, version: p.version, enabled: p.enabled,
66
+ source: registry.plugins.find(r => r.id === p.slug)?.source || 'unknown',
67
+ description: p.description, author: p.author, license: p.license,
68
+ installPath: p.installPath,
69
+ })),
70
+ total: filtered.length,
71
+ registry: { total: registry.plugins.length, updatedAt: registry.updatedAt },
72
+ }, null, 2));
73
+ return;
74
+ }
75
+
76
+ console.log('');
77
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
78
+ console.log(chalk.cyan.bold('\n Plugins\n'));
79
+
80
+ if (filtered.length === 0) {
81
+ console.log(chalk.gray(' Yüklü plugin yok.\n'));
82
+ console.log(chalk.gray(' Yüklemek için: ') + chalk.cyan('natureco plugins install <paket-adı|./path|git:url>'));
83
+ console.log(chalk.gray(' Aramak için: ') + chalk.cyan('natureco plugins search <query>\n'));
84
+ return;
85
+ }
86
+
87
+ filtered.forEach(p => {
88
+ const status = p.enabled ? chalk.green('✓ aktif') : chalk.gray('○ pasif');
89
+ const source = registry.plugins.find(r => r.id === p.slug)?.source || 'local';
90
+ const sourceIcon = source === 'npm' ? '📦' : source === 'git' ? '🌐' : source === 'local' ? '📁' : '❓';
91
+ console.log(` ${sourceIcon} ${chalk.white(p.name)} ${chalk.gray(`v${p.version}`)} ${status}`);
92
+ if (p.description) console.log(chalk.gray(` ${p.description}`));
93
+ if (opts.verbose) {
94
+ console.log(chalk.gray(` Kaynak: ${source} | Yol: ${p.installPath}`));
95
+ if (p.author) console.log(chalk.gray(` Yazar: ${p.author}`));
96
+ }
97
+ console.log('');
98
+ });
99
+
100
+ console.log(chalk.gray(' ' + ''.repeat(48)));
101
+ console.log(chalk.gray(` Toplam: ${filtered.length} plugin (${allPlugins.length - filtered.length} pasif)`));
102
+ console.log(chalk.gray(' Detay: ') + chalk.cyan('natureco plugins list --verbose'));
103
+ console.log(chalk.gray(' JSON: ') + chalk.cyan('natureco plugins list --json\n'));
104
+ }
105
+
106
+ async function installHandler(spec, opts) {
107
+ if (!spec) {
108
+ console.log(chalk.red('\n Paket adı gerekli\n'));
109
+ console.log(chalk.gray(' Kullanım: natureco plugins install <paket-adı|./path|git:url|clawhub:<id>>\n'));
110
+ console.log(chalk.gray(' Örnekler:'));
111
+ console.log(chalk.gray(' natureco plugins install my-plugin'));
112
+ console.log(chalk.gray(' natureco plugins install npm:my-plugin'));
113
+ console.log(chalk.gray(' natureco plugins install ./yerel-klasor'));
114
+ console.log(chalk.gray(' natureco plugins install git:github.com/user/repo'));
115
+ console.log(chalk.gray(' natureco plugins install clawhub:plugin-id\n'));
116
+ process.exit(1);
117
+ }
118
+
119
+ if (opts.dryRun) {
120
+ console.log(chalk.gray(`\n 📋 Kuru çalışma: "${spec}" yüklenecek\n`));
121
+ return;
122
+ }
123
+
124
+ console.log(chalk.gray(`\n "${spec}" yükleniyor...\n`));
125
+
126
+ try {
127
+ const result = await installPlugin(spec);
128
+ console.log(chalk.green(` ✓ Plugin yüklendi: ${result.name} v${result.version}\n`));
129
+ console.log(chalk.gray(` Kaynak: ${result.source}`));
130
+ console.log(chalk.gray(` Slug: ${result.slug}\n`));
131
+ } catch (err) {
132
+ console.log(chalk.red(`\n Yükleme başarısız: ${err.message}\n`));
133
+ process.exit(1);
134
+ }
135
+ }
136
+
137
+ async function uninstallHandler(slug, opts) {
138
+ if (!slug) {
139
+ console.log(chalk.red('\n ❌ Plugin adı gerekli\n'));
140
+ console.log(chalk.gray(' Kullanım: natureco plugins uninstall <slug>\n'));
141
+ process.exit(1);
142
+ }
143
+
144
+ if (opts.dryRun) {
145
+ console.log(chalk.gray(`\n 📋 Kuru çalışma: "${slug}" kaldırılacak\n`));
146
+ return;
147
+ }
148
+
149
+ try {
150
+ const result = await uninstallPlugin(slug, { keepFiles: opts.keepFiles });
151
+ console.log(chalk.green(`\n Plugin kaldırıldı: ${result.name}\n`));
152
+ } catch (err) {
153
+ console.log(chalk.red(`\n Kaldırma başarısız: ${err.message}\n`));
154
+ process.exit(1);
155
+ }
156
+ }
157
+
158
+ function toggleHandler(slug, enable) {
159
+ if (!slug) {
160
+ console.log(chalk.red(`\n ❌ Plugin adı gerekli\n`));
161
+ process.exit(1);
162
+ }
163
+ const pluginDir = path.join(PLUGINS_DIR, slug);
164
+ if (!fs.existsSync(pluginDir)) {
165
+ console.log(chalk.red(`\n ❌ Plugin bulunamadı: ${slug}\n`));
166
+ process.exit(1);
167
+ }
168
+ const disabledFile = path.join(pluginDir, '.disabled');
169
+ if (enable) {
170
+ if (fs.existsSync(disabledFile)) fs.unlinkSync(disabledFile);
171
+ console.log(chalk.green(`\n ✓ Plugin aktif: ${slug}\n`));
172
+ } else {
173
+ fs.writeFileSync(disabledFile, '');
174
+ console.log(chalk.gray(`\n ○ Plugin pasif: ${slug}\n`));
175
+ }
176
+ }
177
+
178
+ function infoHandler(slug, opts) {
179
+ if (!slug && !opts.all) {
180
+ console.log(chalk.red('\n ❌ Plugin adı gerekli\n'));
181
+ console.log(chalk.gray(' Kullanım: natureco plugins info <slug>\n'));
182
+ process.exit(1);
183
+ }
184
+
185
+ if (opts.all) {
186
+ const all = scanInstalled();
187
+ console.log(chalk.cyan.bold('\n Plugin Detayları\n'));
188
+ all.forEach(p => {
189
+ showPluginDetail(p);
190
+ });
191
+ return;
192
+ }
193
+
194
+ const p = getPlugin(slug);
195
+ if (!p) {
196
+ console.log(chalk.red(`\n ❌ Plugin bulunamadı: ${slug}\n`));
197
+ process.exit(1);
198
+ }
199
+
200
+ if (opts.json) {
201
+ console.log(JSON.stringify({
202
+ slug: p.slug, name: p.name, version: p.version, enabled: p.enabled,
203
+ description: p.description, author: p.author, license: p.license,
204
+ keywords: p.keywords || [], installPath: p.installPath,
205
+ entry: p.entry, dependencies: p.dependencies || {},
206
+ openclaw: p.openclaw || {},
207
+ }, null, 2));
208
+ return;
209
+ }
210
+
211
+ showPluginDetail(p);
212
+ }
213
+
214
+ function showPluginDetail(p) {
215
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
216
+ console.log(chalk.cyan.bold(`\n ${p.name}\n`));
217
+ console.log(chalk.gray(' Slug : ') + chalk.white(p.slug));
218
+ console.log(chalk.gray(' Versiyon : ') + chalk.white(p.version));
219
+ console.log(chalk.gray(' Durum : ') + (p.enabled ? chalk.green('aktif') : chalk.gray('pasif')));
220
+ if (p.description) console.log(chalk.gray(' Açıklama : ') + chalk.white(p.description));
221
+ if (p.author) console.log(chalk.gray(' Yazar : ') + chalk.white(p.author));
222
+ if (p.license) console.log(chalk.gray(' Lisans : ') + chalk.white(p.license));
223
+ if (p.keywords?.length) console.log(chalk.gray(' Etiketler : ') + chalk.white(p.keywords.join(', ')));
224
+ console.log(chalk.gray(' Yol : ') + chalk.gray(p.installPath));
225
+ if (p.entry) console.log(chalk.gray(' Giriş : ') + chalk.white(p.entry));
226
+ if (p.dependencies && Object.keys(p.dependencies).length > 0) {
227
+ console.log(chalk.gray(' Bağımlılıklar:'));
228
+ Object.entries(p.dependencies).forEach(([k, v]) => {
229
+ const depPath = path.join(p.installPath, 'node_modules', k);
230
+ const installed = fs.existsSync(depPath) ? chalk.green('✓') : chalk.yellow('✗');
231
+ console.log(chalk.gray(` ${installed} ${k}: ${v}`));
232
+ });
233
+ }
234
+ if (p.openclaw?.tool) {
235
+ console.log(chalk.gray(' OpenClaw Tool Plugin: ') + chalk.white(p.openclaw.tool));
236
+ }
237
+ console.log('');
238
+ }
239
+
240
+ async function updateHandler(slug, opts) {
241
+ if (!slug && !opts.all) {
242
+ console.log(chalk.red('\n ❌ Plugin adı gerekli\n'));
243
+ console.log(chalk.gray(' Kullanım: natureco plugins update <slug>'));
244
+ console.log(chalk.gray(' Tümü: natureco plugins update --all\n'));
245
+ process.exit(1);
246
+ }
247
+
248
+ if (opts.all) {
249
+ const all = scanInstalled();
250
+ console.log(chalk.cyan('\n Tüm pluginler güncelleniyor...\n'));
251
+ for (const p of all) {
252
+ try {
253
+ const result = await updatePlugin(p.slug);
254
+ console.log(chalk.green(` ✓ ${p.name}: ${p.version} → ${result.version}\n`));
255
+ } catch (err) {
256
+ console.log(chalk.yellow(` ⚠ ${p.name}: ${err.message}\n`));
257
+ }
258
+ }
259
+ return;
260
+ }
261
+
262
+ if (opts.dryRun) {
263
+ console.log(chalk.gray(`\n 📋 Kuru çalışma: "${slug}" güncellenecek\n`));
264
+ return;
265
+ }
266
+
267
+ try {
268
+ const result = await updatePlugin(slug);
269
+ console.log(chalk.green(`\n ✓ Plugin güncellendi: ${result.name} → v${result.version}\n`));
270
+ } catch (err) {
271
+ console.log(chalk.red(`\n ❌ Güncelleme başarısız: ${err.message}\n`));
272
+ process.exit(1);
273
+ }
274
+ }
275
+
276
+ async function searchHandler(query, opts) {
277
+ if (!query) {
278
+ console.log(chalk.red('\n ❌ Arama sorgusu gerekli\n'));
279
+ console.log(chalk.gray(' Kullanım: natureco plugins search <query>\n'));
280
+ process.exit(1);
281
+ }
282
+
283
+ console.log(chalk.gray(`\n "${query}" aranıyor...\n`));
284
+
285
+ const results = [];
286
+
287
+ // Yerel kayıt defterinde ara
288
+ const local = searchRegistry(query);
289
+ local.forEach(p => results.push({ ...p, source: 'registry' }));
290
+
291
+ // NatureHub'da ara
292
+ try {
293
+ const res = await fetch(`https://natureco.me/api/plugins/search?q=${encodeURIComponent(query)}&limit=${opts.limit}`, {
294
+ signal: AbortSignal.timeout(5000),
295
+ });
296
+ if (res.ok) {
297
+ const data = await res.json();
298
+ (data.plugins || data.results || []).forEach(p => {
299
+ if (!results.some(r => r.id === p.id || r.id === p.name)) {
300
+ results.push({ id: p.id || p.name, name: p.name || p.id, version: p.version || 'latest', description: p.description || '', source: 'naturehub' });
301
+ }
302
+ });
303
+ }
304
+ } catch {}
305
+
306
+ // ClawHub'da ara
307
+ try {
308
+ const res = await fetch(`https://clawhub.ai/api/plugins?q=${encodeURIComponent(query)}&limit=${opts.limit}`, {
309
+ signal: AbortSignal.timeout(5000),
310
+ });
311
+ if (res.ok) {
312
+ const data = await res.json();
313
+ (data.plugins || data.results || []).forEach(p => {
314
+ if (!results.some(r => r.id === p.id || r.id === p.name)) {
315
+ results.push({ id: p.id || p.name, name: p.name || p.id, version: p.version || 'latest', description: p.description || '', source: 'clawhub' });
316
+ }
317
+ });
318
+ }
319
+ } catch {}
320
+
321
+ if (opts.json) {
322
+ console.log(JSON.stringify({ query, results, total: results.length }, null, 2));
323
+ return;
324
+ }
325
+
326
+ if (results.length === 0) {
327
+ console.log(chalk.yellow(` "${query}" için sonuç bulunamadı.\n`));
328
+ return;
329
+ }
330
+
331
+ console.log(chalk.cyan(` ${results.length} sonuç\n`));
332
+ results.slice(0, opts.limit).forEach(p => {
333
+ const sourceIcon = p.source === 'clawhub' ? '🦞' : p.source === 'naturehub' ? '🌿' : '📋';
334
+ console.log(` ${sourceIcon} ${chalk.white(p.name)} ${chalk.gray(`v${p.version}`)}`);
335
+ if (p.description) console.log(chalk.gray(` ${p.description.slice(0, 80)}`));
336
+ const installHint = p.source === 'clawhub' ? `clawhub:${p.id}` : p.source === 'naturehub' ? p.id : p.id;
337
+ console.log(chalk.gray(` Yüklemek: natureco plugins install ${installHint}\n`));
338
+ });
339
+ }
340
+
341
+ function doctorHandler() {
342
+ const list = scanInstalled();
343
+ const registry = loadRegistry();
344
+
345
+ console.log(chalk.cyan.bold('\n Plugin Tanılama\n'));
346
+
347
+ if (list.length === 0 && registry.plugins.length === 0) {
348
+ console.log(chalk.gray(' Yüklü plugin yok.\n'));
349
+ return;
350
+ }
351
+
352
+ let issues = 0;
353
+
354
+ list.forEach(p => {
355
+ const hasEntry = fs.existsSync(path.join(p.installPath, p.entry || 'index.js'));
356
+ const hasPackage = fs.existsSync(path.join(p.installPath, 'package.json'));
357
+ const manifestErrors = validateManifest(p);
358
+
359
+ if (!hasPackage) {
360
+ console.log(chalk.yellow(` ⚠ ${p.name}: package.json eksik`));
361
+ issues++;
362
+ }
363
+ if (!hasEntry) {
364
+ console.log(chalk.yellow(` ⚠ ${p.name}: ${p.entry || 'index.js'} bulunamadı`));
365
+ issues++;
366
+ }
367
+ if (manifestErrors.length > 0) {
368
+ console.log(chalk.yellow(` ⚠ ${p.name}: ${manifestErrors.join(', ')}`));
369
+ issues++;
370
+ }
371
+
372
+ if (hasPackage && hasEntry && manifestErrors.length === 0) {
373
+ console.log(` ${chalk.green('✓')} ${p.name} v${p.version} — sağlıklı`);
374
+ }
375
+ });
376
+
377
+ registry.plugins.forEach(r => {
378
+ if (!list.some(p => p.slug === r.id)) {
379
+ console.log(chalk.yellow(` ⚠ Kayıtlı ama diskte yok: ${r.id} (kayıttan temizlenecek)`));
380
+ issues++;
381
+ }
382
+ });
383
+
384
+ if (issues === 0 && list.length > 0) {
385
+ console.log(chalk.green(' ✓ Tüm pluginler sağlıklı.\n'));
386
+ } else if (issues > 0) {
387
+ console.log(chalk.yellow(`\n ⚠ ${issues} sorun bulundu.\n`));
388
+ }
389
+ console.log('');
390
+ }
391
+
392
+ function registryHandler(opts) {
393
+ const registry = loadRegistry();
394
+
395
+ if (opts.json) {
396
+ console.log(JSON.stringify(registry, null, 2));
397
+ return;
398
+ }
399
+
400
+ console.log(chalk.cyan.bold('\n Plugin Kayıt Defteri\n'));
401
+ console.log(chalk.gray(' Versiyon : ') + chalk.white(`v${registry.version}`));
402
+ console.log(chalk.gray(' Güncelleme: ') + chalk.white(registry.updatedAt || 'hiç'));
403
+ console.log(chalk.gray(' Kayıtlı : ') + chalk.white(`${registry.plugins.length} plugin`));
404
+
405
+ if (registry.plugins.length > 0) {
406
+ console.log(chalk.cyan('\n Kayıtlı Pluginler\n'));
407
+ registry.plugins.forEach(p => {
408
+ const installed = scanInstalled().some(s => s.slug === p.id) ? chalk.green('✓') : chalk.yellow('✗');
409
+ console.log(` ${installed} ${chalk.white(p.name || p.id)} ${chalk.gray(`v${p.version} [${p.source}]`)}`);
410
+ });
411
+ }
412
+ console.log('');
413
+ }
414
+
415
+ module.exports = plugins;