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.
@@ -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
- // Onay
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
+ };