natureco-cli 2.23.32 → 4.4.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.
Files changed (174) hide show
  1. package/AUDIT.md +178 -0
  2. package/CHANGELOG.md +422 -0
  3. package/DEPLOY_v2.0.0.md +400 -0
  4. package/README.md +159 -1
  5. package/bin/natureco.js +170 -8
  6. package/package.json +43 -11
  7. package/skills/code-review/SKILL.md +0 -0
  8. package/skills/summarize/SKILL.md +0 -0
  9. package/skills/translate/SKILL.md +0 -0
  10. package/src/commands/acp.js +0 -0
  11. package/src/commands/admin-rpc.js +0 -0
  12. package/src/commands/agent.js +0 -0
  13. package/src/commands/agents.js +0 -0
  14. package/src/commands/approvals.js +0 -0
  15. package/src/commands/ask.js +0 -0
  16. package/src/commands/audit.js +209 -0
  17. package/src/commands/backup.js +0 -0
  18. package/src/commands/bonjour.js +0 -0
  19. package/src/commands/bots.js +0 -0
  20. package/src/commands/browser.js +0 -0
  21. package/src/commands/capability.js +0 -0
  22. package/src/commands/channels.js +0 -0
  23. package/src/commands/chat.js +0 -0
  24. package/src/commands/clawbot.js +0 -0
  25. package/src/commands/clickclack.js +0 -0
  26. package/src/commands/code.js +0 -0
  27. package/src/commands/commands.js +0 -0
  28. package/src/commands/commitments.js +0 -0
  29. package/src/commands/completion.js +0 -0
  30. package/src/commands/config.js +0 -0
  31. package/src/commands/configure.js +0 -0
  32. package/src/commands/cost.js +210 -0
  33. package/src/commands/crestodian.js +0 -0
  34. package/src/commands/cron.js +0 -0
  35. package/src/commands/daemon.js +0 -0
  36. package/src/commands/dashboard.js +126 -45
  37. package/src/commands/device-pair.js +0 -0
  38. package/src/commands/devices.js +0 -0
  39. package/src/commands/directory.js +0 -0
  40. package/src/commands/discord.js +0 -0
  41. package/src/commands/dns.js +0 -0
  42. package/src/commands/docs.js +0 -0
  43. package/src/commands/doctor.js +134 -15
  44. package/src/commands/exec-policy.js +0 -0
  45. package/src/commands/gateway-server.js +0 -0
  46. package/src/commands/gateway.js +0 -0
  47. package/src/commands/git.js +0 -0
  48. package/src/commands/health.js +0 -0
  49. package/src/commands/help.js +0 -0
  50. package/src/commands/hooks.js +0 -0
  51. package/src/commands/imessage.js +0 -0
  52. package/src/commands/infer.js +0 -0
  53. package/src/commands/init.js +0 -0
  54. package/src/commands/irc.js +0 -0
  55. package/src/commands/login.js +0 -0
  56. package/src/commands/logout.js +0 -0
  57. package/src/commands/logs.js +0 -0
  58. package/src/commands/mattermost.js +0 -0
  59. package/src/commands/mcp.js +0 -0
  60. package/src/commands/medium.js +206 -0
  61. package/src/commands/memory-cmd.js +0 -0
  62. package/src/commands/memory.js +0 -0
  63. package/src/commands/message.js +0 -0
  64. package/src/commands/migrate.js +0 -0
  65. package/src/commands/models.js +0 -0
  66. package/src/commands/naturehub.js +156 -0
  67. package/src/commands/node.js +0 -0
  68. package/src/commands/nodes.js +0 -0
  69. package/src/commands/oc-path.js +0 -0
  70. package/src/commands/onboard.js +0 -0
  71. package/src/commands/open-prose.js +0 -0
  72. package/src/commands/pairing.js +0 -0
  73. package/src/commands/path.js +0 -0
  74. package/src/commands/plugins.js +0 -0
  75. package/src/commands/policy.js +0 -0
  76. package/src/commands/proxy.js +0 -0
  77. package/src/commands/qr.js +0 -0
  78. package/src/commands/reset.js +0 -0
  79. package/src/commands/run.js +0 -0
  80. package/src/commands/sandbox.js +0 -0
  81. package/src/commands/secrets.js +0 -0
  82. package/src/commands/security.js +0 -0
  83. package/src/commands/seo.js +268 -0
  84. package/src/commands/sessions.js +0 -0
  85. package/src/commands/setup.js +6 -6
  86. package/src/commands/signal.js +0 -0
  87. package/src/commands/skills.js +82 -1
  88. package/src/commands/slack.js +0 -0
  89. package/src/commands/sms.js +0 -0
  90. package/src/commands/status.js +0 -0
  91. package/src/commands/system.js +0 -0
  92. package/src/commands/tasks.js +0 -0
  93. package/src/commands/team.js +171 -0
  94. package/src/commands/telegram.js +0 -0
  95. package/src/commands/terminal.js +0 -0
  96. package/src/commands/thread-ownership.js +0 -0
  97. package/src/commands/transcripts.js +0 -0
  98. package/src/commands/tui.js +0 -0
  99. package/src/commands/ultrareview.js +0 -0
  100. package/src/commands/uninstall.js +0 -0
  101. package/src/commands/update.js +0 -0
  102. package/src/commands/voice.js +0 -0
  103. package/src/commands/vydra.js +0 -0
  104. package/src/commands/web-fetch.js +0 -0
  105. package/src/commands/webhooks.js +0 -0
  106. package/src/commands/whatsapp.js +0 -0
  107. package/src/commands/wiki.js +0 -0
  108. package/src/commands/workboard.js +0 -0
  109. package/src/commands/xp.js +194 -0
  110. package/src/tools/audio_understanding.js +0 -0
  111. package/src/tools/bash.js +0 -0
  112. package/src/tools/browser.js +0 -0
  113. package/src/tools/canvas.js +0 -0
  114. package/src/tools/document_extract.js +0 -0
  115. package/src/tools/duckduckgo.js +0 -0
  116. package/src/tools/exa_search.js +0 -0
  117. package/src/tools/filesystem.js +0 -0
  118. package/src/tools/firecrawl.js +0 -0
  119. package/src/tools/git.js +0 -0
  120. package/src/tools/http.js +0 -0
  121. package/src/tools/image_generation.js +0 -0
  122. package/src/tools/list_dir.js +0 -0
  123. package/src/tools/llm_task.js +43 -11
  124. package/src/tools/media_understanding.js +0 -0
  125. package/src/tools/music_generation.js +0 -0
  126. package/src/tools/parallel_search.js +0 -0
  127. package/src/tools/phone_control.js +0 -0
  128. package/src/tools/phone_control_enhanced.js +0 -0
  129. package/src/tools/read_file.js +0 -0
  130. package/src/tools/searxng.js +0 -0
  131. package/src/tools/speech_to_text.js +0 -0
  132. package/src/tools/text_to_speech.js +0 -0
  133. package/src/tools/thread_ownership.js +0 -0
  134. package/src/tools/video_generation.js +0 -0
  135. package/src/tools/web_readability.js +0 -0
  136. package/src/tools/web_search.js +0 -0
  137. package/src/tools/write_file.js +0 -0
  138. package/src/utils/agents-md.js +0 -0
  139. package/src/utils/agents.js +0 -0
  140. package/src/utils/api.js +5 -1
  141. package/src/utils/approvals.js +0 -0
  142. package/src/utils/audit.js +199 -0
  143. package/src/utils/background.js +0 -0
  144. package/src/utils/baileys.js +0 -0
  145. package/src/utils/branding.js +136 -0
  146. package/src/utils/commands.js +0 -0
  147. package/src/utils/config.js +0 -0
  148. package/src/utils/cost-tracker.js +360 -0
  149. package/src/utils/cron.js +0 -0
  150. package/src/utils/dashboard-server.js +284 -0
  151. package/src/utils/errors.js +0 -0
  152. package/src/utils/format.js +7 -10
  153. package/src/utils/gateway-ws.js +0 -0
  154. package/src/utils/headless.js +0 -0
  155. package/src/utils/history.js +0 -0
  156. package/src/utils/hooks.js +0 -0
  157. package/src/utils/inquirer-wrapper.js +0 -0
  158. package/src/utils/mcp-client.js +0 -0
  159. package/src/utils/mcp.js +0 -0
  160. package/src/utils/memory.js +0 -0
  161. package/src/utils/parallel-tools.js +0 -0
  162. package/src/utils/path-utils.js +0 -0
  163. package/src/utils/pattern-detector.js +314 -0
  164. package/src/utils/plugin-registry.js +0 -0
  165. package/src/utils/secret-scanner.js +204 -0
  166. package/src/utils/secrets.js +0 -0
  167. package/src/utils/sessions.js +0 -0
  168. package/src/utils/skills.js +0 -0
  169. package/src/utils/sub-agent.js +6 -0
  170. package/src/utils/token-budget.js +0 -0
  171. package/src/utils/tool-adapter.js +0 -0
  172. package/src/utils/tool-runner.js +0 -0
  173. package/src/utils/tui.js +750 -0
  174. package/src/utils/web-fetch.js +0 -0
