natureco-cli 5.20.4 → 5.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +779 -750
- package/README.md +608 -610
- package/bin/natureco.js +1099 -1095
- package/package.json +95 -94
- package/scripts/generate-qr.js +21 -0
- package/scripts/import-curated-skills-log.json +5 -0
- package/scripts/import-curated-skills.js +262 -0
- package/scripts/import-skills-log.json +167 -0
- package/scripts/import-skills.js +261 -0
- package/scripts/postinstall.js +125 -0
- package/src/commands/agent.js +280 -280
- package/src/commands/ask.js +4 -2
- package/src/commands/chat.js +0 -1
- package/src/commands/help.js +0 -2
- package/src/commands/naturehub.js +206 -373
- package/src/commands/repl.js +56 -63
- package/src/providers/mem0-memory.js +121 -121
- package/src/providers/supermemory-memory.js +117 -117
- package/src/tools/llm_task.js +150 -163
- package/src/tools/mac_alarm.js +199 -199
- package/src/tools/workflow.js +438 -439
- package/src/utils/api.js +1211 -1188
- package/src/utils/cost-tracker.js +361 -360
- package/src/utils/inquirer-wrapper.js +43 -31
- package/src/utils/paste-safe-input.js +346 -334
- package/src/utils/process-errors.js +129 -115
- package/src/utils/provider-detect.js +76 -72
- package/src/utils/skills.js +1 -1
- package/src/utils/system-prompt.js +141 -136
- package/src/utils/tools.js +324 -324
- package/README.md.bak +0 -565
- package/src/tools/http.js.bak +0 -78
|
@@ -1,115 +1,129 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Top-level process error handlers.
|
|
3
|
-
*
|
|
4
|
-
* Node's default behavior for unhandled rejections is to print a deprecated
|
|
5
|
-
* warning and (since Node 15) exit with code 1. The default for uncaught
|
|
6
|
-
* exceptions is to print the stack and exit 1. Both bypass natureco's audit
|
|
7
|
-
* trail and dump raw Node output that's useless to a CLI user.
|
|
8
|
-
*
|
|
9
|
-
* `install({ audit, exit, stderr })` registers handlers that:
|
|
10
|
-
* 1. Append a structured entry to the audit log (synchronous — the
|
|
11
|
-
* process is about to die, async fire-and-forget would race),
|
|
12
|
-
* 2. Print a single friendly Turkish line + log path to stderr,
|
|
13
|
-
* 3. Exit with code 1 (configurable via `exit` for tests).
|
|
14
|
-
*
|
|
15
|
-
* Idempotent: a second call replaces the previous handlers (so the test
|
|
16
|
-
* suite can re-install with fresh spies).
|
|
17
|
-
*/
|
|
18
|
-
const path = require('path');
|
|
19
|
-
const os = require('os');
|
|
20
|
-
|
|
21
|
-
const ERROR_LOG_PATH = path.join(os.homedir(), '.natureco', 'logs', 'crash.log');
|
|
22
|
-
|
|
23
|
-
let _installed = false;
|
|
24
|
-
let _registered = { rejection: null, exception: null, warning: null };
|
|
25
|
-
|
|
26
|
-
function _defaultAudit() {
|
|
27
|
-
try {
|
|
28
|
-
return require('./audit');
|
|
29
|
-
} catch {
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function _serializeError(err) {
|
|
35
|
-
if (!err) return { type: 'unknown', message: 'null' };
|
|
36
|
-
if (err instanceof Error) {
|
|
37
|
-
return {
|
|
38
|
-
type: err.constructor.name,
|
|
39
|
-
message: err.message,
|
|
40
|
-
stack: err.stack ? err.stack.split('\n').slice(0, 20).join('\n') : null,
|
|
41
|
-
code: err.code,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
if (typeof err === 'object') {
|
|
45
|
-
try { return { type: 'object', message: JSON.stringify(err).slice(0, 1000) }; }
|
|
46
|
-
catch { return { type: 'object', message: String(err) }; }
|
|
47
|
-
}
|
|
48
|
-
return { type: typeof err, message: String(err) };
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Install global handlers. Returns an `uninstall()` function.
|
|
53
|
-
*
|
|
54
|
-
* @param {{
|
|
55
|
-
* audit?: { logSync: Function, ACTIONS?: Record<string,string> } | null,
|
|
56
|
-
* exit?: (code: number) => void,
|
|
57
|
-
* stderr?: (msg: string) => void,
|
|
58
|
-
* }} [opts]
|
|
59
|
-
*/
|
|
60
|
-
function install(opts = {}) {
|
|
61
|
-
const audit = opts.audit === undefined ? _defaultAudit() : opts.audit;
|
|
62
|
-
const exit = opts.exit || ((code) => process.exit(code));
|
|
63
|
-
const stderr = opts.stderr || ((msg) => process.stderr.write(msg));
|
|
64
|
-
|
|
65
|
-
// Replace any previous handlers (idempotency for tests).
|
|
66
|
-
if (_registered.rejection) process.off('unhandledRejection', _registered.rejection);
|
|
67
|
-
if (_registered.exception) process.off('uncaughtException', _registered.exception);
|
|
68
|
-
|
|
69
|
-
const onRejection = (reason) => {
|
|
70
|
-
const payload = { kind: 'unhandledRejection', error: _serializeError(reason) };
|
|
71
|
-
try { audit?.logSync('error', payload); } catch { /* ignore */ }
|
|
72
|
-
|
|
73
|
-
`\n
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Top-level process error handlers.
|
|
3
|
+
*
|
|
4
|
+
* Node's default behavior for unhandled rejections is to print a deprecated
|
|
5
|
+
* warning and (since Node 15) exit with code 1. The default for uncaught
|
|
6
|
+
* exceptions is to print the stack and exit 1. Both bypass natureco's audit
|
|
7
|
+
* trail and dump raw Node output that's useless to a CLI user.
|
|
8
|
+
*
|
|
9
|
+
* `install({ audit, exit, stderr })` registers handlers that:
|
|
10
|
+
* 1. Append a structured entry to the audit log (synchronous — the
|
|
11
|
+
* process is about to die, async fire-and-forget would race),
|
|
12
|
+
* 2. Print a single friendly Turkish line + log path to stderr,
|
|
13
|
+
* 3. Exit with code 1 (configurable via `exit` for tests).
|
|
14
|
+
*
|
|
15
|
+
* Idempotent: a second call replaces the previous handlers (so the test
|
|
16
|
+
* suite can re-install with fresh spies).
|
|
17
|
+
*/
|
|
18
|
+
const path = require('path');
|
|
19
|
+
const os = require('os');
|
|
20
|
+
|
|
21
|
+
const ERROR_LOG_PATH = path.join(os.homedir(), '.natureco', 'logs', 'crash.log');
|
|
22
|
+
|
|
23
|
+
let _installed = false;
|
|
24
|
+
let _registered = { rejection: null, exception: null, warning: null };
|
|
25
|
+
|
|
26
|
+
function _defaultAudit() {
|
|
27
|
+
try {
|
|
28
|
+
return require('./audit');
|
|
29
|
+
} catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function _serializeError(err) {
|
|
35
|
+
if (!err) return { type: 'unknown', message: 'null' };
|
|
36
|
+
if (err instanceof Error) {
|
|
37
|
+
return {
|
|
38
|
+
type: err.constructor.name,
|
|
39
|
+
message: err.message,
|
|
40
|
+
stack: err.stack ? err.stack.split('\n').slice(0, 20).join('\n') : null,
|
|
41
|
+
code: err.code,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
if (typeof err === 'object') {
|
|
45
|
+
try { return { type: 'object', message: JSON.stringify(err).slice(0, 1000) }; }
|
|
46
|
+
catch { return { type: 'object', message: String(err) }; }
|
|
47
|
+
}
|
|
48
|
+
return { type: typeof err, message: String(err) };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Install global handlers. Returns an `uninstall()` function.
|
|
53
|
+
*
|
|
54
|
+
* @param {{
|
|
55
|
+
* audit?: { logSync: Function, ACTIONS?: Record<string,string> } | null,
|
|
56
|
+
* exit?: (code: number) => void,
|
|
57
|
+
* stderr?: (msg: string) => void,
|
|
58
|
+
* }} [opts]
|
|
59
|
+
*/
|
|
60
|
+
function install(opts = {}) {
|
|
61
|
+
const audit = opts.audit === undefined ? _defaultAudit() : opts.audit;
|
|
62
|
+
const exit = opts.exit || ((code) => process.exit(code));
|
|
63
|
+
const stderr = opts.stderr || ((msg) => process.stderr.write(msg));
|
|
64
|
+
|
|
65
|
+
// Replace any previous handlers (idempotency for tests).
|
|
66
|
+
if (_registered.rejection) process.off('unhandledRejection', _registered.rejection);
|
|
67
|
+
if (_registered.exception) process.off('uncaughtException', _registered.exception);
|
|
68
|
+
|
|
69
|
+
const onRejection = (reason) => {
|
|
70
|
+
const payload = { kind: 'unhandledRejection', error: _serializeError(reason) };
|
|
71
|
+
try { audit?.logSync('error', payload); } catch { /* ignore */ }
|
|
72
|
+
if (process.env.NATURECO_DEBUG) {
|
|
73
|
+
stderr(`\n[DEBUG] stack:\n${payload.error.stack || '(stack yok)'}\n`);
|
|
74
|
+
}
|
|
75
|
+
stderr(
|
|
76
|
+
`\n ✗ Beklenmedik bir hata oluştu (unhandled promise rejection).\n` +
|
|
77
|
+
` Detay: ${payload.error.message}\n` +
|
|
78
|
+
` Log: ${ERROR_LOG_PATH}\n` +
|
|
79
|
+
` Hata raporu için: github.com/natureco-official/natureco-cli/issues\n\n`,
|
|
80
|
+
);
|
|
81
|
+
exit(1);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const onException = (err) => {
|
|
85
|
+
// EPIPE: çıktı bir boruya aktarılırken okuyucu kapandı (ör. `natureco help | head`).
|
|
86
|
+
// Hata değil, normal akış — sessizce başarıyla çık.
|
|
87
|
+
if (err && err.code === 'EPIPE') { exit(0); return; }
|
|
88
|
+
const payload = { kind: 'uncaughtException', error: _serializeError(err) };
|
|
89
|
+
try { audit?.logSync('error', payload); } catch { /* ignore */ }
|
|
90
|
+
stderr(
|
|
91
|
+
`\n ✗ Beklenmedik bir hata oluştu (uncaught exception).\n` +
|
|
92
|
+
` Detay: ${payload.error.message}\n` +
|
|
93
|
+
` Log: ${ERROR_LOG_PATH}\n` +
|
|
94
|
+
` Hata raporu için: github.com/natureco-official/natureco-cli/issues\n\n`,
|
|
95
|
+
);
|
|
96
|
+
exit(1);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// Akış seviyesinde EPIPE — stdout/stderr 'error' olayı uncaughtException'a
|
|
100
|
+
// dönüşmeden önce yakala (Node bazı platformlarda stream error olarak verir)
|
|
101
|
+
const onStreamError = (err) => {
|
|
102
|
+
if (err && err.code === 'EPIPE') exit(0);
|
|
103
|
+
};
|
|
104
|
+
process.stdout.on('error', onStreamError);
|
|
105
|
+
process.stderr.on('error', onStreamError);
|
|
106
|
+
|
|
107
|
+
process.on('unhandledRejection', onRejection);
|
|
108
|
+
process.on('uncaughtException', onException);
|
|
109
|
+
_registered = { rejection: onRejection, exception: onException, warning: null };
|
|
110
|
+
_installed = true;
|
|
111
|
+
|
|
112
|
+
return function uninstall() {
|
|
113
|
+
if (_registered.rejection) process.off('unhandledRejection', _registered.rejection);
|
|
114
|
+
if (_registered.exception) process.off('uncaughtException', _registered.exception);
|
|
115
|
+
_registered = { rejection: null, exception: null, warning: null };
|
|
116
|
+
_installed = false;
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function isInstalled() {
|
|
121
|
+
return _installed;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
module.exports = {
|
|
125
|
+
install,
|
|
126
|
+
isInstalled,
|
|
127
|
+
ERROR_LOG_PATH,
|
|
128
|
+
_internals: { _serializeError },
|
|
129
|
+
};
|
|
@@ -1,72 +1,76 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Provider detection — single source of truth for "given a base URL
|
|
3
|
-
* (and optionally a model name) which provider family is this?"
|
|
4
|
-
*
|
|
5
|
-
* v5.22.0: Delegates real detection to model-provider.js's detectFamily.
|
|
6
|
-
* Keeps convenience predicates (isAnthropic, isMiniMax, etc.) and
|
|
7
|
-
* buildChatEndpoint for backward compatibility.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
const { detectFamily } = require('./model-provider');
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Canonical detection — delegates to model-provider.
|
|
14
|
-
* @param {string} providerUrl
|
|
15
|
-
* @param {string} [model]
|
|
16
|
-
* @returns {string}
|
|
17
|
-
*/
|
|
18
|
-
function detectProvider(providerUrl, model) {
|
|
19
|
-
return detectFamily(providerUrl, model);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/** Convenience predicates — each one short-circuits on hostname only. */
|
|
23
|
-
function isAnthropic(url) {
|
|
24
|
-
return (url || '').toLowerCase().includes('anthropic.com');
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function isGroq(url) {
|
|
28
|
-
return (url || '').toLowerCase().includes('groq.com');
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* MiniMax has three known production hosts:
|
|
33
|
-
* api.minimax.io — global English-facing
|
|
34
|
-
* api.minimaxi.com — China-facing
|
|
35
|
-
* api.minimax.cn — legacy CN domain seen in some auth tokens
|
|
36
|
-
*/
|
|
37
|
-
function isMiniMax(url) {
|
|
38
|
-
const u = (url || '').toLowerCase();
|
|
39
|
-
return u.includes('minimax.io') || u.includes('minimaxi.com') || u.includes('minimax.cn');
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function isOllama(url) {
|
|
43
|
-
const u = (url || '').toLowerCase();
|
|
44
|
-
return u.includes('localhost') || u.includes('127.0.0.1') || u.includes('ollama');
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function isGemini(url) {
|
|
48
|
-
const u = (url || '').toLowerCase();
|
|
49
|
-
return u.includes('generativelanguage.googleapis.com') || u.includes('gemini');
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Build the correct chat completions endpoint for a given provider URL.
|
|
54
|
-
* Handles MiniMax (non-standard path), Gemini (OpenAI-compat path under /openai/),
|
|
55
|
-
* and standard OpenAI-compatible providers.
|
|
56
|
-
*/
|
|
57
|
-
function buildChatEndpoint(providerUrl) {
|
|
58
|
-
|
|
59
|
-
if (isMiniMax(base))
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Provider detection — single source of truth for "given a base URL
|
|
3
|
+
* (and optionally a model name) which provider family is this?"
|
|
4
|
+
*
|
|
5
|
+
* v5.22.0: Delegates real detection to model-provider.js's detectFamily.
|
|
6
|
+
* Keeps convenience predicates (isAnthropic, isMiniMax, etc.) and
|
|
7
|
+
* buildChatEndpoint for backward compatibility.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const { detectFamily } = require('./model-provider');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Canonical detection — delegates to model-provider.
|
|
14
|
+
* @param {string} providerUrl
|
|
15
|
+
* @param {string} [model]
|
|
16
|
+
* @returns {string}
|
|
17
|
+
*/
|
|
18
|
+
function detectProvider(providerUrl, model) {
|
|
19
|
+
return detectFamily(providerUrl, model);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Convenience predicates — each one short-circuits on hostname only. */
|
|
23
|
+
function isAnthropic(url) {
|
|
24
|
+
return (url || '').toLowerCase().includes('anthropic.com');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function isGroq(url) {
|
|
28
|
+
return (url || '').toLowerCase().includes('groq.com');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* MiniMax has three known production hosts:
|
|
33
|
+
* api.minimax.io — global English-facing
|
|
34
|
+
* api.minimaxi.com — China-facing
|
|
35
|
+
* api.minimax.cn — legacy CN domain seen in some auth tokens
|
|
36
|
+
*/
|
|
37
|
+
function isMiniMax(url) {
|
|
38
|
+
const u = (url || '').toLowerCase();
|
|
39
|
+
return u.includes('minimax.io') || u.includes('minimaxi.com') || u.includes('minimax.cn');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function isOllama(url) {
|
|
43
|
+
const u = (url || '').toLowerCase();
|
|
44
|
+
return u.includes('localhost') || u.includes('127.0.0.1') || u.includes('ollama');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function isGemini(url) {
|
|
48
|
+
const u = (url || '').toLowerCase();
|
|
49
|
+
return u.includes('generativelanguage.googleapis.com') || u.includes('gemini');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Build the correct chat completions endpoint for a given provider URL.
|
|
54
|
+
* Handles MiniMax (non-standard path), Gemini (OpenAI-compat path under /openai/),
|
|
55
|
+
* and standard OpenAI-compatible providers.
|
|
56
|
+
*/
|
|
57
|
+
function buildChatEndpoint(providerUrl) {
|
|
58
|
+
let base = (providerUrl || '').replace(/\/+$/, '');
|
|
59
|
+
if (isMiniMax(base)) {
|
|
60
|
+
// Kullanıcı OpenAI alışkanlığıyla .../v1 girerse /v1/v1/... 404'üne düşmesin
|
|
61
|
+
base = base.replace(/\/v1$/, '');
|
|
62
|
+
return `${base}/v1/text/chatcompletion_v2`;
|
|
63
|
+
}
|
|
64
|
+
if (isGemini(base)) return `${base}/openai/chat/completions`;
|
|
65
|
+
return `${base}/chat/completions`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
module.exports = {
|
|
69
|
+
detectProvider,
|
|
70
|
+
isAnthropic,
|
|
71
|
+
isGroq,
|
|
72
|
+
isMiniMax,
|
|
73
|
+
isOllama,
|
|
74
|
+
isGemini,
|
|
75
|
+
buildChatEndpoint,
|
|
76
|
+
};
|
package/src/utils/skills.js
CHANGED
|
@@ -212,7 +212,7 @@ async function installSkill(slug) {
|
|
|
212
212
|
|
|
213
213
|
fs.writeFileSync(path.join(skillDir, 'SKILL.md'), content, 'utf8');
|
|
214
214
|
} catch (err) {
|
|
215
|
-
throw new Error(`Skill yüklenemedi: ${err.message}
|
|
215
|
+
throw new Error(`Skill yüklenemedi: ${err.message}`, { cause: err });
|
|
216
216
|
}
|
|
217
217
|
}
|
|
218
218
|
|