natureco-cli 5.6.15 → 5.6.17
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 +1085 -1084
- package/package.json +1 -1
- package/src/commands/memory-cmd.js +406 -338
- package/src/commands/reset.js +23 -12
- package/src/utils/dangerous.js +110 -0
- package/src/utils/memory-store.js +185 -0
package/src/commands/reset.js
CHANGED
|
@@ -17,12 +17,34 @@ const path = require('path');
|
|
|
17
17
|
const os = require('os');
|
|
18
18
|
const inquirer = require('../utils/inquirer-wrapper');
|
|
19
19
|
const chalk = require('chalk');
|
|
20
|
+
const { requireApproval, RISK } = require('../utils/dangerous');
|
|
20
21
|
|
|
21
22
|
async function reset() {
|
|
22
23
|
const args = process.argv.slice(3);
|
|
23
24
|
const home = os.homedir();
|
|
24
25
|
const baseDir = path.join(home, '.natureco');
|
|
25
26
|
|
|
27
|
+
// v5.6.16: Dangerous command approval
|
|
28
|
+
const isFullReset = args.includes('--all') || args.includes('--personal');
|
|
29
|
+
const risk = isFullReset ? RISK.CRITICAL : RISK.HIGH;
|
|
30
|
+
const reason = isFullReset
|
|
31
|
+
? 'Tum kisisel veriler ve ayarlar silinecek (geri alinamaz)'
|
|
32
|
+
: 'Secili kapsamdaki veriler silinecek';
|
|
33
|
+
|
|
34
|
+
// --yes/-y bypass (eski davranis)
|
|
35
|
+
const skipApproval = args.includes('--yes') || args.includes('-y');
|
|
36
|
+
|
|
37
|
+
if (!skipApproval) {
|
|
38
|
+
const argsObj = {
|
|
39
|
+
flags: args.filter(a => a.startsWith('--') || a.startsWith('-'))
|
|
40
|
+
};
|
|
41
|
+
const approved = await requireApproval('natureco reset', argsObj, risk, reason);
|
|
42
|
+
if (!approved) {
|
|
43
|
+
console.log(chalk.gray('\nIptal edildi.\n'));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
26
48
|
console.log(chalk.yellow('\n\u26a0 RESET - Tum veriler silinecek!\n'));
|
|
27
49
|
|
|
28
50
|
const whatToReset = {
|
|
@@ -48,18 +70,7 @@ async function reset() {
|
|
|
48
70
|
if (whatToReset.soul) console.log(' - soul/ (generic default doner)');
|
|
49
71
|
if (whatToReset.personal) console.log(' - personal/');
|
|
50
72
|
|
|
51
|
-
|
|
52
|
-
const ans = await inquirer.prompt([{
|
|
53
|
-
type: 'confirm',
|
|
54
|
-
name: 'confirm',
|
|
55
|
-
message: 'Tum verileri silmek istediginize emin misiniz?',
|
|
56
|
-
default: false,
|
|
57
|
-
}]);
|
|
58
|
-
|
|
59
|
-
if (!ans.confirm) {
|
|
60
|
-
console.log(chalk.gray('\nIptal edildi.'));
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
73
|
+
|
|
63
74
|
|
|
64
75
|
// Sil
|
|
65
76
|
if (whatToReset.config) {
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dangerous Command Approval (v5.6.16)
|
|
3
|
+
*
|
|
4
|
+
* Hermes Agent'taki "Command required approval" mekanizmasinin
|
|
5
|
+
* NatureCo CLI versiyonu. Riskli komutlari calistirmadan once
|
|
6
|
+
* kullanici onayi alir.
|
|
7
|
+
*
|
|
8
|
+
* Kullanim:
|
|
9
|
+
* const { requireApproval, RISK } = require('../utils/dangerous');
|
|
10
|
+
* if (!await requireApproval('reset', { scope: 'full' }, RISK.CRITICAL)) return;
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const inquirer = require('../utils/inquirer-wrapper');
|
|
14
|
+
const chalk = require('chalk');
|
|
15
|
+
|
|
16
|
+
const RISK = {
|
|
17
|
+
LOW: 'low', // Otomatik onay
|
|
18
|
+
MEDIUM: 'medium', // Basit onay mesaji
|
|
19
|
+
HIGH: 'high', // Acik onay gerekli
|
|
20
|
+
CRITICAL: 'critical', // Tam yazim onay gerekli
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const RISK_LABELS = {
|
|
24
|
+
low: { color: 'gray', icon: '⚪', label: 'DUSUK RISK' },
|
|
25
|
+
medium: { color: 'yellow', icon: '🟡', label: 'ORTA RISK' },
|
|
26
|
+
high: { color: 'red', icon: '🔴', label: 'YUKSEK RISK' },
|
|
27
|
+
critical: { color: 'magenta', icon: '⛔', label: 'KRITIK - GERI ALINAMAZ' },
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const RISK_RANK = { low: 0, medium: 1, high: 2, critical: 3 };
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Komut calistirmadan once risk seviyesi goster, onay iste
|
|
34
|
+
* @param {string} command - komut adi ('reset', 'uninstall', 'memory clear', vs.)
|
|
35
|
+
* @param {object} args - komutun parametreleri
|
|
36
|
+
* @param {string} risk - RISK enum degeri
|
|
37
|
+
* @param {string} reason - neden tehlikeli
|
|
38
|
+
* @returns {Promise<boolean>} - onay verildi mi
|
|
39
|
+
*/
|
|
40
|
+
async function requireApproval(command, args = {}, risk = RISK.HIGH, reason = '') {
|
|
41
|
+
// --force veya --yes flag kontrolu (CLI tarafinda eklenir)
|
|
42
|
+
if (process.env.NATURECO_FORCE === '1' || args.force || args.yes) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const label = RISK_LABELS[risk] || RISK_LABELS.high;
|
|
47
|
+
|
|
48
|
+
console.log();
|
|
49
|
+
console.log(chalk[label.color](` ${label.icon} ${label.label}: ${command}`));
|
|
50
|
+
console.log(chalk.gray(' ' + '─'.repeat(60)));
|
|
51
|
+
console.log(chalk.white(` Komut: ${command}`));
|
|
52
|
+
if (Object.keys(args).length > 0) {
|
|
53
|
+
console.log(chalk.gray(` Argumanlar: ${JSON.stringify(args)}`));
|
|
54
|
+
}
|
|
55
|
+
if (reason) {
|
|
56
|
+
console.log(chalk[label.color](` Neden: ${reason}`));
|
|
57
|
+
}
|
|
58
|
+
console.log(chalk.gray(' ' + '─'.repeat(60)));
|
|
59
|
+
|
|
60
|
+
// Dusuk risk - otomatik onay, sadece mesaj goster
|
|
61
|
+
if (risk === RISK.LOW) {
|
|
62
|
+
console.log(chalk.gray(' Otomatik onaylandi (dusuk risk)'));
|
|
63
|
+
console.log();
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Kritik risk - tam yazim gerekli
|
|
68
|
+
if (risk === RISK.CRITICAL) {
|
|
69
|
+
console.log(chalk.red(' Bu islem geri alinamaz!'));
|
|
70
|
+
const { confirm } = await inquirer.prompt([{
|
|
71
|
+
type: 'input',
|
|
72
|
+
name: 'confirm',
|
|
73
|
+
message: chalk.red(' Devam etmek icin "EVET SIL" yazin (veya Enter ile iptal):'),
|
|
74
|
+
validate: (input) => input === 'EVET SIL' || input === ''
|
|
75
|
+
}]);
|
|
76
|
+
console.log();
|
|
77
|
+
return confirm === 'EVET SIL';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Yuksek ve orta risk - basit onay
|
|
81
|
+
const promptType = risk === RISK.HIGH ? 'confirm' : 'confirm';
|
|
82
|
+
const { ok } = await inquirer.prompt([{
|
|
83
|
+
type: promptType,
|
|
84
|
+
name: 'ok',
|
|
85
|
+
message: chalk[label.color](` Bu komutu calistirmak istediginize emin misiniz?`),
|
|
86
|
+
default: false,
|
|
87
|
+
}]);
|
|
88
|
+
console.log();
|
|
89
|
+
return ok;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Komutun risk seviyesini goster, hizli onay al
|
|
94
|
+
* (sync versiyon, sadece mesaj gosterir)
|
|
95
|
+
*/
|
|
96
|
+
function showRisk(command, args = {}, risk = RISK.MEDIUM, reason = '') {
|
|
97
|
+
const label = RISK_LABELS[risk] || RISK_LABELS.medium;
|
|
98
|
+
console.log();
|
|
99
|
+
console.log(chalk[label.color](` ${label.icon} ${label.label}: ${command}`));
|
|
100
|
+
if (reason) console.log(chalk.gray(` ${reason}`));
|
|
101
|
+
console.log();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
module.exports = {
|
|
105
|
+
RISK,
|
|
106
|
+
RISK_LABELS,
|
|
107
|
+
RISK_RANK,
|
|
108
|
+
requireApproval,
|
|
109
|
+
showRisk,
|
|
110
|
+
};
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* memory_write - Memory'ye fact/kayit yaz (v5.1.1)
|
|
3
|
+
*
|
|
4
|
+
* REPL'in extractMemoryFromMessage ozelligini tool olarak expose eder.
|
|
5
|
+
* Parton'un vizyonu: "Benim asistanim, her seyimi hatirlayacak"
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require("fs");
|
|
9
|
+
const path = require("path");
|
|
10
|
+
const os = require("os");
|
|
11
|
+
|
|
12
|
+
const MEMORY_DIR = path.join(os.homedir(), ".natureco", "memory");
|
|
13
|
+
|
|
14
|
+
function getMemoryFile(username) {
|
|
15
|
+
const name = (username || "default").toLowerCase();
|
|
16
|
+
return path.join(MEMORY_DIR, `${name}.json`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function loadMemory(username) {
|
|
20
|
+
const file = getMemoryFile(username);
|
|
21
|
+
try {
|
|
22
|
+
if (!fs.existsSync(file)) {
|
|
23
|
+
return { name: username || "User", nickname: null, botName: null, facts: [], preferences: [] };
|
|
24
|
+
}
|
|
25
|
+
return JSON.parse(fs.readFileSync(file, "utf8"));
|
|
26
|
+
} catch {
|
|
27
|
+
return { name: username || "User", nickname: null, botName: null, facts: [], preferences: [] };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function saveMemory(username, memory) {
|
|
32
|
+
if (!fs.existsSync(MEMORY_DIR)) fs.mkdirSync(MEMORY_DIR, { recursive: true });
|
|
33
|
+
memory.lastUpdated = new Date().toISOString();
|
|
34
|
+
fs.writeFileSync(getMemoryFile(username), JSON.stringify(memory, null, 2), "utf8");
|
|
35
|
+
return memory;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Score azalt (eski fact'ler zamanla unutuluyor)
|
|
40
|
+
*/
|
|
41
|
+
function decayFacts(memory) {
|
|
42
|
+
if (!memory.facts) return memory;
|
|
43
|
+
const now = Date.now();
|
|
44
|
+
memory.facts = memory.facts.map(f => {
|
|
45
|
+
if (!f.score) f.score = 5;
|
|
46
|
+
// 1 haftadan eski -1, 1 aydan eski -3
|
|
47
|
+
const ageMs = now - new Date(f.updatedAt || f.createdAt || now).getTime();
|
|
48
|
+
const ageDays = ageMs / (1000 * 60 * 60 * 24);
|
|
49
|
+
if (ageDays > 30) f.score = Math.max(0, f.score - 3);
|
|
50
|
+
else if (ageDays > 7) f.score = Math.max(0, f.score - 1);
|
|
51
|
+
return f;
|
|
52
|
+
});
|
|
53
|
+
// score 0 olanlari sil
|
|
54
|
+
memory.facts = memory.facts.filter(f => (f.score || 0) > 0);
|
|
55
|
+
// max 15 fact tut
|
|
56
|
+
memory.facts.sort((a, b) => (b.score || 0) - (a.score || 0));
|
|
57
|
+
memory.facts = memory.facts.slice(0, 15);
|
|
58
|
+
return memory;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* v5.4.9: Memory yazma sonrasi verification — geri oku ve gercekten yazildigini dogrula
|
|
64
|
+
* Self-validation mekanizmasi: tool cagirip "success" demesine ragmen dosya bos olabilir
|
|
65
|
+
*/
|
|
66
|
+
function verifyMemoryWrite(username, expectedFact, expectedBotName) {
|
|
67
|
+
try {
|
|
68
|
+
const memFile = getMemoryFile(username);
|
|
69
|
+
if (!fs.existsSync(memFile)) {
|
|
70
|
+
return { success: false, error: "Memory dosyasi olusturulamadi: " + memFile };
|
|
71
|
+
}
|
|
72
|
+
const mem = JSON.parse(fs.readFileSync(memFile, "utf8"));
|
|
73
|
+
|
|
74
|
+
// Fact verification
|
|
75
|
+
if (expectedFact) {
|
|
76
|
+
const found = (mem.facts || []).some(f => f.value === expectedFact);
|
|
77
|
+
if (!found) {
|
|
78
|
+
return { success: false, error: "Fact memory'de bulunamadi: " + expectedFact };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// BotName verification
|
|
83
|
+
if (expectedBotName && mem.botName !== expectedBotName) {
|
|
84
|
+
return { success: false, error: "BotName guncellenmedi: " + mem.botName };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return { success: true, message: "Memory dogrulandi" };
|
|
88
|
+
} catch (e) {
|
|
89
|
+
return { success: false, error: e.message };
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
function addMemory({ username, fact, score = 5, category = "general", botName, nickname, name }) {
|
|
95
|
+
// Username yoksa ve 'name' parametresi varsa, onu username olarak kullan
|
|
96
|
+
// (Parton'un "patron" diye hitap etmesi durumu icin)
|
|
97
|
+
const effectiveUsername = username || (name && name.toLowerCase()) || 'default';
|
|
98
|
+
if (!effectiveUsername || effectiveUsername === 'default') {
|
|
99
|
+
// Hicbir username yok, default.json'a yaz
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let memory = loadMemory(effectiveUsername);
|
|
103
|
+
memory = decayFacts(memory);
|
|
104
|
+
|
|
105
|
+
// identity updates (botName, nickname, name) — name sadece memory.name, username degil
|
|
106
|
+
if (botName) memory.botName = botName;
|
|
107
|
+
if (nickname !== undefined) memory.nickname = nickname;
|
|
108
|
+
if (name) memory.name = name; // Bu memory.name (kullanici gercek adi), username degil
|
|
109
|
+
|
|
110
|
+
if (fact) {
|
|
111
|
+
// duplicate kontrol
|
|
112
|
+
const existing = memory.facts.find(f => (f.value || f).toLowerCase() === fact.toLowerCase());
|
|
113
|
+
if (existing) {
|
|
114
|
+
existing.score = Math.min(10, (existing.score || 5) + 2);
|
|
115
|
+
existing.updatedAt = new Date().toISOString();
|
|
116
|
+
} else {
|
|
117
|
+
memory.facts.push({
|
|
118
|
+
value: fact,
|
|
119
|
+
score,
|
|
120
|
+
category,
|
|
121
|
+
updatedAt: new Date().toISOString(),
|
|
122
|
+
createdAt: new Date().toISOString(),
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!memory.preferences) memory.preferences = [];
|
|
128
|
+
memory = saveMemory(effectiveUsername, memory);
|
|
129
|
+
|
|
130
|
+
// v5.4.9: Verification - geri oku ve dogrula
|
|
131
|
+
const verifyResult = verifyMemoryWrite(effectiveUsername, fact, botName);
|
|
132
|
+
if (!verifyResult.success) {
|
|
133
|
+
return {
|
|
134
|
+
success: false,
|
|
135
|
+
error: "Memory yazildi ama dogrulanamadi: " + verifyResult.error,
|
|
136
|
+
username: effectiveUsername,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
success: true,
|
|
142
|
+
message: "Memory guncellendi ve dogrulandi",
|
|
143
|
+
username: effectiveUsername,
|
|
144
|
+
verified: true,
|
|
145
|
+
totalFacts: memory.facts.length,
|
|
146
|
+
facts: memory.facts.map(f => ({ value: f.value, score: f.score, category: f.category })),
|
|
147
|
+
botName: memory.botName,
|
|
148
|
+
nickname: memory.nickname,
|
|
149
|
+
name: memory.name,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function clearMemory({ username }) {
|
|
154
|
+
if (!username) return { success: false, error: "username gerekli" };
|
|
155
|
+
const file = getMemoryFile(username);
|
|
156
|
+
if (fs.existsSync(file)) fs.unlinkSync(file);
|
|
157
|
+
return { success: true, message: `Memory temizlendi: ${username}` };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function showMemory({ username }) {
|
|
161
|
+
if (!username) return { success: false, error: "username gerekli" };
|
|
162
|
+
const memory = loadMemory(username);
|
|
163
|
+
return {
|
|
164
|
+
success: true,
|
|
165
|
+
username,
|
|
166
|
+
name: memory.name,
|
|
167
|
+
nickname: memory.nickname,
|
|
168
|
+
botName: memory.botName,
|
|
169
|
+
totalFacts: (memory.facts || []).length,
|
|
170
|
+
facts: memory.facts || [],
|
|
171
|
+
preferences: memory.preferences || [],
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
module.exports = {
|
|
177
|
+
getMemoryFile,
|
|
178
|
+
loadMemory,
|
|
179
|
+
saveMemory,
|
|
180
|
+
decayFacts,
|
|
181
|
+
verifyMemoryWrite,
|
|
182
|
+
addMemory,
|
|
183
|
+
clearMemory,
|
|
184
|
+
showMemory,
|
|
185
|
+
};
|