@@ -0,0 +1,750 @@
1
+ /**
2
+ * NatureCo CLI — Terminal UI Engine (Phase 9 — "DESKTOP-LIKE")
3
+ *
4
+ * Hedef: Kullanıcı terminal açık olduğunu unutsun.
5
+ * PC uygulaması hissi için: animasyonlar, progress, interaktif box'lar,
6
+ * keyboard shortcuts, tab navigation, breadcrumb, status bar, theme.
7
+ *
8
+ * Sıfır dependency — sadece ANSI escape kodları + readline.
9
+ * Ink/blessed kurmuyoruz (bundle boyutu, startup hızı için).
10
+ */
11
+
12
+ // ════════════════════════════════════════════════════════════
13
+ // ANSI Escape Sequences
14
+ // ════════════════════════════════════════════════════════════
15
+
16
+ const ESC = '\x1b';
17
+ const CSI = ESC + '[';
18
+
19
+ // Cursor
20
+ const CURSOR = {
21
+ hide: CSI + '?25l',
22
+ show: CSI + '?25h',
23
+ save: ESC + '7',
24
+ restore: ESC + '8',
25
+ home: CSI + 'H',
26
+ pos: (row, col) => CSI + `${row};${col}H`,
27
+ up: (n = 1) => CSI + n + 'A',
28
+ down: (n = 1) => CSI + n + 'B',
29
+ right: (n = 1) => CSI + n + 'C',
30
+ left: (n = 1) => CSI + n + 'D',
31
+ nextLine: CSI + '1E',
32
+ prevLine: CSI + '1F',
33
+ clearLine: CSI + '2K',
34
+ clearLineRight: CSI + '0K',
35
+ clearScreen: CSI + '2J',
36
+ clearScreenDown: CSI + '0J',
37
+ clearScreenUp: CSI + '1J',
38
+ };
39
+
40
+ // Screen modes
41
+ const SCREEN = {
42
+ altEnter: CSI + '?1049h', // Alternate screen buffer
43
+ altExit: CSI + '?1049l',
44
+ rawEnable: () => process.stdin.setRawMode && process.stdin.setRawMode(true),
45
+ rawDisable: () => process.stdin.setRawMode && process.stdin.setRawMode(false),
46
+ };
47
+
48
+ // Mouse (gerekirse)
49
+ const MOUSE = {
50
+ enable: CSI + '?1000h' + CSI + '?1006h',
51
+ disable: CSI + '?1006l' + CSI + '?1000l',
52
+ };
53
+
54
+ // ════════════════════════════════════════════════════════════
55
+ // Capability Detection
56
+ // ════════════════════════════════════════════════════════════
57
+
58
+ const CAPS = {
59
+ color: false,
60
+ trueColor: false,
61
+ unicode: false,
62
+ width: 80,
63
+ height: 24,
64
+ isTTY: false,
65
+ };
66
+
67
+ function detectCapabilities() {
68
+ CAPS.isTTY = !!process.stdout.isTTY;
69
+
70
+ // Renk desteği
71
+ if (process.env.NO_COLOR || process.env.CI) {
72
+ CAPS.color = false;
73
+ CAPS.trueColor = false;
74
+ } else if (process.env.FORCE_COLOR === '0') {
75
+ CAPS.color = false;
76
+ } else {
77
+ const term = (process.env.TERM || '').toLowerCase();
78
+ CAPS.color = CAPS.isTTY && !term.includes('dumb');
79
+ CAPS.trueColor = CAPS.isTTY && (
80
+ process.env.COLORTERM === 'truecolor' ||
81
+ process.env.COLORTERM === '24bit' ||
82
+ term.includes('256color') ||
83
+ term.includes('truecolor')
84
+ );
85
+ }
86
+
87
+ // Unicode desteği
88
+ const lang = process.env.LANG || process.env.LC_ALL || '';
89
+ CAPS.unicode = !/^(C|POSIX)/i.test(lang);
90
+
91
+ // Terminal boyutu
92
+ if (CAPS.isTTY && process.stdout.columns) {
93
+ CAPS.width = process.stdout.columns;
94
+ CAPS.height = process.stdout.rows;
95
+ }
96
+
97
+ return CAPS;
98
+ }
99
+
100
+ // ════════════════════════════════════════════════════════════
101
+ // Color Palette — NatureCo Brand
102
+ // ════════════════════════════════════════════════════════════
103
+
104
+ const PALETTE = {
105
+ // Brand renkleri
106
+ primary: '#22c55e', // NatureCo yeşil
107
+ secondary: '#0ea5e9', // sky blue
108
+ accent: '#f59e0b', // amber
109
+ success: '#10b981',
110
+ warning: '#eab308',
111
+ danger: '#ef4444',
112
+ info: '#3b82f6',
113
+ muted: '#64748b',
114
+ text: '#e2e8f0',
115
+ bg: '#0f172a',
116
+ bgAlt: '#1e293b',
117
+ border: '#334155',
118
+ };
119
+
120
+ const STYLE = {
121
+ reset: '\x1b[0m',
122
+ bold: '\x1b[1m',
123
+ dim: '\x1b[2m',
124
+ italic: '\x1b[3m',
125
+ underline: '\x1b[4m',
126
+ blink: '\x1b[5m',
127
+ reverse: '\x1b[7m',
128
+ hidden: '\x1b[8m',
129
+ strikethrough: '\x1b[9m',
130
+ };
131
+
132
+ // True color helper
133
+ function fg(hex) {
134
+ if (!CAPS.trueColor) return '';
135
+ const [r, g, b] = hexToRgb(hex);
136
+ return `\x1b[38;2;${r};${g};${b}m`;
137
+ }
138
+ function bg(hex) {
139
+ if (!CAPS.trueColor) return '';
140
+ const [r, g, b] = hexToRgb(hex);
141
+ return `\x1b[48;2;${r};${g};${b}m`;
142
+ }
143
+ function hexToRgb(hex) {
144
+ const h = hex.replace('#', '');
145
+ return [
146
+ parseInt(h.slice(0, 2), 16),
147
+ parseInt(h.slice(2, 4), 16),
148
+ parseInt(h.slice(4, 6), 16),
149
+ ];
150
+ }
151
+
152
+ // 256-color fallback
153
+ function fg256(n) { return CAPS.color ? `\x1b[38;5;${n}m` : ''; }
154
+ function bg256(n) { return CAPS.color ? `\x1b[48;5;${n}m` : ''; }
155
+
156
+ // Styled text helper
157
+ function styled(text, opts = {}) {
158
+ if (!CAPS.color && !CAPS.trueColor) return text;
159
+ let code = '';
160
+ if (opts.color) code += typeof opts.color === 'string' && opts.color.startsWith('#') ? fg(opts.color) : fg256(opts.color);
161
+ if (opts.bg) code += typeof opts.bg === 'string' && opts.bg.startsWith('#') ? bg(opts.bg) : bg256(opts.bg);
162
+ if (opts.bold) code += STYLE.bold;
163
+ if (opts.dim) code += STYLE.dim;
164
+ if (opts.italic) code += STYLE.italic;
165
+ if (opts.underline) code += STYLE.underline;
166
+ return `${code}${text}${STYLE.reset}`;
167
+ }
168
+
169
+ // Renkli kısayollar
170
+ const C = {
171
+ brand: (t) => styled(t, { color: PALETTE.primary, bold: true }),
172
+ sky: (t) => styled(t, { color: PALETTE.secondary }),
173
+ amber: (t) => styled(t, { color: PALETTE.accent }),
174
+ green: (t) => styled(t, { color: PALETTE.success }),
175
+ red: (t) => styled(t, { color: PALETTE.danger }),
176
+ yellow: (t) => styled(t, { color: PALETTE.warning }),
177
+ blue: (t) => styled(t, { color: PALETTE.info }),
178
+ muted: (t) => styled(t, { color: PALETTE.muted }),
179
+ text: (t) => styled(t, { color: PALETTE.text }),
180
+ dim: (t) => styled(t, { dim: true }),
181
+ bold: (t) => styled(t, { bold: true }),
182
+ };
183
+
184
+ // ════════════════════════════════════════════════════════════
185
+ // Box Drawing — Unicode borders
186
+ // ════════════════════════════════════════════════════════════
187
+
188
+ const BORDER = {
189
+ single: { tl: '┌', tr: '┐', bl: '└', br: '┘', h: '─', v: '│', tDown: '┬', tUp: '┴', tRight: '├', tLeft: '┤', cross: '┼' },
190
+ double: { tl: '╔', tr: '╗', bl: '╚', br: '╝', h: '═', v: '║', tDown: '╦', tUp: '╩', tRight: '╠', tLeft: '╣', cross: '╬' },
191
+ round: { tl: '╭', tr: '╮', bl: '╰', br: '╯', h: '─', v: '│', tDown: '┬', tUp: '┴', tRight: '├', tLeft: '┤', cross: '┼' },
192
+ heavy: { tl: '┏', tr: '┓', bl: '┗', br: '┛', h: '━', v: '┃', tDown: '┳', tUp: '┻', tRight: '┣', tLeft: '┫', cross: '╋' },
193
+ };
194
+
195
+ function box(width, height, options = {}) {
196
+ const {
197
+ style = 'round',
198
+ title = '',
199
+ titleColor = PALETTE.primary,
200
+ borderColor = PALETTE.border,
201
+ bg: bgColor = null,
202
+ padding = 1,
203
+ } = options;
204
+
205
+ const b = BORDER[style] || BORDER.round;
206
+ const w = Math.max(10, width);
207
+ const h = Math.max(3, height);
208
+
209
+ const bc = CAPS.trueColor ? fg(borderColor) : '';
210
+ const reset = STYLE.reset;
211
+ const tColor = CAPS.trueColor ? fg(titleColor) : '';
212
+
213
+ const lines = [];
214
+ // Üst kenar
215
+ const topTitle = title ? ` ${title} ` : '';
216
+ const topFill = w - 2 - topTitle.length;
217
+ const leftFill = Math.floor(topFill / 2);
218
+ const rightFill = topFill - leftFill;
219
+ lines.push(bc + b.tl + b.h.repeat(leftFill) + tColor + topTitle + bc + b.h.repeat(rightFill) + b.tr + reset);
220
+
221
+ // İçeride boş satırlar (doldurulacak)
222
+ for (let i = 1; i < h - 1; i++) {
223
+ lines.push(bc + b.v + reset + ' '.repeat(w - 2) + bc + b.v + reset);
224
+ }
225
+
226
+ // Alt kenar
227
+ lines.push(bc + b.bl + b.h.repeat(w - 2) + b.br + reset);
228
+
229
+ return lines.join('\n');
230
+ }
231
+
232
+ // ════════════════════════════════════════════════════════════
233
+ // Progress Bar & Spinner
234
+ // ════════════════════════════════════════════════════════════
235
+
236
+ const SPINNER_FRAMES = {
237
+ dots: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'],
238
+ line: ['|', '/', '-', '\\'],
239
+ arc: ['◜', '◠', '◝', '◞', '◡', '◟'],
240
+ pulse: ['█', '▓', '▒', '░', '▒', '▓'],
241
+ bounce: ['⠁', '⠂', '⠄', '⠂'],
242
+ grow: ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█', '▇', '▆', '▅', '▄', '▃', '▂'],
243
+ circle: ['◐', '◓', '◑', '◒'],
244
+ arrow: ['←', '↖', '↑', '↗', '→', '↘', '↓', '↙'],
245
+ };
246
+
247
+ function progressBar(current, total, options = {}) {
248
+ const { width = 30, showPercent = true, showETA = false, fillChar = '█', emptyChar = '░' } = options;
249
+ const pct = Math.min(1, Math.max(0, current / total));
250
+ const filled = Math.floor(pct * width);
251
+ const empty = width - filled;
252
+ const bar = C.brand(fillChar.repeat(filled)) + C.muted(emptyChar.repeat(empty));
253
+ let suffix = '';
254
+ if (showPercent) suffix += ` ${(pct * 100).toFixed(0).padStart(3)}%`;
255
+ if (showETA && options.startTime) {
256
+ const elapsed = (Date.now() - options.startTime) / 1000;
257
+ const remaining = pct > 0 ? (elapsed / pct - elapsed) : 0;
258
+ suffix += ` ETA: ${formatDuration(remaining)}`;
259
+ }
260
+ return `${bar}${suffix}`;
261
+ }
262
+
263
+ function formatDuration(seconds) {
264
+ if (!isFinite(seconds) || seconds < 0) return '--:--';
265
+ if (seconds < 60) return `${Math.round(seconds)}s`;
266
+ if (seconds < 3600) return `${Math.floor(seconds / 60)}m ${Math.round(seconds % 60)}s`;
267
+ return `${Math.floor(seconds / 3600)}h ${Math.floor((seconds % 3600) / 60)}m`;
268
+ }
269
+
270
+ // ════════════════════════════════════════════════════════════
271
+ // Animated Spinner — async/await ile
272
+ // ════════════════════════════════════════════════════════════
273
+
274
+ class Spinner {
275
+ constructor(text = '', options = {}) {
276
+ this.text = text;
277
+ this.style = options.style || 'dots';
278
+ this.frames = SPINNER_FRAMES[this.style] || SPINNER_FRAMES.dots;
279
+ this.interval = options.interval || 80;
280
+ this.timer = null;
281
+ this.index = 0;
282
+ }
283
+ start() {
284
+ if (!CAPS.isTTY) {
285
+ process.stdout.write(this.text + '... ');
286
+ return this;
287
+ }
288
+ process.stdout.write(CURSOR.hide);
289
+ this.timer = setInterval(() => {
290
+ const frame = C.brand(this.frames[this.index]) + ' ' + C.text(this.text);
291
+ process.stdout.write('\r' + CURSOR.clearLineRight + frame);
292
+ this.index = (this.index + 1) % this.frames.length;
293
+ }, this.interval);
294
+ return this;
295
+ }
296
+ stop(finalText = null) {
297
+ if (this.timer) clearInterval(this.timer);
298
+ if (CAPS.isTTY) {
299
+ process.stdout.write(CURSOR.show + '\r' + CURSOR.clearLineRight);
300
+ }
301
+ if (finalText) console.log(finalText);
302
+ return this;
303
+ }
304
+ update(text) {
305
+ this.text = text;
306
+ return this;
307
+ }
308
+ }
309
+
310
+ async function withSpinner(text, fn, options = {}) {
311
+ const spinner = new Spinner(text, options).start();
312
+ try {
313
+ const result = await fn(spinner);
314
+ spinner.stop(options.successText || C.green('✓ ' + text));
315
+ return result;
316
+ } catch (err) {
317
+ spinner.stop(C.red('✗ ' + text) + C.red('\n ' + err.message));
318
+ throw err;
319
+ }
320
+ }
321
+
322
+ // ════════════════════════════════════════════════════════════
323
+ // Banner / Splash Screen
324
+ // ════════════════════════════════════════════════════════════
325
+
326
+ function bigBanner(text, color = PALETTE.primary) {
327
+ // Banner font: minimal ASCII
328
+ const lines = text.split('\n');
329
+ const out = [];
330
+ for (const line of lines) {
331
+ out.push(C.text(line, { color }));
332
+ }
333
+ return out.join('\n');
334
+ }
335
+
336
+ // Smooth fade-in effect (line by line)
337
+ async function fadeIn(lines, delay = 30) {
338
+ for (const line of lines) {
339
+ console.log(line);
340
+ if (CAPS.isTTY) await sleep(delay);
341
+ }
342
+ }
343
+
344
+ function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
345
+
346
+ // ════════════════════════════════════════════════════════════
347
+ // Status Bar (footer / header)
348
+ // ════════════════════════════════════════════════════════════
349
+
350
+ function statusBar(items, options = {}) {
351
+ // items: [{ label, value, color }]
352
+ const separator = C.muted(' │ ');
353
+ const parts = items.map(({ label, value, color }) => {
354
+ const l = C.muted(label);
355
+ const v = typeof color === 'string' ? styled(value, { color }) : value;
356
+ return `${l} ${v}`;
357
+ });
358
+ return parts.join(separator);
359
+ }
360
+
361
+ function breadcrumb(path) {
362
+ // path: ['home', 'naturehub', 'post']
363
+ return path.map((seg, i) => {
364
+ const isLast = i === path.length - 1;
365
+ return isLast ? C.brand(seg) : C.muted(seg);
366
+ }).join(C.muted(' › '));
367
+ }
368
+
369
+ // ════════════════════════════════════════════════════════════
370
+ // Table — gelişmiş, border + color + alignment
371
+ // ════════════════════════════════════════════════════════════
372
+
373
+ function table(data, columns, options = {}) {
374
+ const reset = STYLE.reset;
375
+ const { borderStyle = 'single', headerColor = PALETTE.primary, zebra = true } = options;
376
+ const b = BORDER[borderStyle] || BORDER.single;
377
+
378
+ // Sütun genişliklerini hesapla
379
+ const widths = columns.map(col => {
380
+ const headerLen = stripAnsi(col.label || col.key).length;
381
+ const maxDataLen = Math.max(0, ...data.map(row => {
382
+ const val = col.render ? col.render(row) : (row[col.key] || '');
383
+ return stripAnsi(String(val)).length;
384
+ }));
385
+ return Math.max(headerLen, maxDataLen, col.minWidth || 3);
386
+ });
387
+
388
+ const lines = [];
389
+ const bc = CAPS.trueColor ? fg(PALETTE.border) : '';
390
+
391
+ // Üst
392
+ const topBorder = b.tl + b.h.repeat(widths.reduce((s, w) => s + w + 3, 1) - 1) + b.tr;
393
+ lines.push(bc + topBorder + STYLE.reset);
394
+
395
+ // Header
396
+ const headerCells = columns.map((col, i) => {
397
+ const text = (col.label || col.key).padEnd(widths[i]);
398
+ return styled(text, { color: headerColor, bold: true });
399
+ });
400
+ lines.push(bc + b.v + reset + ' ' + headerCells.join(' ' + bc + b.v + reset + ' ') + ' ' + bc + b.v + reset);
401
+
402
+ // Header alt border
403
+ const midBorder = b.tRight + widths.map(w => b.h.repeat(w + 2)).join(b.tDown) + b.tLeft;
404
+ lines.push(bc + midBorder + STYLE.reset);
405
+
406
+ // Veri satırları
407
+ data.forEach((row, ri) => {
408
+ const bgColor = zebra && ri % 2 === 1 ? bg(PALETTE.bgAlt) : '';
409
+ const cells = columns.map((col, i) => {
410
+ const val = col.render ? col.render(row) : (row[col.key] || '');
411
+ const text = String(val).padEnd(widths[i]);
412
+ return bgColor + text + STYLE.reset;
413
+ });
414
+ lines.push(bc + b.v + reset + ' ' + cells.join(' ' + bc + b.v + reset + ' ') + ' ' + bc + b.v + reset);
415
+ });
416
+
417
+ // Alt
418
+ const botBorder = b.bl + b.h.repeat(widths.reduce((s, w) => s + w + 3, 1) - 1) + b.br;
419
+ lines.push(bc + botBorder + STYLE.reset);
420
+
421
+ return lines.join('\n');
422
+ }
423
+
424
+ function stripAnsi(str) {
425
+ return String(str).replace(/\x1b\[[0-9;]*m/g, '');
426
+ }
427
+
428
+ // ════════════════════════════════════════════════════════════
429
+ // Keyboard Input
430
+ // ════════════════════════════════════════════════════════════
431
+
432
+ function readKey() {
433
+ return new Promise((resolve) => {
434
+ if (!CAPS.isTTY) {
435
+ process.stdin.once('data', (chunk) => {
436
+ const key = chunk.toString();
437
+ resolve(parseKey(key));
438
+ });
439
+ return;
440
+ }
441
+ SCREEN.rawEnable();
442
+ process.stdin.once('data', (chunk) => {
443
+ SCREEN.rawDisable();
444
+ resolve(parseKey(chunk.toString()));
445
+ });
446
+ });
447
+ }
448
+
449
+ function parseKey(str) {
450
+ // Özel tuşlar
451
+ if (str === '\x1b[A' || str === '\x1bOA') return { type: 'arrow', direction: 'up' };
452
+ if (str === '\x1b[B' || str === '\x1bOB') return { type: 'arrow', direction: 'down' };
453
+ if (str === '\x1b[C' || str === '\x1bOC') return { type: 'arrow', direction: 'right' };
454
+ if (str === '\x1b[D' || str === '\x1bOD') return { type: 'arrow', direction: 'left' };
455
+ if (str === '\x1b[H') return { type: 'home' };
456
+ if (str === '\x1b[F') return { type: 'end' };
457
+ if (str === '\t') return { type: 'tab' };
458
+ if (str === '\r' || str === '\n') return { type: 'enter' };
459
+ if (str === '\x1b' || str === '\x1b\x1b') return { type: 'escape' };
460
+ if (str === '\x03') return { type: 'ctrl-c' };
461
+ if (str === '\x1b[5~') return { type: 'page-up' };
462
+ if (str === '\x1b[6~') return { type: 'page-down' };
463
+ // Normal karakter
464
+ if (str.length === 1) return { type: 'char', value: str };
465
+ return { type: 'unknown', raw: str };
466
+ }
467
+
468
+ // ════════════════════════════════════════════════════════════
469
+ // Help Overlay (kısayollar)
470
+ // ════════════════════════════════════════════════════════════
471
+
472
+ function helpOverlay(shortcuts) {
473
+ const lines = [C.bold(C.brand(' ⌨️ Klavye Kısayolları\n'))];
474
+ for (const [key, desc] of Object.entries(shortcuts)) {
475
+ lines.push(` ${styled(key.padEnd(12), { bg: PALETTE.bgAlt, color: PALETTE.text })} ${C.muted(desc)}`);
476
+ }
477
+ return lines.join('\n');
478
+ }
479
+
480
+ // ════════════════════════════════════════════════════════════
481
+ // Splash Screen — Animasyonlu açılış
482
+ // ════════════════════════════════════════════════════════════
483
+
484
+ async function splash(options = {}) {
485
+ const {
486
+ title = 'NatureCo CLI',
487
+ version = '4.2.0',
488
+ subtitle = 'OpenClaw\'dan daha güvenli, daha hızlı, daha ucuz',
489
+ duration = 1500,
490
+ } = options;
491
+
492
+ if (!CAPS.isTTY) {
493
+ console.log(`${title} v${version}`);
494
+ console.log(subtitle);
495
+ return;
496
+ }
497
+
498
+ // Logo satırları (ASCII art)
499
+ const logo = [
500
+ '███╗ ██╗ █████╗ ████████╗██╗ ██╗██████╗ ███████╗ ██████╗ ██████╗ ',
501
+ '████╗ ██║██╔══██╗╚══██╔══╝██║ ██║██╔══██╗██╔════╝██╔═══██╗██╔═══██╗',
502
+ '██╔██╗ ██║███████║ ██║ ██║ ██║██████╔╝█████╗ ██║ ██║██║ ██║',
503
+ '██║╚██╗██║██╔══██║ ██║ ██║ ██║██╔══██╗██╔══╝ ██║ ██║██║ ██║',
504
+ '██║ ╚████║██║ ██║ ██║ ╚██████╔╝██║ ██║███████╗╚██████╔╝╚██████╔╝',
505
+ '╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═════╝ ',
506
+ ];
507
+
508
+ // Animasyon: satır satır fade-in
509
+ process.stdout.write('\n');
510
+ for (const line of logo) {
511
+ process.stdout.write(' ' + styled(line, { color: PALETTE.primary, bold: true }) + '\n');
512
+ await sleep(50);
513
+ }
514
+
515
+ // Alt yazı fade-in
516
+ await sleep(200);
517
+ process.stdout.write('\n');
518
+ process.stdout.write(' ' + styled(title + ' v' + version, { color: PALETTE.text, bold: true }) + '\n');
519
+ process.stdout.write(' ' + styled(subtitle, { color: PALETTE.muted, italic: true }) + '\n');
520
+ process.stdout.write('\n');
521
+
522
+ // Loading dots animasyonu
523
+ const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
524
+ const startTime = Date.now();
525
+ let i = 0;
526
+ while (Date.now() - startTime < duration) {
527
+ const elapsed = Math.floor((Date.now() - startTime) / 100);
528
+ process.stdout.write('\r ' + styled(frames[i % frames.length], { color: PALETTE.primary, bold: true }) + ' ' +
529
+ styled('Hazır', { color: PALETTE.muted }) +
530
+ ' '.repeat(10));
531
+ i++;
532
+ await sleep(80);
533
+ }
534
+
535
+ // Final clear
536
+ process.stdout.write('\r' + ' '.repeat(60) + '\r');
537
+ }
538
+
539
+ // ════════════════════════════════════════════════════════════
540
+ // Welcome Card — PC uygulaması açılış hissi
541
+ // ════════════════════════════════════════════════════════════
542
+
543
+ function welcomeCard({ version, user, status, tips }) {
544
+ const w = Math.min(70, CAPS.width - 4);
545
+ const lines = [];
546
+
547
+ // Üst çerçeve
548
+ lines.push(C.brand('╭' + '─'.repeat(w - 2) + '╮'));
549
+
550
+ // Logo (küçük)
551
+ const logo = '🌿 NatureCo CLI';
552
+ const ver = `v${version}`;
553
+ const titlePadding = w - 2 - logo.length - ver.length - 2;
554
+ lines.push(C.brand('│ ') + C.bold(logo) + ' '.repeat(titlePadding) + C.muted(ver) + C.brand(' │'));
555
+
556
+ // Ayraç
557
+ lines.push(C.brand('├' + '─'.repeat(w - 2) + '┤'));
558
+
559
+ // Status satırları
560
+ const statusLines = [
561
+ ['Kullanıcı', user?.name || C.amber('(setup gerekli)')],
562
+ ['Sürüm', C.text(version)],
563
+ ['Durum', status],
564
+ ['Çalışma dizini', C.dim(process.cwd())],
565
+ ];
566
+ for (const [label, value] of statusLines) {
567
+ const line = ` ${C.muted(label.padEnd(16))} ${value}`;
568
+ const padLen = w - 2 - stripAnsi(line).length;
569
+ lines.push(C.brand('│') + line + ' '.repeat(Math.max(0, padLen)) + C.brand('│'));
570
+ }
571
+
572
+ // Ayraç
573
+ lines.push(C.brand('├' + '─'.repeat(w - 2) + '┤'));
574
+
575
+ // Tip
576
+ const tipText = tips || '🌱 natureco code → Edit & refactor any file';
577
+ const tipLabel = '💡 İpucu';
578
+ const tipLine = ` ${C.amber(tipLabel)} ${C.dim(tipText)}`;
579
+ const tipPadLen = w - 2 - stripAnsi(tipLine).length;
580
+ lines.push(C.brand('│') + tipLine + ' '.repeat(Math.max(0, tipPadLen)) + C.brand('│'));
581
+
582
+ // Ayraç
583
+ lines.push(C.brand('├' + '─'.repeat(w - 2) + '┤'));
584
+
585
+ // Kısayollar
586
+ const shortcuts = [
587
+ ['Tab', 'otomatik tamamlama'],
588
+ ['↑↓', 'komut geçmişi'],
589
+ ['Ctrl+C', 'güvenli çıkış'],
590
+ ['? help', 'tüm komutlar'],
591
+ ];
592
+ for (const [key, desc] of shortcuts) {
593
+ const k = styled(key.padEnd(8), { bg: PALETTE.bgAlt, color: PALETTE.text });
594
+ const line = ` ${k} ${C.muted(desc)}`;
595
+ const padLen = w - 2 - stripAnsi(line).length;
596
+ lines.push(C.brand('│') + line + ' '.repeat(Math.max(0, padLen)) + C.brand('│'));
597
+ }
598
+
599
+ // Alt çerçeve
600
+ lines.push(C.brand('╰' + '─'.repeat(w - 2) + '╯'));
601
+
602
+ return lines.join('\n');
603
+ }
604
+
605
+ // ════════════════════════════════════════════════════════════
606
+ // Pretty Errors — Stack trace yerine güzel hata mesajı
607
+ // ════════════════════════════════════════════════════════════
608
+
609
+ function prettyError(err, options = {}) {
610
+ const { title = 'Bir hata oluştu', showStack = false, suggestion = null } = options;
611
+ const lines = [];
612
+ const w = Math.min(70, CAPS.width - 4);
613
+
614
+ lines.push(C.red('╭' + '─'.repeat(w - 2) + '╮'));
615
+ const titleIcon = '✗ ' + title;
616
+ const titlePad = w - 2 - titleIcon.length;
617
+ lines.push(C.red('│ ') + C.bold(C.red(titleIcon)) + ' '.repeat(Math.max(0, titlePad)) + C.red(' │'));
618
+
619
+ lines.push(C.red('├' + '─'.repeat(w - 2) + '┤'));
620
+
621
+ // Hata mesajı
622
+ const msg = err.message || String(err);
623
+ const wrapped = wrapText(msg, w - 6);
624
+ for (const line of wrapped) {
625
+ const padded = ' ' + line;
626
+ const padLen = w - 2 - padded.length;
627
+ lines.push(C.red('│') + padded + ' '.repeat(Math.max(0, padLen)) + C.red(' │'));
628
+ }
629
+
630
+ if (suggestion) {
631
+ lines.push(C.red('├' + '─'.repeat(w - 2) + '┤'));
632
+ const sugText = '💡 ' + suggestion;
633
+ const sugWrap = wrapText(sugText, w - 6);
634
+ for (const line of sugWrap) {
635
+ const padded = ' ' + styled(line, { color: PALETTE.warning });
636
+ const padLen = w - 2 - padded.length;
637
+ lines.push(C.red('│') + padded + ' '.repeat(Math.max(0, padLen)) + C.red(' │'));
638
+ }
639
+ }
640
+
641
+ if (showStack && err.stack) {
642
+ lines.push(C.red('├' + '─'.repeat(w - 2) + '┤'));
643
+ const stackLines = err.stack.split('\n').slice(0, 5);
644
+ for (const s of stackLines) {
645
+ const padded = ' ' + styled(s, { color: PALETTE.muted, dim: true });
646
+ const padLen = w - 2 - Math.min(stripAnsi(padded).length, w - 4);
647
+ lines.push(C.red('│') + padded.slice(0, w - 2) + ' '.repeat(Math.max(0, padLen)) + C.red(' │'));
648
+ }
649
+ }
650
+
651
+ lines.push(C.red('╰' + '─'.repeat(w - 2) + '╯'));
652
+ return lines.join('\n');
653
+ }
654
+
655
+ function wrapText(text, width) {
656
+ const words = text.split(' ');
657
+ const lines = [];
658
+ let current = '';
659
+ for (const word of words) {
660
+ if ((current + ' ' + word).trim().length > width) {
661
+ if (current) lines.push(current);
662
+ current = word;
663
+ } else {
664
+ current = current ? current + ' ' + word : word;
665
+ }
666
+ }
667
+ if (current) lines.push(current);
668
+ return lines;
669
+ }
670
+
671
+ // ════════════════════════════════════════════════════════════
672
+ // Notification — toast gibi sağ üstten (basit)
673
+ // ════════════════════════════════════════════════════════════
674
+
675
+ function notify(message, options = {}) {
676
+ const { type = 'info', duration = 3000 } = options;
677
+ const icons = { info: 'ℹ️', success: '✓', warning: '⚠️', error: '✗' };
678
+ const colors = { info: PALETTE.info, success: PALETTE.success, warning: PALETTE.warning, error: PALETTE.danger };
679
+ const icon = icons[type] || icons.info;
680
+ const color = colors[type] || colors.info;
681
+ const text = ` ${icon} ${message} `;
682
+ console.log('\n' + styled(text, { bg: color, color: '#000000', bold: true }));
683
+ }
684
+
685
+ // ════════════════════════════════════════════════════════════
686
+ // Tree view — file/dir ağacı
687
+ // ════════════════════════════════════════════════════════════
688
+
689
+ function tree(items, options = {}) {
690
+ const { indent = ' ', expanded = {} } = options;
691
+ const lines = [];
692
+
693
+ function render(items, depth = 0) {
694
+ for (const item of items) {
695
+ const isLast = item === items[items.length - 1];
696
+ const prefix = depth === 0 ? '' : (indent.repeat(depth - 1) + (isLast ? '└─ ' : '├─ '));
697
+ const icon = item.icon || (item.children ? '📁' : '📄');
698
+ const name = item.name || item.label || '';
699
+ const color = item.children ? PALETTE.primary : PALETTE.text;
700
+ lines.push(prefix + icon + ' ' + styled(name, { color }));
701
+ if (item.children && (depth === 0 || expanded[item.name])) {
702
+ render(item.children, depth + 1);
703
+ }
704
+ }
705
+ }
706
+
707
+ render(items);
708
+ return lines.join('\n');
709
+ }
710
+
711
+ // ════════════════════════════════════════════════════════════
712
+ // Init
713
+ // ════════════════════════════════════════════════════════════
714
+
715
+ function init() {
716
+ detectCapabilities();
717
+ // Resize olunca güncelle
718
+ if (CAPS.isTTY) {
719
+ process.stdout.on('resize', () => {
720
+ CAPS.width = process.stdout.columns || 80;
721
+ CAPS.height = process.stdout.rows || 24;
722
+ });
723
+ }
724
+ }
725
+
726
+ module.exports = {
727
+ // Capabilities
728
+ CAPS, PALETTE, STYLE,
729
+ // ANSI primitives
730
+ CURSOR, SCREEN, MOUSE,
731
+ // Color helpers
732
+ fg, bg, fg256, bg256, styled, hexToRgb, C, stripAnsi,
733
+ // Borders & boxes
734
+ BORDER, box,
735
+ // Progress
736
+ SPINNER_FRAMES, Spinner, withSpinner, progressBar, formatDuration,
737
+ // Visual
738
+ bigBanner, fadeIn, splash, welcomeCard, table, statusBar, breadcrumb,
739
+ // Errors
740
+ prettyError,
741
+ // Notifications
742
+ notify,
743
+ // Tree
744
+ tree,
745
+ // Input
746
+ readKey, parseKey, helpOverlay,
747
+ // Init
748
+ init, detectCapabilities,
749
+ sleep,
750
+ };