@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 +79 -2
- package/aide.mjs +205 -0
- package/package.json +29 -4
- package/src/client.mjs +260 -0
- package/src/commands.mjs +360 -0
- package/src/device.mjs +488 -0
- package/src/repl.mjs +501 -0
- package/src/ui.mjs +260 -0
package/src/commands.mjs
ADDED
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Panel işlevleri → API komut tablosu ve çalıştırıcısı. Hem tek seferlik komutlar (`aide team list`) hem etkileşimli
|
|
3
|
+
* oturumdaki `/aide team list` aynı dağıtıcıyı kullanır.
|
|
4
|
+
*/
|
|
5
|
+
import { AideError, call, confirm } from './client.mjs';
|
|
6
|
+
import { print, unwrap, renderMarkdown, c } from './ui.mjs';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* `:param` konumsal argümanlarla sırayla doldurulur; `bodyArg` kalan argümanları o gövde alanına koyar; `body` sabit
|
|
10
|
+
* gövde; `k=v` ve `--data '{…}'` gövdeye eklenir; `confirm` geri alınamaz işler; `query` bayraktan sorgu parametresi.
|
|
11
|
+
*/
|
|
12
|
+
const ROUTES = [
|
|
13
|
+
// Sohbetler
|
|
14
|
+
['sessions', 'list', 'GET', '/api/chat/sessions', 'Sohbetleri listele', { columns: ['id', 'title', 'messageCount', 'updatedAt'] }],
|
|
15
|
+
['sessions', 'show', 'GET', '/api/chat/sessions/:id', 'Sohbetin mesajlarını göster', { render: 'messages' }],
|
|
16
|
+
['sessions', 'new', 'POST', '/api/chat/sessions', 'Yeni sohbet aç', { bodyArg: 'title' }],
|
|
17
|
+
['sessions', 'rename', 'PATCH', '/api/chat/sessions/:id', 'Sohbetin başlığını değiştir', { bodyArg: 'title', required: true }],
|
|
18
|
+
['sessions', 'clear', 'POST', '/api/chat/sessions/:id/clear', 'Sohbetin mesajlarını temizle', { confirm: true }],
|
|
19
|
+
['sessions', 'rm', 'DELETE', '/api/chat/sessions/:id', 'Sohbeti sil', { confirm: true }],
|
|
20
|
+
['sessions', 'cancel', 'POST', '/api/chat/cancel', 'Süren yanıtı durdur', { bodyArg: 'sessionId' }],
|
|
21
|
+
// Ekip
|
|
22
|
+
['team', 'list', 'GET', '/api/employees', 'Personeli listele', { columns: ['id', 'name', 'role', 'department', 'hierarchyRole'] }],
|
|
23
|
+
['team', 'show', 'GET', '/api/employees/:id', 'Personel ayrıntısı'],
|
|
24
|
+
['team', 'add', 'POST', '/api/employees', 'Personel ekle (name= role= department= skillSets=[...] …)'],
|
|
25
|
+
['team', 'set', 'PUT', '/api/employees/:id', 'Personeli güncelle (k=v …)'],
|
|
26
|
+
['team', 'rm', 'DELETE', '/api/employees/:id', 'Personeli sil', { confirm: true }],
|
|
27
|
+
['team', 'task', 'POST', '/api/engine/agents/:id/task', 'Personele iş ver', { bodyArg: 'instruction', required: true, render: 'answer' }],
|
|
28
|
+
['team', 'chat', 'POST', '/api/engine/agents/:id/chat', 'Personelle özel sohbet', { bodyArg: 'message', required: true, render: 'answer' }],
|
|
29
|
+
['team', 'history', 'GET', '/api/engine/agents/:id/chat', 'Özel sohbet geçmişi', { render: 'messages' }],
|
|
30
|
+
['team', 'tools', 'GET', '/api/employees/:id/tools', 'Personelin araçları'],
|
|
31
|
+
['team', 'roles', 'GET', '/api/employees/hierarchy-roles', 'Hiyerarşi rolleri'],
|
|
32
|
+
// Yetenek setleri
|
|
33
|
+
['skills', 'list', 'GET', '/api/skillsets', 'Yetenek setlerini listele', { columns: ['id', 'name', 'tools', 'description'] }],
|
|
34
|
+
['skills', 'add', 'POST', '/api/skillsets', 'Yetenek seti ekle (name= description= tools=[...] …)'],
|
|
35
|
+
['skills', 'set', 'PUT', '/api/skillsets/:id', 'Yetenek setini güncelle'],
|
|
36
|
+
['skills', 'rm', 'DELETE', '/api/skillsets/:id', 'Yetenek setini sil', { confirm: true }],
|
|
37
|
+
['skills', 'assign', 'POST', '/api/skillsets/assign', 'Personele yetenek seti ata (employeeId= skillSetId= …)'],
|
|
38
|
+
// Veri kaynakları
|
|
39
|
+
['data', 'list', 'GET', '/api/datasources', 'Veri kaynaklarını listele', { columns: ['name', 'driver', 'status', 'entities'] }],
|
|
40
|
+
['data', 'add', 'PUT', '/api/datasources/:name', 'Veri kaynağı ekle/güncelle (driver= host= database= …)'],
|
|
41
|
+
['data', 'test', 'POST', '/api/datasources/:name/test', 'Bağlantıyı dene'],
|
|
42
|
+
['data', 'discover', 'POST', '/api/datasources/:name/discover', 'Şemayı yeniden keşfet'],
|
|
43
|
+
['data', 'describe', 'POST', '/api/datasources/:name/describe', 'Veri sözlüğünü (AI açıklamaları) üret'],
|
|
44
|
+
['data', 'catalog', 'GET', '/api/datasources/:name/catalog', 'Katalog (tablolar, alanlar, sözlük)'],
|
|
45
|
+
['data', 'note', 'PATCH', '/api/datasources/:name/catalog/:entity', 'Tablo açıklaması/alan notu düzelt (description= …)'],
|
|
46
|
+
['data', 'rm', 'DELETE', '/api/datasources/:name', 'Veri kaynağını sil', { confirm: true }],
|
|
47
|
+
// Otomasyonlar
|
|
48
|
+
['auto', 'list', 'GET', '/api/automations', 'Kuralları listele', { columns: ['id', 'name', 'enabled', 'trigger', 'action'] }],
|
|
49
|
+
['auto', 'add', 'POST', '/api/automations', 'Kural ekle (--data \'{…}\')'],
|
|
50
|
+
['auto', 'set', 'PATCH', '/api/automations/:id', 'Kuralı güncelle'],
|
|
51
|
+
['auto', 'enable', 'PATCH', '/api/automations/:id', 'Kuralı aç', { body: { enabled: true } }],
|
|
52
|
+
['auto', 'disable', 'PATCH', '/api/automations/:id', 'Kuralı kapat', { body: { enabled: false } }],
|
|
53
|
+
['auto', 'rm', 'DELETE', '/api/automations/:id', 'Kuralı sil', { confirm: true }],
|
|
54
|
+
['auto', 'events', 'GET', '/api/automations/events', 'Olay kaydı'],
|
|
55
|
+
['auto', 'schedules', 'GET', '/api/automations/schedules', 'Zamanlanmış rutinler'],
|
|
56
|
+
['auto', 'schedule', 'POST', '/api/automations/schedules', 'Rutin ekle ("Muhasebe her gün 09:00 …")', { bodyArg: 'text', required: true }],
|
|
57
|
+
['auto', 'schedule-set', 'PATCH', '/api/automations/schedules/:employeeId/:taskId', 'Rutini güncelle (enabled=false …)'],
|
|
58
|
+
['auto', 'schedule-rm', 'DELETE', '/api/automations/schedules/:employeeId/:taskId', 'Rutini sil', { confirm: true }],
|
|
59
|
+
// Notlar, hesap, organizasyon
|
|
60
|
+
['notes', 'list', 'GET', '/api/me/notes', 'Notlarım', { columns: ['id', 'text', 'source', 'createdAt'] }],
|
|
61
|
+
['notes', 'add', 'POST', '/api/me/notes', 'Not ekle', { bodyArg: 'text', required: true }],
|
|
62
|
+
['notes', 'rm', 'DELETE', '/api/me/notes/:id', 'Notu sil', { confirm: true }],
|
|
63
|
+
['reminders', 'list', 'GET', '/api/me/reminders', 'Hatırlatmalarım ve alarmlarım', { columns: ['id', 'text', 'describe', 'status', 'dueAt'] }],
|
|
64
|
+
['reminders', 'add', 'POST', '/api/me/reminders', 'Hatırlatma kur ("yarın 14:00 Ahmet Bey\'i ara")', { bodyArg: 'text', required: true, render: 'reminder' }],
|
|
65
|
+
['reminders', 'done', 'PATCH', '/api/me/reminders/:id', 'Tamamlandı say', { body: { action: 'done' } }],
|
|
66
|
+
['reminders', 'snooze', 'PATCH', '/api/me/reminders/:id', 'Ertele (minutes=10)', { body: { action: 'snooze' } }],
|
|
67
|
+
['reminders', 'cancel', 'PATCH', '/api/me/reminders/:id', 'İptal et', { body: { action: 'cancel' } }],
|
|
68
|
+
['reminders', 'rm', 'DELETE', '/api/me/reminders/:id', 'Hatırlatmayı sil', { confirm: true }],
|
|
69
|
+
['prefs', 'show', 'GET', '/api/me/notification-prefs', 'Bildirim kanallarım'],
|
|
70
|
+
['prefs', 'set', 'PUT', '/api/me/notification-prefs', 'Kanalları ayarla (channels=\'["inapp","telegram"]\' telegramChatId= phone= quietHours=\'{"from":"22:00","to":"08:00"}\')'],
|
|
71
|
+
['prefs', 'test', 'POST', '/api/me/notification-prefs/test', 'Kanallara deneme bildirimi gönder'],
|
|
72
|
+
['project', 'list', 'GET', '/api/projects', 'Projeler', { columns: ['id', 'title', 'status', 'progress', 'updatedAt'] }],
|
|
73
|
+
['project', 'start', 'POST', '/api/projects', 'Proje başlat (hedefi yazın; arka planda planlanır)', { bodyArg: 'goal', required: true }],
|
|
74
|
+
['project', 'show', 'GET', '/api/projects/:id', 'Proje ayrıntısı (görevler, olaylar, özet)', { render: 'project' }],
|
|
75
|
+
['project', 'pause', 'POST', '/api/projects/:id/pause', 'Duraklat (çalışan görev biter, yenisi alınmaz)'],
|
|
76
|
+
['project', 'resume', 'POST', '/api/projects/:id/resume', 'Devam ettir'],
|
|
77
|
+
['project', 'cancel', 'POST', '/api/projects/:id/cancel', 'İptal et', { confirm: true }],
|
|
78
|
+
['project', 'message', 'POST', '/api/projects/:id/messages', 'Araya mesaj (yeni istek/yön değişikliği)', { bodyArg: 'text', required: true }],
|
|
79
|
+
['project', 'task', 'PATCH', '/api/projects/:id/tasks/:taskId', 'Görev sırası: first (öne al) · skip (atla) · reopen (yeniden aç)', { bodyArg: 'action', required: true }],
|
|
80
|
+
['questions', 'list', 'GET', '/api/questions', 'Bana sorulanlar (--all: hepsi)', { columns: ['id', 'text', 'options', 'defaultOption', 'status'] }],
|
|
81
|
+
['questions', 'answer', 'POST', '/api/questions/:id/answer', 'Soruyu yanıtla', { bodyArg: 'answer', required: true }],
|
|
82
|
+
['me', 'profile', 'GET', '/api/me/profile', 'Profilim'],
|
|
83
|
+
['me', 'set', 'PUT', '/api/me/profile', 'Profili güncelle (name= …)'],
|
|
84
|
+
['me', 'password', 'POST', '/api/me/password', 'Şifre değiştir (currentPassword= newPassword=)'],
|
|
85
|
+
['org', 'members', 'GET', '/api/me/organization/members', 'Üyeler', { columns: ['id', 'name', 'email', 'orgRole', 'status'] }],
|
|
86
|
+
['org', 'invite', 'POST', '/api/me/organization/members', 'Üye davet et (email= name= orgRole=)'],
|
|
87
|
+
['org', 'member-set', 'PATCH', '/api/me/organization/members/:memberId', 'Üye rolünü değiştir (orgRole=admin|member)'],
|
|
88
|
+
['org', 'member-rm', 'DELETE', '/api/me/organization/members/:memberId', 'Üyeyi çıkar', { confirm: true }],
|
|
89
|
+
['org', 'audit', 'GET', '/api/me/organization/audit', 'Denetim kaydı'],
|
|
90
|
+
['culture', 'list', 'GET', '/api/culture', 'Şirket kültürü kuralları'],
|
|
91
|
+
['culture', 'add', 'POST', '/api/culture/rule', 'Kural ekle (title= description=)'],
|
|
92
|
+
['culture', 'rm', 'DELETE', '/api/culture/rule/:id', 'Kuralı sil', { confirm: true }],
|
|
93
|
+
// Entegrasyonlar
|
|
94
|
+
['integrations', 'list', 'GET', '/api/connectors', 'Entegrasyonlar (e-posta, WhatsApp …)'],
|
|
95
|
+
['integrations', 'set', 'PUT', '/api/connectors/:type', 'Entegrasyon ayarla (k=v …)'],
|
|
96
|
+
['integrations', 'test', 'POST', '/api/connectors/:type/test', 'Entegrasyonu dene'],
|
|
97
|
+
['integrations', 'rm', 'DELETE', '/api/connectors/:type', 'Entegrasyonu kaldır', { confirm: true }],
|
|
98
|
+
// Şirket yönetimi, bildirimler
|
|
99
|
+
['company', 'status', 'GET', '/api/engine/status', 'Motor durumu (modeller, kuyruk, hız)'],
|
|
100
|
+
['company', 'panel', 'GET', '/api/engine/panel', 'Şirket Yönetimi Paneli verisi'],
|
|
101
|
+
['company', 'messages', 'GET', '/api/engine/agent-messages', 'Personel yazışmaları', { columns: ['at', 'kind', 'fromAgentId', 'toAgentId', 'title'] }],
|
|
102
|
+
['notify', 'list', 'GET', '/api/engine/notifications', 'Bildirimler (--since ISO tarih)', { query: ['since'] }],
|
|
103
|
+
// Sistem (platform yöneticisi)
|
|
104
|
+
['system', 'host', 'GET', '/api/system/model-host', 'Model sunucusu durumu'],
|
|
105
|
+
['system', 'cleanup', 'POST', '/api/system/model-host/cleanup', 'Sahipsiz model süreçlerini temizle (--dry: yalnızca göster)', { dryFlag: true }],
|
|
106
|
+
['system', 'update', 'POST', '/api/system/model-host/update', 'Model sunucusu ajanını güncelle'],
|
|
107
|
+
['system', 'rollback', 'POST', '/api/system/model-host/rollback', 'Ajanı önceki sürüme döndür', { confirm: true }]
|
|
108
|
+
].map(([group, action, method, url, summary, options = {}]) => ({ group, action, method, url, summary, ...options }));
|
|
109
|
+
|
|
110
|
+
const GROUP_TITLES = {
|
|
111
|
+
sessions: 'Sohbetler',
|
|
112
|
+
team: 'Ekip (personel)',
|
|
113
|
+
skills: 'Yetenek setleri',
|
|
114
|
+
data: 'Veri kaynakları',
|
|
115
|
+
auto: 'Otomasyonlar ve rutinler',
|
|
116
|
+
notes: 'Notlarım',
|
|
117
|
+
reminders: 'Hatırlatmalar ve alarmlar',
|
|
118
|
+
project: 'Projeler (uzun soluklu işler)',
|
|
119
|
+
questions: 'Bana sorulanlar',
|
|
120
|
+
prefs: 'Bildirim tercihleri',
|
|
121
|
+
me: 'Hesabım',
|
|
122
|
+
org: 'Organizasyon',
|
|
123
|
+
culture: 'Şirket kültürü',
|
|
124
|
+
integrations: 'Entegrasyonlar',
|
|
125
|
+
company: 'Şirket yönetimi',
|
|
126
|
+
notify: 'Bildirimler',
|
|
127
|
+
system: 'Sistem (platform yöneticisi)'
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const VALUE_FLAGS = new Set(['server', 'token', 'email', 'password', 'session', 'data', 'file', 'since', 'columns', 'workspace']);
|
|
131
|
+
|
|
132
|
+
/** `count=3` → 3, `enabled=true` → true, `skillSets=["developer"]` → dizi; diğerleri metin. */
|
|
133
|
+
const parseValue = (value) => {
|
|
134
|
+
if(/^(true|false|null|-?\d+(\.\d+)?|\[.*\]|\{.*\})$/s.test(value)) {
|
|
135
|
+
try {
|
|
136
|
+
return JSON.parse(value);
|
|
137
|
+
} catch {
|
|
138
|
+
return value;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return value;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
/** `--anahtar değer`, `--bayrak`, `anahtar=değer` (gövde alanı) ve konumsal argümanlar ayrılır. */
|
|
146
|
+
const parseArgs = (argv) => {
|
|
147
|
+
const flags = {};
|
|
148
|
+
const fields = {};
|
|
149
|
+
const positional = [];
|
|
150
|
+
|
|
151
|
+
for(let index = 0; index < argv.length; index += 1) {
|
|
152
|
+
const arg = argv[index];
|
|
153
|
+
|
|
154
|
+
if(arg.startsWith('--')) {
|
|
155
|
+
const [key, inline] = arg.slice(2).split(/=(.*)/s);
|
|
156
|
+
const next = argv[index + 1];
|
|
157
|
+
|
|
158
|
+
if(inline !== undefined) {
|
|
159
|
+
flags[key] = inline;
|
|
160
|
+
} else if(VALUE_FLAGS.has(key) && next !== undefined) {
|
|
161
|
+
flags[key] = next;
|
|
162
|
+
index += 1;
|
|
163
|
+
} else {
|
|
164
|
+
flags[key] = true;
|
|
165
|
+
}
|
|
166
|
+
} else if(/^[A-Za-z_][\w.]*=/.test(arg)) {
|
|
167
|
+
const [key, value] = arg.split(/=(.*)/s);
|
|
168
|
+
|
|
169
|
+
fields[key] = parseValue(value);
|
|
170
|
+
} else {
|
|
171
|
+
positional.push(arg);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return { flags, fields, positional };
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
/** Tırnakları dikkate alarak satırı argümanlara böler (etkileşimli `/aide …` için). */
|
|
179
|
+
const splitLine = (line) => (line.match(/"[^"]*"|'[^']*'|\S+/g) || []).map((part) => part.replace(/^(["'])(.*)\1$/s, '$2'));
|
|
180
|
+
|
|
181
|
+
const renderMessages = (value) => {
|
|
182
|
+
const messages = Array.isArray(value) ? value : value?.messages || [];
|
|
183
|
+
|
|
184
|
+
if(messages.length === 0) {
|
|
185
|
+
console.log(c.dim('(mesaj yok)'));
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
messages.forEach((message) => {
|
|
190
|
+
console.log(message.role === 'user' ? c.bold('❯ Siz') : c.accent('✻ Ai-de'));
|
|
191
|
+
console.log(`${message.role === 'user' ? (message.content || '') : renderMarkdown(message.content || message.text || '')}\n`);
|
|
192
|
+
});
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const runRoute = async (spec, { flags, fields, positional }) => {
|
|
196
|
+
const params = (spec.url.match(/:\w+/g) || []).map((param) => param.slice(1));
|
|
197
|
+
const usage = `aide ${spec.group} ${spec.action} ${params.map((param) => `<${param}>`).join(' ')}${spec.bodyArg ? ` "<${spec.bodyArg}>"` : ''}`.trim();
|
|
198
|
+
|
|
199
|
+
if(positional.length < params.length) {
|
|
200
|
+
throw new AideError(`Eksik argüman: ${usage}`);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
let url = spec.url;
|
|
204
|
+
|
|
205
|
+
params.forEach((param, index) => {
|
|
206
|
+
url = url.replace(`:${param}`, encodeURIComponent(positional[index]));
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
const rest = positional.slice(params.length);
|
|
210
|
+
const query = (spec.query || []).filter((key) => flags[key]).map((key) => `${key}=${encodeURIComponent(flags[key])}`);
|
|
211
|
+
|
|
212
|
+
if(query.length > 0) {
|
|
213
|
+
url += `?${query.join('&')}`;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if(spec.required && rest.length === 0 && fields[spec.bodyArg] === undefined) {
|
|
217
|
+
throw new AideError(`Eksik argüman: ${usage}`);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const body = spec.method === 'GET' || spec.method === 'DELETE' ? undefined : {
|
|
221
|
+
...(spec.body || {}),
|
|
222
|
+
...(spec.bodyArg && rest.length > 0 ? { [spec.bodyArg]: rest.join(' ') } : {}),
|
|
223
|
+
...(spec.dryFlag ? { dryRun: Boolean(flags.dry) } : {}),
|
|
224
|
+
...fields,
|
|
225
|
+
...(flags.data ? JSON.parse(String(flags.data)) : {})
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
if(spec.confirm && !(await confirm(flags, `${spec.summary}: ${positional.slice(0, params.length).join(' ')} — emin misiniz?`))) {
|
|
229
|
+
console.log(c.dim('Vazgeçildi.'));
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const json = await call(flags, spec.method, url, body);
|
|
234
|
+
|
|
235
|
+
if(flags.json) {
|
|
236
|
+
console.log(JSON.stringify(json, null, 2));
|
|
237
|
+
} else if(spec.render === 'messages') {
|
|
238
|
+
renderMessages(unwrap(json));
|
|
239
|
+
} else if(spec.render === 'answer') {
|
|
240
|
+
const value = unwrap(json);
|
|
241
|
+
const text = typeof value === 'string' ? value : value?.output || value?.answer || value?.reply || value?.text || value?.content;
|
|
242
|
+
|
|
243
|
+
console.log(text ? renderMarkdown(text) : '');
|
|
244
|
+
|
|
245
|
+
if(!text) {
|
|
246
|
+
print(json, flags, spec);
|
|
247
|
+
}
|
|
248
|
+
} else if(spec.render === 'reminder') {
|
|
249
|
+
const reminder = unwrap(json);
|
|
250
|
+
|
|
251
|
+
console.log(`${c.green('✓')} ${reminder.isAlarm ? 'Alarm' : 'Hatırlatma'} kuruldu: ${c.bold(reminder.text)} — ${reminder.describe}`);
|
|
252
|
+
} else if(spec.render === 'project') {
|
|
253
|
+
renderProject(unwrap(json));
|
|
254
|
+
} else {
|
|
255
|
+
print(json, flags, spec);
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
const PROJECT_STATUS = { awaiting_acceptance: 'teslim onayı bekliyor', reviewing: 'teslim hazırlanıyor', staffing: 'kadro bekliyor', planning: 'planlanıyor', cancelled: 'iptal', running: 'çalışıyor', paused: 'duraklatıldı', failed: 'başarısız', done: 'tamamlandı' };
|
|
260
|
+
const STATUS_ICONS = { done: c.green('✓'), skipped: c.dim('↷'), running: c.accent('●'), ready: c.yellow('○'), pending: c.dim('○'), waiting_input: c.yellow('?'), cancelled: c.dim('✗') };
|
|
261
|
+
|
|
262
|
+
/** Proje ayrıntısı: durum, ilerleme, görev listesi (durum simgesiyle), son olaylar, özet. */
|
|
263
|
+
const renderProject = (project) => {
|
|
264
|
+
if(!project?.id) {
|
|
265
|
+
print(project);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
console.log(`${c.bold(project.title)} ${c.dim(`· ${PROJECT_STATUS[project.status] || project.status} · ${project.progress?.done ?? 0}/${project.progress?.total ?? 0} · ${project.id}`)}`);
|
|
270
|
+
console.log(c.dim(project.goal || ''));
|
|
271
|
+
(project.tasks || []).forEach((task) => console.log(` ${STATUS_ICONS[task.status] || '·'} ${task.title} ${c.dim(`(${task.status}${task.attempts > 1 ? ` · ${task.attempts}. deneme` : ''})`)}`));
|
|
272
|
+
|
|
273
|
+
if(project.summary) {
|
|
274
|
+
console.log(`\n${renderMarkdown(project.summary)}`);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if(project.acceptanceReport?.length) {
|
|
278
|
+
console.log(c.bold('\nKabul ölçütleri'));
|
|
279
|
+
project.acceptanceReport.forEach((item) => console.log(` ${item.status === 'met' ? c.green('✓') : item.status === 'missing' ? c.red('✗') : c.dim('?')} ${item.criterion}${item.note ? c.dim(` — ${item.note}`) : ''}`));
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if(project.status === 'awaiting_acceptance') {
|
|
283
|
+
console.log(c.yellow('\nTeslim onayınızı bekliyor: aide questions list → aide questions answer <id> "Kabul ediyorum" | "Düzeltme istiyorum: …"'));
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const events = (project.events || []).slice(0, 5);
|
|
287
|
+
|
|
288
|
+
if(events.length > 0) {
|
|
289
|
+
console.log(c.dim(`\nSon olaylar: ${events.map((item) => item.type).join(' · ')}`));
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
/** Her uç nokta: aide api GET /api/engine/panel · aide api POST /api/me/notes text="..." · --data '{…}' */
|
|
294
|
+
const runApi = async ({ flags, fields, positional }) => {
|
|
295
|
+
const [method, url] = positional;
|
|
296
|
+
|
|
297
|
+
if(!method || !url) {
|
|
298
|
+
throw new AideError('Kullanım: aide api <GET|POST|PUT|PATCH|DELETE> </api/...> [k=v …] [--data \'{…}\']');
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const upper = method.toUpperCase();
|
|
302
|
+
const body = upper === 'GET' ? undefined : { ...fields, ...(flags.data ? JSON.parse(String(flags.data)) : {}) };
|
|
303
|
+
// Git Bash "/api/x" argümanını Windows yoluna çevirir ("C:/Program Files/Git/api/x"); "api/x" de kabul edilir
|
|
304
|
+
const normalized = url.replace(/\\/g, '/');
|
|
305
|
+
const start = normalized.search(/(^|\/)api\//);
|
|
306
|
+
const route = start >= 0 ? `/${normalized.slice(start).replace(/^\//, '')}` : normalized;
|
|
307
|
+
|
|
308
|
+
print(await call(flags, upper, route, body), flags);
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
const routesTable = (flags) => {
|
|
312
|
+
if(flags.json) {
|
|
313
|
+
console.log(JSON.stringify(ROUTES.map(({ group, action, method, url, summary }) => ({ command: `aide ${group} ${action}`, method, url, summary })), null, 2));
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
ROUTES.forEach((spec) => console.log(`${`aide ${spec.group} ${spec.action}`.padEnd(30)} ${c.dim(spec.method.padEnd(6))} ${spec.url}`));
|
|
318
|
+
console.log(c.dim(`\n${ROUTES.length} adlandırılmış komut. Diğer her uç nokta için: aide api <METOT> <yol>`));
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const groupHelp = (group) => {
|
|
322
|
+
console.log(c.bold(GROUP_TITLES[group]));
|
|
323
|
+
ROUTES.filter((spec) => spec.group === group).forEach((spec) => {
|
|
324
|
+
const params = (spec.url.match(/:\w+/g) || []).map((param) => `<${param.slice(1)}>`).join(' ');
|
|
325
|
+
const usage = `aide ${spec.group} ${spec.action}${params ? ` ${params}` : ''}${spec.bodyArg ? ` "<${spec.bodyArg}>"` : ''}`;
|
|
326
|
+
|
|
327
|
+
console.log(` ${usage.padEnd(62)}${c.dim(spec.summary)}`);
|
|
328
|
+
});
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
/** Grup komutunu çalıştırır (`team list`); grup yoksa false döner. */
|
|
332
|
+
const runGroupCommand = async (command, args) => {
|
|
333
|
+
if(!GROUP_TITLES[command]) {
|
|
334
|
+
return false;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const [action = 'list', ...positional] = args.positional;
|
|
338
|
+
const spec = ROUTES.find((item) => item.group === command && item.action === action);
|
|
339
|
+
|
|
340
|
+
if(!spec) {
|
|
341
|
+
groupHelp(command);
|
|
342
|
+
throw new AideError(`Bilinmeyen işlem: aide ${command} ${action}`);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
await runRoute(spec, { ...args, positional });
|
|
346
|
+
|
|
347
|
+
return true;
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
export {
|
|
351
|
+
runGroupCommand,
|
|
352
|
+
GROUP_TITLES,
|
|
353
|
+
routesTable,
|
|
354
|
+
parseValue,
|
|
355
|
+
groupHelp,
|
|
356
|
+
parseArgs,
|
|
357
|
+
splitLine,
|
|
358
|
+
ROUTES,
|
|
359
|
+
runApi
|
|
360
|
+
};
|