natureco-cli 2.23.28 → 2.23.29
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/bin/natureco.js +68 -6
- package/package.json +10 -6
- package/src/commands/channels.js +94 -4
- package/src/commands/chat.js +11 -25
- package/src/commands/config.js +111 -68
- package/src/commands/doctor.js +121 -16
- package/src/commands/gateway-server.js +35 -21
- package/src/commands/gateway.js +11 -20
- package/src/commands/help.js +6 -0
- package/src/commands/imessage.js +55 -0
- package/src/commands/irc.js +70 -0
- package/src/commands/mattermost.js +62 -0
- package/src/commands/message.js +24 -4
- package/src/commands/models.js +584 -216
- package/src/commands/plugins.js +415 -172
- package/src/commands/security.js +149 -1
- package/src/commands/setup.js +1 -3
- package/src/commands/signal.js +66 -0
- package/src/commands/skills.js +20 -29
- package/src/commands/sms.js +64 -0
- package/src/commands/tasks.js +328 -79
- package/src/commands/webhooks.js +79 -0
- package/src/commands/whatsapp.js +7 -21
- package/src/tools/bash.js +63 -29
- package/src/utils/api.js +3 -20
- package/src/utils/approvals.js +297 -0
- package/src/utils/background.js +223 -66
- package/src/utils/baileys.js +21 -0
- package/src/utils/config.js +141 -10
- package/src/utils/errors.js +148 -0
- package/src/utils/inquirer-wrapper.js +1 -2
- package/src/utils/path-utils.js +13 -13
- package/src/utils/plugin-registry.js +238 -0
- package/src/utils/secrets.js +177 -0
- package/src/utils/skills.js +10 -23
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const { NatureCoError } = require('./errors');
|
|
5
|
+
|
|
6
|
+
const ENV_SHORTHAND_RE = /^\$\{([A-Z][A-Z0-9_]{0,127})\}$/;
|
|
7
|
+
const ENV_SHORT_RE = /^\$([A-Z][A-Z0-9_]{0,127})$/;
|
|
8
|
+
const SECRET_REF_ENV_PREFIX = 'secretref-env:';
|
|
9
|
+
const SECRET_REF_ENV_LEGACY = '__env__:';
|
|
10
|
+
|
|
11
|
+
class UnresolvedSecretError extends NatureCoError {
|
|
12
|
+
constructor(message, options = {}) {
|
|
13
|
+
super(message, options);
|
|
14
|
+
this.ref = options.ref || null;
|
|
15
|
+
this.path = options.path || null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Cache for resolved secrets
|
|
20
|
+
const _secretCache = new Map();
|
|
21
|
+
|
|
22
|
+
function resolveEnvVar(name) {
|
|
23
|
+
return process.env[name] ?? null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function coerceSecretRef(value) {
|
|
27
|
+
if (!value || typeof value !== 'string') return null;
|
|
28
|
+
|
|
29
|
+
// Structured ref: {"source":"env","provider":"default","id":"MY_KEY"}
|
|
30
|
+
try {
|
|
31
|
+
const parsed = JSON.parse(value);
|
|
32
|
+
if (parsed && typeof parsed === 'object' && parsed.source && parsed.provider && parsed.id) {
|
|
33
|
+
return { source: parsed.source, provider: parsed.provider, id: parsed.id };
|
|
34
|
+
}
|
|
35
|
+
} catch {}
|
|
36
|
+
|
|
37
|
+
// Env shorthand: ${MY_KEY} or $MY_KEY
|
|
38
|
+
let m = value.match(ENV_SHORTHAND_RE);
|
|
39
|
+
if (m) return { source: 'env', provider: 'default', id: m[1] };
|
|
40
|
+
m = value.match(ENV_SHORT_RE);
|
|
41
|
+
if (m) return { source: 'env', provider: 'default', id: m[1] };
|
|
42
|
+
|
|
43
|
+
// Legacy: secretref-env:MY_KEY or __env__:MY_KEY
|
|
44
|
+
if (value.startsWith(SECRET_REF_ENV_PREFIX)) {
|
|
45
|
+
return { source: 'env', provider: 'default', id: value.slice(SECRET_REF_ENV_PREFIX.length) };
|
|
46
|
+
}
|
|
47
|
+
if (value.startsWith(SECRET_REF_ENV_LEGACY)) {
|
|
48
|
+
return { source: 'env', provider: 'default', id: value.slice(SECRET_REF_ENV_LEGACY.length) };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function resolveSecretRef(ref, options = {}) {
|
|
55
|
+
const { cache = true, throwOnMissing = false } = options;
|
|
56
|
+
const cacheKey = `${ref.source}:${ref.provider}:${ref.id}`;
|
|
57
|
+
|
|
58
|
+
if (cache && _secretCache.has(cacheKey)) {
|
|
59
|
+
return _secretCache.get(cacheKey);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
let resolved = null;
|
|
63
|
+
|
|
64
|
+
if (ref.source === 'env') {
|
|
65
|
+
resolved = resolveEnvVar(ref.id);
|
|
66
|
+
} else if (ref.source === 'file') {
|
|
67
|
+
try {
|
|
68
|
+
const content = fs.readFileSync(ref.id, 'utf8').trim();
|
|
69
|
+
resolved = content;
|
|
70
|
+
} catch {}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (resolved === null && throwOnMissing) {
|
|
74
|
+
throw new UnresolvedSecretError(
|
|
75
|
+
`Secret not found: ${cacheKey}`,
|
|
76
|
+
{ ref, path: cacheKey }
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (cache && resolved !== null) {
|
|
81
|
+
_secretCache.set(cacheKey, resolved);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return resolved;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function resolveSecretValue(value, options = {}) {
|
|
88
|
+
if (!value || typeof value !== 'string') return value;
|
|
89
|
+
|
|
90
|
+
const ref = coerceSecretRef(value);
|
|
91
|
+
if (ref) {
|
|
92
|
+
const resolved = resolveSecretRef(ref, options);
|
|
93
|
+
return resolved ?? value;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return value;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function resolveConfigSecrets(config, options = {}) {
|
|
100
|
+
if (!config || typeof config !== 'object') return config;
|
|
101
|
+
|
|
102
|
+
const resolved = Array.isArray(config) ? [] : {};
|
|
103
|
+
for (const [key, value] of Object.entries(config)) {
|
|
104
|
+
if (value && typeof value === 'object') {
|
|
105
|
+
resolved[key] = resolveConfigSecrets(value, options);
|
|
106
|
+
} else if (typeof value === 'string') {
|
|
107
|
+
resolved[key] = resolveSecretValue(value, options);
|
|
108
|
+
} else {
|
|
109
|
+
resolved[key] = value;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return resolved;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function loadEnvFile(filePath) {
|
|
116
|
+
const envPath = filePath || path.join(process.cwd(), '.env');
|
|
117
|
+
if (!fs.existsSync(envPath)) return {};
|
|
118
|
+
|
|
119
|
+
const env = {};
|
|
120
|
+
const content = fs.readFileSync(envPath, 'utf8');
|
|
121
|
+
for (const line of content.split('\n')) {
|
|
122
|
+
const trimmed = line.trim();
|
|
123
|
+
if (!trimmed || trimmed.startsWith('#') || !trimmed.includes('=')) continue;
|
|
124
|
+
const eqIdx = trimmed.indexOf('=');
|
|
125
|
+
const key = trimmed.slice(0, eqIdx).trim();
|
|
126
|
+
let val = trimmed.slice(eqIdx + 1).trim();
|
|
127
|
+
if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) {
|
|
128
|
+
val = val.slice(1, -1);
|
|
129
|
+
}
|
|
130
|
+
if (key) env[key] = val;
|
|
131
|
+
}
|
|
132
|
+
return env;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function injectEnvFile(envPath) {
|
|
136
|
+
const env = loadEnvFile(envPath);
|
|
137
|
+
for (const [key, val] of Object.entries(env)) {
|
|
138
|
+
if (!(key in process.env)) {
|
|
139
|
+
process.env[key] = val;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return env;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function clearSecretCache() {
|
|
146
|
+
_secretCache.clear();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function listSecretRefs(config, prefix = '') {
|
|
150
|
+
const refs = [];
|
|
151
|
+
if (!config || typeof config !== 'object') return refs;
|
|
152
|
+
|
|
153
|
+
for (const [key, value] of Object.entries(config)) {
|
|
154
|
+
const fullPath = prefix ? `${prefix}.${key}` : key;
|
|
155
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
156
|
+
refs.push(...listSecretRefs(value, fullPath));
|
|
157
|
+
} else if (typeof value === 'string') {
|
|
158
|
+
const ref = coerceSecretRef(value);
|
|
159
|
+
if (ref) {
|
|
160
|
+
refs.push({ path: fullPath, ref, value });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return refs;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
module.exports = {
|
|
168
|
+
UnresolvedSecretError,
|
|
169
|
+
coerceSecretRef,
|
|
170
|
+
resolveSecretRef,
|
|
171
|
+
resolveSecretValue,
|
|
172
|
+
resolveConfigSecrets,
|
|
173
|
+
loadEnvFile,
|
|
174
|
+
injectEnvFile,
|
|
175
|
+
clearSecretCache,
|
|
176
|
+
listSecretRefs,
|
|
177
|
+
};
|
package/src/utils/skills.js
CHANGED
|
@@ -299,30 +299,17 @@ Bu skill ${name} işlemlerini yapar.
|
|
|
299
299
|
return path.join(skillDir, 'SKILL.md');
|
|
300
300
|
}
|
|
301
301
|
|
|
302
|
-
//
|
|
303
|
-
const POPULAR_SKILLS = [
|
|
304
|
-
{ slug: 'github', name: 'GitHub', description: 'GitHub repo işlemleri', source: 'clawhub' },
|
|
305
|
-
{ slug: 'filesystem', name: 'Filesystem', description: 'Dosya sistemi işlemleri', source: 'clawhub' },
|
|
306
|
-
{ slug: 'web-search', name: 'Web Search', description: 'Web arama', source: 'clawhub' },
|
|
307
|
-
{ slug: 'summarize', name: 'Summarize', description: 'Metin özetleme', source: 'clawhub' },
|
|
308
|
-
{ slug: 'code-review', name: 'Code Review', description: 'Kod inceleme', source: 'clawhub' },
|
|
309
|
-
{ slug: 'translate', name: 'Translate', description: 'Çeviri', source: 'clawhub' },
|
|
310
|
-
{ slug: 'weather', name: 'Weather', description: 'Hava durumu', source: 'clawhub' },
|
|
311
|
-
{ slug: 'calendar', name: 'Calendar', description: 'Takvim yönetimi', source: 'clawhub' },
|
|
312
|
-
];
|
|
313
|
-
|
|
314
|
-
// Get popular skills from ClawHub API (fallback to hardcoded list)
|
|
302
|
+
// Get popular skills from ClawHub API (no fallback — transparent error)
|
|
315
303
|
async function getPopularSkills() {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
return POPULAR_SKILLS;
|
|
304
|
+
const response = await fetch('https://clawhub.ai/api/skills?q=&limit=20');
|
|
305
|
+
if (!response.ok) {
|
|
306
|
+
throw new Error(`ClawHub API returned HTTP ${response.status}`);
|
|
307
|
+
}
|
|
308
|
+
const data = await response.json();
|
|
309
|
+
if (!data.skills || data.skills.length === 0) {
|
|
310
|
+
throw new Error('ClawHub API returned empty skill list');
|
|
311
|
+
}
|
|
312
|
+
return data.skills.map(s => ({ ...s, source: 'clawhub' }));
|
|
326
313
|
}
|
|
327
314
|
|
|
328
315
|
// Get skill prompt injection content (full SKILL.md content)
|