natureco-cli 5.7.2 → 5.7.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "natureco-cli",
3
- "version": "5.7.2",
3
+ "version": "5.7.4",
4
4
  "description": "OpenClaw'dan daha güvenli, daha hızlı, daha ucuz AI agent CLI. Multi-agent, self-evolving skills, audit log, maliyet optimizasyonu ve NatureCo platform-native.",
5
5
  "bin": {
6
6
  "natureco": "bin/natureco.js"
@@ -24,7 +24,7 @@ const chalk = require('chalk');
24
24
  const tui = require('../utils/tui');
25
25
  const { loadToolDefinitions, toOpenAIFormat, executeTool } = require('../utils/tools');
26
26
  const { accumulateToolCallDeltas, finalizeToolCalls } = require('../utils/streaming-tools');
27
- const { createPasteSafeInput, enableBracketedPaste, disableBracketedPaste, restoreNewlines } = require('../utils/paste-safe-input');
27
+ const { createPasteSafeInput, createOutputFilter, enableBracketedPaste, disableBracketedPaste, restoreNewlines } = require('../utils/paste-safe-input');
28
28
 
29
29
  // v5.4.6: Model adi sizintisini engelle — global'e ata, callback'lerden erisebilir olsun
30
30
  const MODEL_NAMES_TO_HIDE = ['MiniMax-M2.5', 'MiniMaxM2.5', 'minimaxm25', 'Claude-3', 'GPT-4', 'ChatGPT'];
@@ -620,7 +620,7 @@ async function startRepl(args) {
620
620
 
621
621
  const rl = readline.createInterface({
622
622
  input: createPasteSafeInput(process.stdin),
623
- output: process.stdout,
623
+ output: createOutputFilter(process.stdout),
624
624
  prompt: tui.styled('\n You ', { color: tui.PALETTE.primary, bold: true }),
625
625
  terminal: true,
626
626
  });
@@ -728,6 +728,13 @@ async function startRepl(args) {
728
728
  const line = restoreNewlines(input).trim();
729
729
  if (!line) { rl.prompt(); return; }
730
730
 
731
+ // Çok satırlı paste display'ini temizle (readline tek satır modeli
732
+ // yüzünden terminalde biriken eski satırlar kalıcı oluyordu).
733
+ const newlineCount = (line.match(/\n/g) || []).length;
734
+ if (newlineCount > 0) {
735
+ process.stdout.write(`\x1b[${newlineCount + 1}A\x1b[J`);
736
+ }
737
+
731
738
  // Slash komutlar
732
739
  if (line.startsWith('/')) {
733
740
  const parts = line.slice(1).split(/\s+/);
@@ -8,12 +8,27 @@
8
8
  * yapıştırdığında readline bunu 10 ayrı mesaj gibi okur ve her birini hemen
9
9
  * gönderir — kullanıcı paste'i bitirmeden cevaplar gelmeye başlar.
10
10
  *
11
- * Çözüm: Terminalin "bracketed paste" (ESC[200~ ... ESC[201~) işaretleyicilerini
12
- * dinleyip, bu işaretler arasındaki tüm veriyi tek parça olarak topluyoruz.
13
- * İçindeki gerçek satır sonlarını geçici bir placeholder ile değiştirip
14
- * readline'a TEK satır gibi besliyoruz. Kullanıcı gerçekten Enter'a basana kadar
15
- * hiçbir 'line' event'i tetiklenmez. Enter'a basıldığında, alınan satırdaki
16
- * placeholder'lar gerçek "\n" karakterine geri çevrilip mesaj olarak kullanılır.
11
+ * Çözüm: İki katmanlı bir yaklaşım:
12
+ *
13
+ * 1. INPUT KATMANI (createPasteSafeInput):
14
+ * Terminalin "bracketed paste" (ESC[200~ ... ESC[201~) işaretleyicilerini
15
+ * dinleyip, bu işaretler arasındaki tüm veriyi tek parça olarak topluyoruz.
16
+ * Ayrıca terminal-agnostik bir heuristik: çok satırlı büyük chunk'ları da
17
+ * paste olarak algılar. İçindeki gerçek satır sonlarını geçici bir
18
+ * placeholder (NEWLINE_PLACEHOLDER) ile değiştirip readline'a TEK satır gibi
19
+ * besliyoruz. Kullanıcı gerçekten Enter'a basana kadar hiçbir 'line' event'i
20
+ * tetiklenmez.
21
+ *
22
+ * 2. OUTPUT KATMANI (createOutputFilter):
23
+ * Readline'ın echo mekanizması placeholder karakterlerini terminale
24
+ * yazarken araya girer. Bir state machine ile karakterleri placeholder
25
+ * dizisiyle eşleştirir, tam eşleşme olursa terminale \n (yeni satır)
26
+ * yazar. Böylece kullanıcı "␤␤LINEBREAK␤␤" gibi literal placeholder
27
+ * yazıları görmez, satır sonlarını doğal yeni satırlar olarak deneyimler.
28
+ *
29
+ * Enter'a basıldığında, readline'dan gelen placeholder'lı satır,
30
+ * restoreNewlines() ile gerçek \n karakterlerine dönüştürülüp mesaj
31
+ * olarak işlenir.
17
32
  */
18
33
 
19
34
  'use strict';
@@ -164,8 +179,100 @@ function restoreNewlines(line) {
164
179
  return line.split(NEWLINE_PLACEHOLDER).join('\n');
165
180
  }
166
181
 
182
+ /**
183
+ * createOutputFilter — Readline'ın output'unda dolaşan placeholder
184
+ * karakterlerini (NEWLINE_PLACEHOLDER) gerçek satır sonlarına (\n)
185
+ * dönüştüren bir wrapper. Kullanıcı terminalde "␤␤LINEBREAK␤␤" gibi
186
+ * literal placeholder yazıları GÖRMEZ.
187
+ *
188
+ * Kullanım:
189
+ * const outFilter = createOutputFilter(process.stdout);
190
+ * const rl = readline.createInterface({ input, output: outFilter, ... });
191
+ *
192
+ * Çalışma prensibi:
193
+ * Readline, echo mekanizmasıyla her karakteri output.write() ile
194
+ * terminale yazar. Placeholder karakterleri de tek tek yazılır.
195
+ * Bu fonksiyon bir state machine tutar: karakterleri placeholder
196
+ * ile eşleştirir, tam eşleşme olursa \n yazar, olmazsa karakteri
197
+ * olduğu gibi geçirir. Kısmi eşleşmeler (chunk sınırında bölünmüş
198
+ * placeholder) sonraki write()'da tamamlanmak üzere partial
199
+ * buffer'da bekletilir.
200
+ */
201
+ function createOutputFilter(output = process.stdout) {
202
+ let partial = '';
203
+
204
+ const filter = {
205
+ write(data) {
206
+ const str = data.toString('utf8');
207
+ let result = '';
208
+ let i = 0;
209
+
210
+ while (i < str.length) {
211
+ if (partial.length > 0) {
212
+ // Kısmi eşleşme var — devamını bekle
213
+ const expected = NEWLINE_PLACEHOLDER[partial.length];
214
+ const ch = str[i];
215
+ if (ch === expected) {
216
+ partial += ch;
217
+ i++;
218
+ if (partial === NEWLINE_PLACEHOLDER) {
219
+ result += '\n';
220
+ partial = '';
221
+ }
222
+ } else {
223
+ // Eşleşme bozuldu — partial buffer'ı boşalt
224
+ result += partial;
225
+ partial = '';
226
+ // ch'i tekrar dene (yeni placeholder başlangıcı olabilir)
227
+ // continue ile aynı i değerinde else-if'e düş
228
+ }
229
+ } else {
230
+ const ch = str[i];
231
+ if (ch === NEWLINE_PLACEHOLDER[0]) {
232
+ partial = ch;
233
+ i++;
234
+ // Tek karakterlik placeholder değil, bekle
235
+ } else {
236
+ result += ch;
237
+ i++;
238
+ }
239
+ }
240
+ }
241
+
242
+ if (result) return output.write(result);
243
+ return true;
244
+ },
245
+
246
+ end(...args) {
247
+ if (partial) {
248
+ output.write(partial);
249
+ partial = '';
250
+ }
251
+ return output.end(...args);
252
+ },
253
+
254
+ get columns() { return output.columns; },
255
+ get rows() { return output.rows; },
256
+ get isTTY() { return output.isTTY; },
257
+
258
+ on(...args) { return output.on(...args); },
259
+ off(...args) { return output.off ? output.off(...args) : undefined; },
260
+ addListener(...args) { return output.addListener(...args); },
261
+ removeListener(...args) { return output.removeListener(...args); },
262
+ emit(...args) { return output.emit(...args); },
263
+ getColorDepth(...args) {
264
+ return typeof output.getColorDepth === 'function'
265
+ ? output.getColorDepth(...args)
266
+ : undefined;
267
+ },
268
+ };
269
+
270
+ return filter;
271
+ }
272
+
167
273
  module.exports = {
168
274
  createPasteSafeInput,
275
+ createOutputFilter,
169
276
  enableBracketedPaste,
170
277
  disableBracketedPaste,
171
278
  restoreNewlines,