@nibgat/aide 0.0.0-stage → 0.2.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/README.md CHANGED
@@ -1,3 +1,80 @@
1
- # Temporary Holding Version
1
+ # aide — Ai-de komut satırı
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Şirketinizin Ai-de sistemini terminalden yönetin: sohbet, personel, yetenek setleri, veri kaynakları, otomasyonlar, bildirimler, sistem ve **cihaz/terminal yönetimi**. Panelde yapılan her iş burada da yapılır. Bağımlılığı yoktur (Node 18+; cihaz modu için Node 22+).
4
+
5
+ ## Kurulum
6
+
7
+ ```bash
8
+ npm install -g @nibgat/aide
9
+ aide
10
+ ```
11
+
12
+ İlk çalıştırmada Ai-de sunucusunun adresi sorulur (ör. `https://aide.sirketiniz.com`). Adres denenir, Ai-de sunucusu olduğu doğrulanır, ardından e-posta ve şifre (görünmez) ile giriş yapılır. Bilgiler `~/.aide/config.json` dosyasına yalnızca sizin okuyabileceğiniz izinle yazılır.
13
+
14
+ Repo içinden: `yarn aide` ya da `cd apps/cli && npm link`.
15
+
16
+ ## Etkileşimli oturum
17
+
18
+ `aide` komutu sohbet oturumu açar:
19
+
20
+ - Yanıt akışla gelir, bitince Markdown olarak (başlık, liste, tablo, kod) çizilir. Personelin veri çıktısı ve yorumu ayrı bloklardır.
21
+ - Personelin ve araçların adımları soluk satırlar olarak düşer; son adımda canlı gösterge döner.
22
+ - **Ctrl+C** süren yanıtı iptal eder (sunucudaki iş de durur). Boş satırda iki kez Ctrl+C ya da **Ctrl+D** çıkar.
23
+ - Tur sürerken yazdıklarınız sıraya alınır. Yapıştırılan çok satırlı metin tek mesajdır; satır sonu `\` ile alt satıra devam edilir.
24
+ - Geçmiş `~/.aide/history` dosyasında tutulur (↑/↓). Boştayken yeni bildirimler istemin üstüne düşer.
25
+
26
+ | Komut | |
27
+ |---|---|
28
+ | `/yeni` · `/oturumlar` · `/oturum <no>` · `/ad <başlık>` · `/sil` | sohbetler |
29
+ | `/ekip` · `/durum` · `/bildirimler` · `/sunucu` | ekip, model/kuyruk durumu, bildirimler |
30
+ | `/aide <komut>` | CLI'nin her komutu oturum içinden (`/aide data list`) |
31
+ | `!komut` | yerel terminalde çalıştır (`!git status`) |
32
+ | `/temizle` · `/yardim` · `/cikis` | |
33
+
34
+ `Tab` eğik çizgi komutlarını tamamlar.
35
+
36
+ ## Tek seferlik komutlar
37
+
38
+ ```bash
39
+ aide chat "bu ay kaç fatura kesildi?" # adımlar stderr'e, yanıt stdout'a
40
+ aide chat "bunu özetle" --file rapor.pdf
41
+ aide team list --json | jq '.data[].name'
42
+ aide team task <id> "Ekim faturalarını kontrol et"
43
+ aide auto schedule "Muhasebe her gün 09:00'da vadesi geçenleri raporlasın"
44
+ aide data test netsis
45
+ aide notify watch
46
+ aide api GET /api/engine/panel # adı konmamış her uç nokta
47
+ aide routes # komut ↔ API tablosu
48
+ aide help <grup> # sessions, team, skills, data, auto, notes, me, org, culture, integrations, company, notify, system
49
+ ```
50
+
51
+ Seçenekler: `--json` ham JSON · `--yes` silmede onay sorma (etkileşimsiz ortamda zorunlu) · `--server`/`--token` tek komutluk adres/anahtar · `k=v` gövde alanı (sayı, `true/false`, `[dizi]`, `{nesne}` JSON olarak okunur). Ortam: `AIDE_SERVER`, `AIDE_TOKEN`, `AIDE_PASSWORD`, `AIDE_HOME`, `NO_COLOR`.
52
+
53
+ ## Cihaz modu: terminal ve işletim sistemi yönetimi
54
+
55
+ ```bash
56
+ aide device connect --workspace ~/projeler # bu makineyi Ai-de'ye cihaz olarak bağla
57
+ aide device install --workspace ~/projeler --dry # açılışta kendiliğinden bağlanan servis: önce ne yapacağını gör
58
+ aide device install --workspace ~/projeler # kur (Linux: systemd kullanıcı servisi · macOS: LaunchAgent · Windows: oturum açılışı görevi)
59
+ aide device status · aide device uninstall
60
+ ```
61
+
62
+ Makine Ai-de'ye bağlanır; personel bu makinede **yalnızca çalışma klasöründe** dosya okur/yazar ve komut çalıştırır. Yazma ve komutlar her seferinde terminalde onay ister. `--read-only` yalnızca okumaya izin verir. `--approve-all` ekransız sunucular için onaysız çalışır (bilerek kullanın). Repo içinde `@aide/connectors` erişilebilirse yerel ağdaki veritabanları da bu makineden sorgulanır (Edge Runner). Personel `system_info` aracıyla makinenin durumunu (CPU, bellek, diskler, en çok bellek kullanan süreçler) salt okuma olarak görür.
63
+
64
+ Servis ekransız çalıştığı için onay soramaz: varsayılan **salt okuma** kurulur; yazma/komut için `--approve-all` bilerek verilir. Kimlik `aide login` ile kaydedilen yapılandırmadan okunur.
65
+
66
+ ## Yayınlama
67
+
68
+ ```bash
69
+ cd apps/cli
70
+ npm pack --dry-run # içerik denetimi (8 dosya, ~22 kB)
71
+ npm publish # @nibgat kapsamı npm'de sizin olmalı; yoksa package.json "name" değiştirilir
72
+ ```
73
+
74
+ ## Kapsam
75
+
76
+ Yeni bir API ucu eklendiğinde ya `src/commands.mjs` içindeki `ROUTES` tablosuna komut eklenir ya da gerekçesiyle `scripts/maintenance/cliCoverage.mjs` içindeki `IGNORED` listesine yazılır:
77
+
78
+ ```bash
79
+ node scripts/maintenance/cliCoverage.mjs --strict
80
+ ```
package/aide.mjs ADDED
@@ -0,0 +1,205 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Ai-de komut satırı (aide). Argümansız: etkileşimli oturum (ilk çalıştırmada sunucu adresi ve giriş sorulur).
4
+ * Tek seferlik: `aide chat "…"`, `aide team list`, `aide api GET /api/...`, `aide device connect` … Ayrıntı: aide help
5
+ */
6
+ import { routesTable, runGroupCommand, parseArgs, groupHelp, runApi, GROUP_TITLES } from './src/commands.mjs';
7
+ import { startRepl, onboard, ensureSession, VERSION } from './src/repl.mjs';
8
+ import { updateConfig, readConfig, streamTurn, CONFIG_FILE, call, upload, AideError } from './src/client.mjs';
9
+ import { renderMarkdown, createSpinner, print, c } from './src/ui.mjs';
10
+ import {
11
+ manageService,
12
+ connectDevice
13
+ } from './src/device.mjs';
14
+
15
+ const help = (group) => {
16
+ if(group && GROUP_TITLES[group]) {
17
+ groupHelp(group);
18
+ return;
19
+ }
20
+
21
+ console.log(`${c.accent('✻')} ${c.bold('aide')} ${c.dim(`v${VERSION}`)} — Ai-de komut satırı
22
+
23
+ ${c.bold('Başlangıç')}
24
+ aide etkileşimli oturum (ilk seferde sunucu + giriş sorulur)
25
+ aide login [--server <adres>] [--email <e-posta>]
26
+ aide chat "bu ay kaç fatura kesildi?" tek soru (yanıt akışla) · --file rapor.pdf · --new
27
+ aide remind "yarın 14:00 Ahmet Bey'i ara" hatırlatma/alarm (aide reminders list)
28
+ aide whoami · aide logout · aide config [server <adres>]
29
+
30
+ ${c.bold('Gruplar')} ${c.dim('(aide help <grup>)')}
31
+ ${Object.entries(GROUP_TITLES).map(([key, title]) => ` ${key.padEnd(14)} ${title}`).join('\n')}
32
+
33
+ ${c.bold('Cihaz (terminal / işletim sistemi yönetimi)')}
34
+ aide device connect [--workspace <klasör>] [--read-only] [--approve-all]
35
+ bu makineyi bağla: personel burada dosya/komut işi yapar (onaylı)
36
+ aide device install [--workspace <klasör>] [--approve-all] [--dry]
37
+ açılışta kendiliğinden bağlanan servis (systemd / LaunchAgent / Windows görevi)
38
+ aide device uninstall · aide device status servisi kaldır / durumunu göster
39
+
40
+ ${c.bold('Her şey')}
41
+ aide api <METOT> </api/yol> [k=v …] [--data '{…}'] adı konmamış her uç nokta
42
+ aide routes komut ↔ API tablosu
43
+ aide notify watch bildirimleri canlı izle
44
+
45
+ ${c.bold('Seçenekler')}
46
+ --json ham JSON (betikler) · --yes silmede onay sorma · --server/--token geçici adres/anahtar · k=v gövde alanı`);
47
+ };
48
+
49
+ /** Tek seferlik soru: adımlar stderr'e soluk, yanıt stdout'a (Markdown çizilmiş ya da --json). */
50
+ const chatOnce = async ({ flags, positional }) => {
51
+ const sessionId = flags.session ? String(flags.session) : await ensureSession(flags, Boolean(flags.new));
52
+ const attachments = [];
53
+
54
+ for(const file of flags.file ? String(flags.file).split(',') : []) {
55
+ attachments.push(await upload(flags, file));
56
+ }
57
+
58
+ if(positional.length === 0) {
59
+ return startRepl(flags);
60
+ }
61
+
62
+ const spinner = flags.json || flags.quiet ? null : createSpinner('Düşünüyor');
63
+
64
+ spinner?.start();
65
+
66
+ const final = await streamTurn(flags, {
67
+ prompt: positional.join(' '),
68
+ sessionId,
69
+ attachments,
70
+ onStep: (message) => {
71
+ if(!spinner || /^(Tamamlandı|🧭 İstek yönlendiriliyor)/.test(message)) {
72
+ spinner?.update(message);
73
+ return;
74
+ }
75
+
76
+ spinner.stop(`⎿ ${message}`);
77
+ spinner.update(message);
78
+ spinner.start();
79
+ }
80
+ }).finally(() => spinner?.stop());
81
+
82
+ if(flags.json) {
83
+ console.log(JSON.stringify(final, null, 2));
84
+ return;
85
+ }
86
+
87
+ const parts = Array.isArray(final.messages) && final.messages.length > 1 ? final.messages : [final.finalTurkishResponse || ''];
88
+
89
+ parts.forEach((part, index) => console.log(`${index > 0 ? `${c.gray('─'.repeat(40))}\n` : ''}${renderMarkdown(part)}`));
90
+ };
91
+
92
+ const watchNotifications = async (flags) => {
93
+ let since = String(flags.since || new Date().toISOString());
94
+
95
+ console.log(c.dim('Bildirimler izleniyor (Ctrl+C ile çıkış)…'));
96
+
97
+ for(;;) {
98
+ const json = await call(flags, 'GET', `/api/engine/notifications?since=${encodeURIComponent(since)}`).catch((error) => {
99
+ console.error(c.red(error.message));
100
+ return {};
101
+ });
102
+ const items = json.data || json.notifications || [];
103
+
104
+ (Array.isArray(items) ? items : []).forEach((item) => {
105
+ console.log(`${c.accent('●')} ${c.bold(item.title || item.kind || 'Bildirim')} ${c.dim(item.at || item.createdAt || '')}\n ${item.body || item.message || ''}`);
106
+ since = item.at || item.createdAt || since;
107
+ });
108
+
109
+ await new Promise((resolve) => setTimeout(resolve, 15000));
110
+ }
111
+ };
112
+
113
+ const main = async () => {
114
+ const [command, ...rest] = process.argv.slice(2);
115
+ const args = parseArgs(rest);
116
+
117
+ switch(command) {
118
+ case undefined:
119
+ if(!process.stdin.isTTY) {
120
+ help();
121
+ return;
122
+ }
123
+
124
+ return startRepl(args.flags);
125
+ case 'help':
126
+ case '--help':
127
+ case '-h':
128
+ help(args.positional[0]);
129
+ return;
130
+ case 'version':
131
+ case '--version':
132
+ case '-v':
133
+ console.log(VERSION);
134
+ return;
135
+ case 'login':
136
+ await onboard(args.flags);
137
+ return;
138
+ case 'logout':
139
+ await call(args.flags, 'POST', '/api/auth/logout', {}).catch(() => null);
140
+ updateConfig({ token: '', sessionId: null });
141
+ console.log(c.green('✓ Çıkış yapıldı.'));
142
+ return;
143
+ case 'whoami':
144
+ print(await call(args.flags, 'GET', '/api/auth/me'), args.flags);
145
+ return;
146
+ case 'config': {
147
+ const [action, key, value] = args.positional;
148
+
149
+ if(action === 'server' && key) {
150
+ updateConfig({ server: key, token: '' });
151
+ console.log(c.green(`✓ server = ${key} (yeniden giriş: aide login)`));
152
+ return;
153
+ }
154
+
155
+ if(action === 'set' && key) {
156
+ updateConfig({ [key]: value });
157
+ console.log(c.green(`✓ ${key} = ${value}`));
158
+ return;
159
+ }
160
+
161
+ const { token, ...visible } = readConfig();
162
+
163
+ print({ ...visible, token: token ? `${token.slice(0, 6)}…` : '(yok)', file: CONFIG_FILE }, args.flags);
164
+ return;
165
+ }
166
+ case 'chat':
167
+ return chatOnce(args);
168
+ case 'remind':
169
+ return runGroupCommand('reminders', { ...args, positional: ['add', ...args.positional] });
170
+ case 'api':
171
+ return runApi(args);
172
+ case 'routes':
173
+ routesTable(args.flags);
174
+ return;
175
+ case 'device':
176
+ if([
177
+ 'uninstall',
178
+ 'install',
179
+ 'status'
180
+ ].includes(args.positional[0])) {
181
+ return manageService(args.positional[0], args.flags);
182
+ }
183
+
184
+ if(args.positional[0] !== 'connect') {
185
+ throw new AideError('Kullanım: aide device connect|install|uninstall|status [--workspace <klasör>] [--read-only] [--approve-all] [--dry]');
186
+ }
187
+
188
+ return connectDevice(args.flags);
189
+ default:
190
+ break;
191
+ }
192
+
193
+ if(command === 'notify' && args.positional[0] === 'watch') {
194
+ return watchNotifications(args.flags);
195
+ }
196
+
197
+ if(!(await runGroupCommand(command, args))) {
198
+ throw new AideError(`Bilinmeyen komut: ${command} (aide help)`);
199
+ }
200
+ };
201
+
202
+ main().catch((error) => {
203
+ console.error(c.red(`✗ ${error.message}`));
204
+ process.exit(1);
205
+ });
package/package.json CHANGED
@@ -1,6 +1,31 @@
1
1
  {
2
2
  "name": "@nibgat/aide",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.0",
4
+ "description": "Ai-de komut satırı: şirketinizin Ai-de sistemini (sohbet, personel, veri kaynakları, otomasyonlar, cihaz/terminal yönetimi) terminalden yönetin",
5
+ "type": "module",
6
+ "bin": {
7
+ "aide": "aide.mjs"
8
+ },
9
+ "files": [
10
+ "aide.mjs",
11
+ "src/",
12
+ "README.md"
13
+ ],
14
+ "keywords": [
15
+ "ai-de",
16
+ "aide",
17
+ "cli",
18
+ "ai",
19
+ "agents",
20
+ "erp",
21
+ "company"
22
+ ],
23
+ "author": "NİBGAT Teknoloji",
24
+ "license": "UNLICENSED",
25
+ "engines": {
26
+ "node": ">=18"
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ }
31
+ }
package/src/client.mjs ADDED
@@ -0,0 +1,260 @@
1
+ /**
2
+ * Yapılandırma (~/.aide/config.json), sunucu istekleri, akışlı sohbet turu (SSE), dosya yükleme ve terminal soruları.
3
+ */
4
+ import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
5
+ import { createInterface } from 'node:readline';
6
+ import path from 'node:path';
7
+ import os from 'node:os';
8
+
9
+ const CONFIG_DIR = process.env.AIDE_HOME || path.join(os.homedir(), '.aide');
10
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
11
+ const HISTORY_FILE = path.join(CONFIG_DIR, 'history');
12
+
13
+ const readConfig = () => {
14
+ try {
15
+ return JSON.parse(readFileSync(CONFIG_FILE, 'utf8'));
16
+ } catch {
17
+ return {};
18
+ }
19
+ };
20
+
21
+ const writeConfig = (config) => {
22
+ mkdirSync(CONFIG_DIR, { recursive: true });
23
+ writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 4), { mode: 0o600 });
24
+ };
25
+
26
+ const updateConfig = (patch) => writeConfig({ ...readConfig(), ...patch });
27
+
28
+ /** "aide.sirket.com" → "https://aide.sirket.com"; "localhost:3000" → "http://localhost:3000". */
29
+ const normalizeServer = (raw) => {
30
+ const text = String(raw || '').trim().replace(/\/+$/, '');
31
+
32
+ if(!text) {
33
+ return '';
34
+ }
35
+
36
+ if(/^https?:\/\//i.test(text)) {
37
+ return text;
38
+ }
39
+
40
+ return /^(localhost|127\.|\d+\.\d+\.\d+\.\d+|[^.]+:\d+$)/i.test(text) ? `http://${text}` : `https://${text}`;
41
+ };
42
+
43
+ const settings = (flags = {}) => {
44
+ const config = readConfig();
45
+
46
+ return {
47
+ server: normalizeServer(flags.server || process.env.AIDE_SERVER || config.server || ''),
48
+ token: String(flags.token || process.env.AIDE_TOKEN || config.token || ''),
49
+ config
50
+ };
51
+ };
52
+
53
+ class AideError extends Error {
54
+ constructor(message, status) {
55
+ super(message);
56
+ this.status = status;
57
+ }
58
+ }
59
+
60
+ const call = async (flags, method, url, body) => {
61
+ const { server, token } = settings(flags);
62
+
63
+ if(!server) {
64
+ throw new AideError('Ai-de sunucusu tanımlı değil: aide login (ya da aide config server <adres>)');
65
+ }
66
+
67
+ let response;
68
+
69
+ try {
70
+ response = await fetch(`${server}${url}`, {
71
+ headers: { 'Content-Type': 'application/json', ...(token ? { Authorization: `Bearer ${token}` } : {}) },
72
+ body: body === undefined ? undefined : JSON.stringify(body),
73
+ signal: flags.signal,
74
+ method
75
+ });
76
+ } catch (error) {
77
+ if(error.name === 'AbortError') {
78
+ throw error;
79
+ }
80
+
81
+ throw new AideError(`Sunucuya ulaşılamadı (${server}): ${error.cause?.code || error.message}`);
82
+ }
83
+
84
+ const text = await response.text();
85
+ let json;
86
+
87
+ try {
88
+ json = text ? JSON.parse(text) : {};
89
+ } catch {
90
+ json = { raw: text };
91
+ }
92
+
93
+ if(response.status === 401) {
94
+ throw new AideError('Oturum yok ya da süresi doldu: aide login', 401);
95
+ }
96
+
97
+ if(!response.ok || json.success === false) {
98
+ throw new AideError(json.error || json.message || `Sunucu hatası (${response.status})`, response.status);
99
+ }
100
+
101
+ return json;
102
+ };
103
+
104
+ /** Sunucu ayakta mı ve Ai-de mi (giriş gerektirmeyen uç). */
105
+ const probe = async (server) => {
106
+ const response = await fetch(`${server}/api/auth/signup-enabled`, { signal: AbortSignal.timeout(8000) });
107
+ const json = await response.json().catch(() => null);
108
+
109
+ if(!response.ok || !json || typeof json !== 'object') {
110
+ throw new AideError(`Bu adres bir Ai-de sunucusu gibi görünmüyor (${response.status}).`);
111
+ }
112
+
113
+ return json;
114
+ };
115
+
116
+ const login = async (server, email, password) => {
117
+ const response = await fetch(`${server}/api/auth/login`, {
118
+ headers: { 'Content-Type': 'application/json' },
119
+ body: JSON.stringify({ email, password }),
120
+ method: 'POST'
121
+ });
122
+ const json = await response.json().catch(() => ({}));
123
+ const token = json.token || json.data?.token;
124
+
125
+ if(!response.ok || !token) {
126
+ throw new AideError(json.error || 'Giriş başarısız.', response.status);
127
+ }
128
+
129
+ return token;
130
+ };
131
+
132
+ /** Dosyayı sunucuda okutur (PDF, Word, Excel, görsel OCR); çıkarılan metin sohbete ek olarak gider. */
133
+ const upload = async (flags, file) => {
134
+ const data = readFileSync(file);
135
+ const json = await call(flags, 'POST', '/api/chat/upload', {
136
+ fileData: data.toString('base64'),
137
+ fileName: path.basename(file),
138
+ mimeType: ''
139
+ });
140
+
141
+ if(!json.data?.extractedText) {
142
+ throw new AideError(`Belgeden metin çıkarılamadı: ${file}`);
143
+ }
144
+
145
+ return { extractedText: json.data.extractedText, fileName: json.data.fileName || path.basename(file) };
146
+ };
147
+
148
+ /**
149
+ * Sohbet turu (SSE: step / done / error). `onStep(message)`, `onToken(token)` çağrılır; sonuç pipelineData'dır.
150
+ * `signal` ile iptal edilir (Ctrl+C): istek kesilir ve sunucudaki iş durdurulur.
151
+ */
152
+ const streamTurn = async (flags, { prompt, sessionId, attachments = [], onStep = () => null, onToken = () => null, signal }) => {
153
+ const { server, token } = settings(flags);
154
+ const response = await fetch(`${server}/api/chat/stream`, {
155
+ headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
156
+ body: JSON.stringify({ prompt, sessionId, attachments }),
157
+ method: 'POST',
158
+ signal
159
+ });
160
+
161
+ if(response.status === 401) {
162
+ throw new AideError('Oturum yok ya da süresi doldu: aide login', 401);
163
+ }
164
+
165
+ if(!response.ok || !response.body) {
166
+ throw new AideError(`Sunucu hatası (${response.status})`, response.status);
167
+ }
168
+
169
+ const decoder = new TextDecoder();
170
+ let buffer = '';
171
+ let final = null;
172
+
173
+ for await (const chunk of response.body) {
174
+ buffer += decoder.decode(chunk, { stream: true });
175
+ const blocks = buffer.split('\n\n');
176
+
177
+ buffer = blocks.pop() || '';
178
+
179
+ for(const block of blocks) {
180
+ const event = /^event: (.+)$/m.exec(block)?.[1];
181
+ const data = /^data: (.+)$/m.exec(block)?.[1];
182
+
183
+ if(!event || !data) {
184
+ continue;
185
+ }
186
+
187
+ const payload = JSON.parse(data);
188
+
189
+ if(event === 'step' && payload.stage === 'token_stream') {
190
+ onToken(payload.token || '');
191
+ } else if(event === 'step' && payload.message) {
192
+ onStep(payload.message, payload);
193
+ } else if(event === 'done') {
194
+ final = payload.pipelineData || {};
195
+ } else if(event === 'error') {
196
+ throw new AideError(payload.message || 'Bir hata oluştu.');
197
+ }
198
+ }
199
+ }
200
+
201
+ return final || {};
202
+ };
203
+
204
+ /** Terminal sorusu; `hidden` şifre içindir (yazılanlar görünmez). */
205
+ const ask = (question, { hidden = false, fallback = '' } = {}) => new Promise((resolve) => {
206
+ if(!process.stdin.isTTY) {
207
+ resolve(fallback);
208
+ return;
209
+ }
210
+
211
+ const rl = createInterface({ input: process.stdin, output: process.stdout, terminal: true });
212
+
213
+ if(hidden) {
214
+ rl._writeToOutput = (text) => {
215
+ if(text.includes(question)) {
216
+ process.stdout.write(text);
217
+ }
218
+ };
219
+ }
220
+
221
+ rl.question(question, (answer) => {
222
+ rl.close();
223
+
224
+ if(hidden) {
225
+ process.stdout.write('\n');
226
+ }
227
+
228
+ resolve(answer.trim() || fallback);
229
+ });
230
+ });
231
+
232
+ const confirm = async (flags, message) => {
233
+ if(flags.yes || flags.y) {
234
+ return true;
235
+ }
236
+
237
+ if(!process.stdin.isTTY) {
238
+ throw new AideError(`${message} — onay için --yes ekleyin.`);
239
+ }
240
+
241
+ return /^(e|evet|y|yes)$/i.test(await ask(`${message} (e/H) `));
242
+ };
243
+
244
+ export {
245
+ normalizeServer,
246
+ updateConfig,
247
+ HISTORY_FILE,
248
+ writeConfig,
249
+ CONFIG_FILE,
250
+ readConfig,
251
+ streamTurn,
252
+ AideError,
253
+ settings,
254
+ confirm,
255
+ upload,
256
+ probe,
257
+ login,
258
+ call,
259
+ ask
260
+ };