@aigencydev/cli 0.2.0 → 0.3.1
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 +234 -37
- package/dist/agent/checkpoints.js +147 -0
- package/dist/agent/chunker.js +1 -19
- package/dist/agent/history.js +0 -9
- package/dist/agent/instructions.js +94 -0
- package/dist/agent/loop.js +2 -34
- package/dist/agent/memory.js +197 -103
- package/dist/agent/session-store.js +160 -0
- package/dist/agent/task-list.js +102 -0
- package/dist/api-client/auth.js +0 -10
- package/dist/api-client/base.js +0 -16
- package/dist/api-client/stream.js +0 -25
- package/dist/api-client/updates.js +2 -9
- package/dist/api-client/usage.js +0 -4
- package/dist/auth/oauth.js +0 -31
- package/dist/auth/pkce.js +1 -9
- package/dist/auth/session.js +0 -16
- package/dist/auth/storage.js +1 -36
- package/dist/cli.js +8 -13
- package/dist/commands/chat.js +14 -19
- package/dist/commands/help.js +0 -4
- package/dist/commands/init.js +327 -30
- package/dist/commands/login.js +0 -30
- package/dist/commands/logout.js +0 -5
- package/dist/commands/update.js +0 -9
- package/dist/commands/usage.js +0 -10
- package/dist/config/bootstrap.js +52 -0
- package/dist/config/defaults.js +4 -15
- package/dist/config/hooks.js +1 -23
- package/dist/config/paths.js +95 -38
- package/dist/config/settings.js +0 -21
- package/dist/index.js +0 -11
- package/dist/security/command-filter.js +0 -35
- package/dist/security/sandbox.js +1 -39
- package/dist/security/sanitize.js +0 -21
- package/dist/tools/bash.js +49 -35
- package/dist/tools/diff.js +0 -7
- package/dist/tools/edit-file.js +4 -12
- package/dist/tools/list-files.js +0 -5
- package/dist/tools/memory-tools.js +126 -0
- package/dist/tools/read-file.js +1 -7
- package/dist/tools/registry.js +7 -9
- package/dist/tools/search-files.js +2 -11
- package/dist/tools/task-tools.js +74 -0
- package/dist/tools/types.js +0 -4
- package/dist/tools/write-file.js +5 -12
- package/dist/types/index.js +0 -7
- package/dist/ui/App.js +122 -39
- package/dist/ui/InputBar.js +0 -9
- package/dist/ui/MessageList.js +0 -9
- package/dist/ui/ModeIndicator.js +0 -11
- package/dist/ui/PermissionPrompt.js +0 -15
- package/dist/ui/StatusBar.js +0 -10
- package/dist/ui/theme.js +23 -61
- package/dist/utils/abort.js +0 -12
- package/dist/utils/errors.js +0 -7
- package/dist/utils/formatting.js +0 -8
- package/dist/utils/logger.js +107 -17
- package/dist/version.js +1 -8
- package/package.json +1 -1
- package/dist/agent/chunker.js.map +0 -1
- package/dist/agent/history.js.map +0 -1
- package/dist/agent/loop.js.map +0 -1
- package/dist/agent/memory.js.map +0 -1
- package/dist/api-client/auth.js.map +0 -1
- package/dist/api-client/base.js.map +0 -1
- package/dist/api-client/stream.js.map +0 -1
- package/dist/api-client/updates.js.map +0 -1
- package/dist/api-client/usage.js.map +0 -1
- package/dist/auth/oauth.js.map +0 -1
- package/dist/auth/pkce.js.map +0 -1
- package/dist/auth/session.js.map +0 -1
- package/dist/auth/storage.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/commands/chat.js.map +0 -1
- package/dist/commands/help.js.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/login.js.map +0 -1
- package/dist/commands/logout.js.map +0 -1
- package/dist/commands/update.js.map +0 -1
- package/dist/commands/usage.js.map +0 -1
- package/dist/config/defaults.js.map +0 -1
- package/dist/config/hooks.js.map +0 -1
- package/dist/config/paths.js.map +0 -1
- package/dist/config/settings.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/security/command-filter.js.map +0 -1
- package/dist/security/sandbox.js.map +0 -1
- package/dist/security/sanitize.js.map +0 -1
- package/dist/tools/bash.js.map +0 -1
- package/dist/tools/diff.js.map +0 -1
- package/dist/tools/edit-file.js.map +0 -1
- package/dist/tools/list-files.js.map +0 -1
- package/dist/tools/read-file.js.map +0 -1
- package/dist/tools/registry.js.map +0 -1
- package/dist/tools/search-files.js.map +0 -1
- package/dist/tools/types.js.map +0 -1
- package/dist/tools/write-file.js.map +0 -1
- package/dist/types/index.js.map +0 -1
- package/dist/ui/App.js.map +0 -1
- package/dist/ui/InputBar.js.map +0 -1
- package/dist/ui/MessageList.js.map +0 -1
- package/dist/ui/ModeIndicator.js.map +0 -1
- package/dist/ui/PermissionPrompt.js.map +0 -1
- package/dist/ui/StatusBar.js.map +0 -1
- package/dist/ui/theme.js.map +0 -1
- package/dist/utils/abort.js.map +0 -1
- package/dist/utils/errors.js.map +0 -1
- package/dist/utils/formatting.js.map +0 -1
- package/dist/utils/logger.js.map +0 -1
- package/dist/version.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,83 +1,280 @@
|
|
|
1
1
|
# AIGENCY CLI
|
|
2
2
|
|
|
3
3
|
Terminalden yapay zeka destekli kod üretimi, dosya yönetimi ve proje otomasyonu.
|
|
4
|
+
AIGENCY hesabınla bağlanır, projende çalışır, kodu senin onayınla yazar.
|
|
5
|
+
|
|
6
|
+
```
|
|
7
|
+
┌──────────────────────────────────────────┐
|
|
8
|
+
│ ✦ AIGENCY CLI v0.3.0 │
|
|
9
|
+
│ ● default · AIGENCY Pro · my-app │
|
|
10
|
+
│ │
|
|
11
|
+
│ ▸ Sana nasıl yardımcı olabilirim? │
|
|
12
|
+
└──────────────────────────────────────────┘
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
4
16
|
|
|
5
17
|
## Kurulum
|
|
6
18
|
|
|
7
|
-
**
|
|
19
|
+
**npm ile (önerilen)**
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g @aigencydev/cli
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**macOS / Linux — shell installer**
|
|
8
25
|
```bash
|
|
9
26
|
curl -fsSL https://aigency.dev/cli/install.sh | bash
|
|
10
27
|
```
|
|
11
28
|
|
|
12
|
-
**Windows
|
|
29
|
+
**Windows — PowerShell**
|
|
13
30
|
```powershell
|
|
14
31
|
irm https://aigency.dev/cli/install.ps1 | iex
|
|
15
32
|
```
|
|
16
33
|
|
|
17
|
-
**
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
```
|
|
34
|
+
> **Not:** Node.js 18.18 veya üzeri gerekir. `node --version` ile kontrol edebilirsin.
|
|
35
|
+
|
|
36
|
+
---
|
|
21
37
|
|
|
22
|
-
##
|
|
38
|
+
## Hızlı Başlangıç
|
|
23
39
|
|
|
24
40
|
```bash
|
|
25
|
-
#
|
|
41
|
+
# 1) Hesabına bağlan (tarayıcı açılır)
|
|
26
42
|
aigency login
|
|
27
43
|
|
|
28
|
-
#
|
|
44
|
+
# 2) Bir proje dizinine gir ve .aigency/ iskeletini oluştur
|
|
45
|
+
cd ~/projects/my-app
|
|
29
46
|
aigency init
|
|
30
47
|
|
|
31
|
-
#
|
|
32
|
-
aigency
|
|
48
|
+
# 3) Ajanla konuşmaya başla
|
|
49
|
+
aigency "bana bir Next.js CV sitesi oluştur, Apple tarzı"
|
|
33
50
|
|
|
34
|
-
#
|
|
35
|
-
aigency
|
|
36
|
-
|
|
37
|
-
# Yardım
|
|
38
|
-
aigency help
|
|
51
|
+
# ya da interaktif modda
|
|
52
|
+
aigency
|
|
39
53
|
```
|
|
40
54
|
|
|
41
|
-
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Komutlar
|
|
58
|
+
|
|
59
|
+
| Komut | Açıklama |
|
|
60
|
+
|---|---|
|
|
61
|
+
| `aigency` | İnteraktif sohbet modu (varsayılan) |
|
|
62
|
+
| `aigency "<prompt>"` | Tek seferlik prompt çalıştır |
|
|
63
|
+
| `aigency login` | AIGENCY hesabına OAuth ile bağlan |
|
|
64
|
+
| `aigency logout` | Oturumu kapat, yerel token'ları sil |
|
|
65
|
+
| `aigency init` | Mevcut dizinde `.aigency/` yapısını kur |
|
|
66
|
+
| `aigency usage` | Aylık token kullanımını göster |
|
|
67
|
+
| `aigency update` | En son sürümü kontrol et |
|
|
68
|
+
| `aigency help` | Komut yardımı |
|
|
69
|
+
| `aigency --version` | Sürümü göster |
|
|
70
|
+
|
|
71
|
+
**Flag'ler:**
|
|
72
|
+
- `--mode <default\|plan\|accept_edits\|auto>` — başlangıç izin modu
|
|
73
|
+
- `--model <pro\|max>` — AIGENCY paket seviyesi
|
|
42
74
|
|
|
43
|
-
|
|
44
|
-
|---|---|---|
|
|
45
|
-
| AIGENCY CLI Pro | 1.500 ₺/ay | 1.000.000 |
|
|
46
|
-
| AIGENCY CLI Max | 3.000 ₺/ay | 5.000.000 + öncelikli kuyruk + Auto mode |
|
|
75
|
+
---
|
|
47
76
|
|
|
48
|
-
## İzin Modları
|
|
77
|
+
## İzin Modları
|
|
49
78
|
|
|
50
79
|
| Mod | Davranış |
|
|
51
80
|
|---|---|
|
|
52
|
-
| `default` | Dosya okuma otomatik, yazma ve komut onay
|
|
53
|
-
| `plan` | Dry-run — hiçbir şey yazılmaz, sadece
|
|
54
|
-
| `accept_edits` | Dosya yazma otomatik,
|
|
55
|
-
| `auto` | Sınıflandırıcı destekli tam otomatik (
|
|
81
|
+
| `default` | Dosya okuma otomatik, yazma ve komut için onay sorulur |
|
|
82
|
+
| `plan` | Dry-run — hiçbir şey yazılmaz, sadece yapılacakların planı gösterilir |
|
|
83
|
+
| `accept_edits` | Dosya yazma otomatik, shell komutları hâlâ onay ister |
|
|
84
|
+
| `auto` | Sınıflandırıcı destekli tam otomatik (yalnızca **Max** tier) |
|
|
85
|
+
|
|
86
|
+
Mod'u çalışırken değiştirmek için **Shift+Tab** bas.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Kısayollar
|
|
91
|
+
|
|
92
|
+
| Tuş | İşlev |
|
|
93
|
+
|---|---|
|
|
94
|
+
| `Shift+Tab` | İzin modlarını döngüle (default → plan → accept_edits → auto) |
|
|
95
|
+
| `ESC` | Aktif ajan işlemini iptal et |
|
|
96
|
+
| `Ctrl+C` | Çalışıyorsa iptal, boştaysa çıkış |
|
|
97
|
+
| `/` | Slash komut başlat |
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Slash Komutları
|
|
102
|
+
|
|
103
|
+
| Komut | İşlev |
|
|
104
|
+
|---|---|
|
|
105
|
+
| `/help` | Komut listesi |
|
|
106
|
+
| `/clear` | Sohbet geçmişini ve onay cache'ini temizle |
|
|
107
|
+
| `/mode [default\|plan\|accept_edits\|auto]` | Modu değiştir veya göster |
|
|
108
|
+
| `/cost` | Bu oturumda kullanılan token sayısı |
|
|
109
|
+
| `/undo` | Son dosya düzenlemesini geri al (checkpoint'ten) |
|
|
110
|
+
| `/exit` veya `/quit` | Çıkış |
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Araçlar (Ajanın Kullanabildiği Tool'lar)
|
|
115
|
+
|
|
116
|
+
Ajan projenizde aşağıdaki işlemleri yapabilir (izin modunuza göre onay ister):
|
|
117
|
+
|
|
118
|
+
**Dosya sistemi**
|
|
119
|
+
- `read_file` — Dosya içeriği okur
|
|
120
|
+
- `list_files` — Dizin listeler (gitignore'a saygı duyar)
|
|
121
|
+
- `search_files` — Regex ile içerik arar
|
|
122
|
+
- `write_file` — Yeni dosya yazar veya tamamen değiştirir
|
|
123
|
+
- `edit_file` — Mevcut dosyada cerrahi değişiklik yapar
|
|
124
|
+
|
|
125
|
+
**Shell**
|
|
126
|
+
- `bash_execute` — İnteraktif olmayan shell komutu çalıştırır (5 dk timeout, canlı çıktı akışı)
|
|
127
|
+
|
|
128
|
+
**Hafıza (kalıcı, makineye özel)**
|
|
129
|
+
- `save_memory` — Önemli bilgiyi oturumlar arası sakla
|
|
130
|
+
- `read_memory` — Detay hafıza dosyasını oku
|
|
131
|
+
- `delete_memory` — Artık geçerli olmayan bilgiyi sil
|
|
132
|
+
|
|
133
|
+
**Görev planlama**
|
|
134
|
+
- `write_tasks` — Büyük görevleri adımlara böl, ilerlemeyi canlı göster
|
|
135
|
+
- `read_tasks` — Mevcut görev listesini oku
|
|
136
|
+
|
|
137
|
+
**Sandbox:** `.git/`, `.env*`, `~/.ssh/`, `node_modules/`, `.next/` gibi hassas yollar
|
|
138
|
+
otomatik reddedilir. `sudo`, `rm -rf /`, `curl | sh` gibi tehlikeli komutlar
|
|
139
|
+
engellenir.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Proje Yapılandırması (`.aigency/`)
|
|
144
|
+
|
|
145
|
+
`aigency init` çalıştırdığında projenizde aşağıdaki yapı oluşturulur:
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
<proje>/.aigency/
|
|
149
|
+
├── AIGENCY.md # Proje talimatları (ajan her oturum başında okur)
|
|
150
|
+
├── PROGRESS.md # İlerleme takibi (opsiyonel)
|
|
151
|
+
├── settings.json # İzin modu, allow/deny listeleri
|
|
152
|
+
├── settings.local.json # Kişisel override (gitignored)
|
|
153
|
+
├── rules/ # Path-scoped kurallar
|
|
154
|
+
│ └── example.md
|
|
155
|
+
├── hooks/ # PreToolUse/PostToolUse script'leri
|
|
156
|
+
│ ├── hooks.json
|
|
157
|
+
│ └── README.md
|
|
158
|
+
├── logs/ # Günlük JSONL logları (gitignored)
|
|
159
|
+
└── .gitignore
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**AIGENCY.md** en önemli dosyadır — projenizin teknoloji yığını, kodlama kuralları,
|
|
163
|
+
stil tercihleri ve "dokunulmaması gereken yerler"i buraya yazın. Ajan her oturum
|
|
164
|
+
başında bu dosyayı okur ve yazdığı kod bunlarla hizalanır.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Kalıcı Hafıza ve Oturum Verileri
|
|
169
|
+
|
|
170
|
+
AIGENCY CLI, **makineye özel** veriler için kullanıcının home dizininde ayrı
|
|
171
|
+
bir alan kullanır:
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
~/.aigency/
|
|
175
|
+
├── cli.json # Auth metadata
|
|
176
|
+
├── credentials.enc # AES-256-GCM şifreli token'lar
|
|
177
|
+
├── settings.json # Kullanıcı seviyesi ayarlar
|
|
178
|
+
├── AIGENCY.md # Tüm projelerde geçerli global talimatlar
|
|
179
|
+
├── cli.log # Rotating log (5 MB × 3 yedek)
|
|
180
|
+
├── cache/ # LLM response, hash cache
|
|
181
|
+
├── temp/ # Oturum scratch alanı
|
|
182
|
+
└── projects/
|
|
183
|
+
└── <proje-hash>/ # Git remote veya yola göre hash
|
|
184
|
+
├── memory/
|
|
185
|
+
│ ├── MEMORY.md # Hafıza index'i
|
|
186
|
+
│ ├── user_*.md # Kullanıcı hakkında
|
|
187
|
+
│ ├── feedback_*.md # Davranış kuralları
|
|
188
|
+
│ ├── project_*.md # Proje bağlamı
|
|
189
|
+
│ └── reference_*.md # Harici kaynak pointer'ları
|
|
190
|
+
├── sessions/
|
|
191
|
+
│ └── <id>.jsonl # Oturum transkriptleri
|
|
192
|
+
└── checkpoints/ # Dosya edit snapshot'ları (undo için)
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Bu alan **git'e commit edilmez** ve senkronize de olmaz — her makinede ayrı.
|
|
196
|
+
`.aigency/` (proje klasörü) ise git'e eklenebilir, takımla paylaşılır.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Paketler
|
|
201
|
+
|
|
202
|
+
| Paket | Fiyat | Aylık Token | Ek Özellikler |
|
|
203
|
+
|---|---|---|---|
|
|
204
|
+
| **AIGENCY CLI Pro** | 1.500 ₺/ay | 1.000.000 | Standart |
|
|
205
|
+
| **AIGENCY CLI Max** | 3.000 ₺/ay | 5.000.000 | Öncelikli kuyruk, Auto mode |
|
|
206
|
+
|
|
207
|
+
Paketleri [aigency.dev/developer/cli](https://aigency.dev/developer/cli) üzerinden
|
|
208
|
+
yönetebilir, kullanımınızı canlı izleyebilirsiniz.
|
|
209
|
+
|
|
210
|
+
---
|
|
56
211
|
|
|
57
212
|
## Yapılandırma
|
|
58
213
|
|
|
59
214
|
### Ortam değişkenleri
|
|
60
215
|
|
|
61
|
-
|
|
62
|
-
|
|
216
|
+
| Değişken | Açıklama |
|
|
217
|
+
|---|---|
|
|
218
|
+
| `AIGENCY_CLI_API_URL` | API sunucu adresi (varsayılan `https://aigency.dev`) |
|
|
219
|
+
| `AIGENCY_CLI_DEBUG` | `1` verilirse ayrıntılı debug log'lar |
|
|
63
220
|
|
|
64
|
-
###
|
|
221
|
+
### `.aigency/settings.json` Örneği
|
|
65
222
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
223
|
+
```json
|
|
224
|
+
{
|
|
225
|
+
"permissions": {
|
|
226
|
+
"defaultMode": "default",
|
|
227
|
+
"allow": [
|
|
228
|
+
"Read(**/*)",
|
|
229
|
+
"Bash(npm run *)",
|
|
230
|
+
"Bash(git status)"
|
|
231
|
+
],
|
|
232
|
+
"ask": [
|
|
233
|
+
"Write(**/*)",
|
|
234
|
+
"Edit(**/*)",
|
|
235
|
+
"Bash(*)"
|
|
236
|
+
],
|
|
237
|
+
"deny": [
|
|
238
|
+
"Read(.env)",
|
|
239
|
+
"Write(.git/**)",
|
|
240
|
+
"Bash(rm -rf *)",
|
|
241
|
+
"Bash(sudo *)"
|
|
242
|
+
]
|
|
243
|
+
},
|
|
244
|
+
"memory": {
|
|
245
|
+
"enabled": true
|
|
246
|
+
},
|
|
247
|
+
"hooks": {
|
|
248
|
+
"enabled": false
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
---
|
|
69
254
|
|
|
70
|
-
## Geliştirme
|
|
255
|
+
## Geliştirme (Contributing)
|
|
71
256
|
|
|
72
257
|
```bash
|
|
73
|
-
|
|
258
|
+
git clone https://github.com/aigencydev/cli.git
|
|
259
|
+
cd cli
|
|
74
260
|
npm install
|
|
261
|
+
|
|
75
262
|
npm run dev -- help # tsx ile direkt çalıştır
|
|
76
|
-
npm run typecheck # tip kontrolü
|
|
263
|
+
npm run typecheck # TypeScript tip kontrolü
|
|
264
|
+
npm run test # Vitest
|
|
77
265
|
npm run build # dist/ üret
|
|
78
|
-
node dist/index.js help # derlenmiş halini çalıştır
|
|
79
266
|
```
|
|
80
267
|
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## Destek
|
|
271
|
+
|
|
272
|
+
- **Web**: [aigency.dev/developer/cli](https://aigency.dev/developer/cli)
|
|
273
|
+
- **Tanıtım**: [aigency.dev/forge](https://aigency.dev/forge)
|
|
274
|
+
- **Sorun / öneri**: [aigency.dev/contact](https://aigency.dev/contact)
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
81
278
|
## Lisans
|
|
82
279
|
|
|
83
|
-
Özel — AIGENCY.
|
|
280
|
+
Özel — AIGENCY. Tüm hakları saklıdır.
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import crypto from "node:crypto";
|
|
4
|
+
import { getCheckpointDir } from "../config/paths.js";
|
|
5
|
+
import { log } from "../utils/logger.js";
|
|
6
|
+
const MAX_CHECKPOINT_BYTES = 2 * 1024 * 1024;
|
|
7
|
+
export async function captureCheckpoint(sessionId, absPath, operation, projectRoot) {
|
|
8
|
+
try {
|
|
9
|
+
let beforeContent = "";
|
|
10
|
+
let existed = false;
|
|
11
|
+
let size = 0;
|
|
12
|
+
try {
|
|
13
|
+
const stat = await fs.stat(absPath);
|
|
14
|
+
if (stat.isFile()) {
|
|
15
|
+
size = stat.size;
|
|
16
|
+
if (size > MAX_CHECKPOINT_BYTES) {
|
|
17
|
+
log.debug(`checkpoint: ${absPath} çok büyük (${size}b), snapshot atlandı`);
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
beforeContent = await fs.readFile(absPath, "utf8");
|
|
21
|
+
existed = true;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
}
|
|
26
|
+
const relPath = path.relative(projectRoot, absPath) || path.basename(absPath);
|
|
27
|
+
const checkpoint = {
|
|
28
|
+
relPath,
|
|
29
|
+
absPath,
|
|
30
|
+
ts: new Date().toISOString(),
|
|
31
|
+
operation,
|
|
32
|
+
beforeContent,
|
|
33
|
+
existed,
|
|
34
|
+
};
|
|
35
|
+
const pathHash = crypto
|
|
36
|
+
.createHash("sha256")
|
|
37
|
+
.update(absPath)
|
|
38
|
+
.digest("hex")
|
|
39
|
+
.slice(0, 12);
|
|
40
|
+
const ts = Date.now();
|
|
41
|
+
const snapshotFile = path.join(getCheckpointDir(sessionId, projectRoot), `${pathHash}-${ts}.snapshot`);
|
|
42
|
+
await fs.mkdir(path.dirname(snapshotFile), { recursive: true });
|
|
43
|
+
await fs.writeFile(snapshotFile, JSON.stringify(checkpoint), "utf8");
|
|
44
|
+
return {
|
|
45
|
+
relPath,
|
|
46
|
+
ts: checkpoint.ts,
|
|
47
|
+
operation,
|
|
48
|
+
existed,
|
|
49
|
+
snapshotFile,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
log.debug(`checkpoint hatası: ${err.message}`);
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export async function findLatestCheckpoint(sessionId, projectRoot) {
|
|
58
|
+
const dir = getCheckpointDir(sessionId, projectRoot);
|
|
59
|
+
let entries;
|
|
60
|
+
try {
|
|
61
|
+
entries = await fs.readdir(dir);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
const files = entries.filter((f) => f.endsWith(".snapshot"));
|
|
67
|
+
if (files.length === 0)
|
|
68
|
+
return null;
|
|
69
|
+
let latest = null;
|
|
70
|
+
for (const file of files) {
|
|
71
|
+
const match = /-(\d+)\.snapshot$/.exec(file);
|
|
72
|
+
if (!match)
|
|
73
|
+
continue;
|
|
74
|
+
const ts = parseInt(match[1], 10);
|
|
75
|
+
if (!latest || ts > latest.ts) {
|
|
76
|
+
latest = { file, ts };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (!latest)
|
|
80
|
+
return null;
|
|
81
|
+
try {
|
|
82
|
+
const raw = await fs.readFile(path.join(dir, latest.file), "utf8");
|
|
83
|
+
return JSON.parse(raw);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
export async function restoreCheckpoint(checkpoint) {
|
|
90
|
+
try {
|
|
91
|
+
if (checkpoint.existed) {
|
|
92
|
+
await fs.mkdir(path.dirname(checkpoint.absPath), { recursive: true });
|
|
93
|
+
await fs.writeFile(checkpoint.absPath, checkpoint.beforeContent, "utf8");
|
|
94
|
+
return {
|
|
95
|
+
ok: true,
|
|
96
|
+
message: `${checkpoint.relPath} önceki haline geri döndürüldü`,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
try {
|
|
101
|
+
await fs.unlink(checkpoint.absPath);
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
ok: true,
|
|
107
|
+
message: `${checkpoint.relPath} silindi (yeni oluşturulmuştu)`,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
return {
|
|
113
|
+
ok: false,
|
|
114
|
+
error: `Geri alma hatası: ${err.message}`,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
export async function listCheckpoints(sessionId, projectRoot) {
|
|
119
|
+
const dir = getCheckpointDir(sessionId, projectRoot);
|
|
120
|
+
let entries;
|
|
121
|
+
try {
|
|
122
|
+
entries = await fs.readdir(dir);
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
const metadata = [];
|
|
128
|
+
for (const file of entries) {
|
|
129
|
+
if (!file.endsWith(".snapshot"))
|
|
130
|
+
continue;
|
|
131
|
+
try {
|
|
132
|
+
const raw = await fs.readFile(path.join(dir, file), "utf8");
|
|
133
|
+
const cp = JSON.parse(raw);
|
|
134
|
+
metadata.push({
|
|
135
|
+
relPath: cp.relPath,
|
|
136
|
+
ts: cp.ts,
|
|
137
|
+
operation: cp.operation,
|
|
138
|
+
existed: cp.existed,
|
|
139
|
+
snapshotFile: path.join(dir, file),
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return metadata.sort((a, b) => (a.ts > b.ts ? -1 : 1));
|
|
147
|
+
}
|
package/dist/agent/chunker.js
CHANGED
|
@@ -1,25 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AIGENCY CLI — kullanıcı prompt'u ve history için basit chunker.
|
|
3
|
-
*
|
|
4
|
-
* Faz 4 scope'u: basit token budget kontrolü + history trim.
|
|
5
|
-
* Faz 5'te gelişmiş chunked streaming (proje dosyalarını parçalara bölüp
|
|
6
|
-
* ardışık stream istekleriyle göndermek) eklenecek.
|
|
7
|
-
*
|
|
8
|
-
* Şu an:
|
|
9
|
-
* - Toplam token (history + prompt) tahmin et
|
|
10
|
-
* - Budget üstü ise en eski mesajları kırp
|
|
11
|
-
* - Kalan budget prompt + 20% response için yeterli değilse uyar
|
|
12
|
-
*/
|
|
13
|
-
/** Basit token tahmini — 1 token ≈ 4 karakter */
|
|
14
1
|
export function approxTokens(text) {
|
|
15
2
|
return Math.ceil(text.length / 4);
|
|
16
3
|
}
|
|
17
|
-
const DEFAULT_MAX_CONTEXT = 120_000;
|
|
4
|
+
const DEFAULT_MAX_CONTEXT = 120_000;
|
|
18
5
|
const DEFAULT_RESERVE_RESPONSE = 8_000;
|
|
19
6
|
const DEFAULT_RESERVE_SYSTEM = 4_000;
|
|
20
|
-
/**
|
|
21
|
-
* History'yi budget'a sığdırır — eskiden başlayarak kırpar.
|
|
22
|
-
*/
|
|
23
7
|
export function prepareChunk(prompt, history, options = {}) {
|
|
24
8
|
const maxContext = options.maxContextTokens || DEFAULT_MAX_CONTEXT;
|
|
25
9
|
const reserveResponse = options.reserveForResponse || DEFAULT_RESERVE_RESPONSE;
|
|
@@ -34,7 +18,6 @@ export function prepareChunk(prompt, history, options = {}) {
|
|
|
34
18
|
warning: `Prompt tek başına ${promptTokens} token — context limiti (${available}) aşılıyor. Komutunuzu kısaltın.`,
|
|
35
19
|
};
|
|
36
20
|
}
|
|
37
|
-
// Sondan başa doğru ekle (son mesajlar daha önemli)
|
|
38
21
|
const reversed = [...history].reverse();
|
|
39
22
|
const selected = [];
|
|
40
23
|
let total = promptTokens;
|
|
@@ -56,4 +39,3 @@ export function prepareChunk(prompt, history, options = {}) {
|
|
|
56
39
|
warning,
|
|
57
40
|
};
|
|
58
41
|
}
|
|
59
|
-
//# sourceMappingURL=chunker.js.map
|
package/dist/agent/history.js
CHANGED
|
@@ -1,16 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AIGENCY CLI — sohbet geçmişi ring buffer.
|
|
3
|
-
*
|
|
4
|
-
* Kullanıcı + asistan mesajlarını tutar. /clear komutu sıfırlar.
|
|
5
|
-
* Chunked streaming sırasında bu history stream endpoint'ine gönderilir.
|
|
6
|
-
*/
|
|
7
1
|
const MAX_HISTORY = 40;
|
|
8
2
|
export class ChatHistory {
|
|
9
3
|
messages = [];
|
|
10
4
|
push(msg) {
|
|
11
5
|
const approxTokens = msg.approxTokens ?? Math.ceil((msg.content || "").length / 4);
|
|
12
6
|
this.messages.push({ ...msg, approxTokens });
|
|
13
|
-
// Ring buffer — en eski mesajları kırp
|
|
14
7
|
while (this.messages.length > MAX_HISTORY) {
|
|
15
8
|
this.messages.shift();
|
|
16
9
|
}
|
|
@@ -24,7 +17,6 @@ export class ChatHistory {
|
|
|
24
17
|
length() {
|
|
25
18
|
return this.messages.length;
|
|
26
19
|
}
|
|
27
|
-
/** Son N mesajı döner — stream endpoint'ine bunu gönderiyoruz */
|
|
28
20
|
tail(n) {
|
|
29
21
|
return this.messages.slice(-n);
|
|
30
22
|
}
|
|
@@ -32,4 +24,3 @@ export class ChatHistory {
|
|
|
32
24
|
return this.messages.reduce((acc, m) => acc + (m.approxTokens || 0), 0);
|
|
33
25
|
}
|
|
34
26
|
}
|
|
35
|
-
//# sourceMappingURL=history.js.map
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { getUserInstructionsFile, getProjectInstructionsFile, getProjectAigencyDir, } from "../config/paths.js";
|
|
4
|
+
import { log } from "../utils/logger.js";
|
|
5
|
+
const MAX_PER_FILE = 32 * 1024;
|
|
6
|
+
const MAX_TOTAL = 96 * 1024;
|
|
7
|
+
const MAX_WALK_DEPTH = 10;
|
|
8
|
+
export async function loadInstructions(projectRoot, cwd = process.cwd()) {
|
|
9
|
+
const sources = [];
|
|
10
|
+
let totalBytes = 0;
|
|
11
|
+
const tryAdd = async (label, filePath) => {
|
|
12
|
+
if (totalBytes >= MAX_TOTAL)
|
|
13
|
+
return;
|
|
14
|
+
const content = await readFileIfExists(filePath);
|
|
15
|
+
if (!content)
|
|
16
|
+
return;
|
|
17
|
+
const trimmed = content.slice(0, MAX_PER_FILE);
|
|
18
|
+
const remaining = MAX_TOTAL - totalBytes;
|
|
19
|
+
const finalContent = trimmed.slice(0, remaining);
|
|
20
|
+
sources.push({
|
|
21
|
+
label,
|
|
22
|
+
path: filePath,
|
|
23
|
+
content: finalContent,
|
|
24
|
+
sizeBytes: finalContent.length,
|
|
25
|
+
});
|
|
26
|
+
totalBytes += finalContent.length;
|
|
27
|
+
};
|
|
28
|
+
await tryAdd("global", getUserInstructionsFile());
|
|
29
|
+
await tryAdd("project", getProjectInstructionsFile(projectRoot));
|
|
30
|
+
await tryAdd("local", path.join(getProjectAigencyDir(projectRoot), "AIGENCY.local.md"));
|
|
31
|
+
const rootInstructions = path.join(projectRoot, "AIGENCY.md");
|
|
32
|
+
if (rootInstructions !== getProjectInstructionsFile(projectRoot)) {
|
|
33
|
+
await tryAdd("project-root", rootInstructions);
|
|
34
|
+
}
|
|
35
|
+
if (isInside(cwd, projectRoot) && cwd !== projectRoot) {
|
|
36
|
+
let current = path.resolve(cwd);
|
|
37
|
+
const root = path.resolve(projectRoot);
|
|
38
|
+
let depth = 0;
|
|
39
|
+
while (current !== root && depth < MAX_WALK_DEPTH) {
|
|
40
|
+
const local = path.join(current, ".aigency", "AIGENCY.md");
|
|
41
|
+
const bare = path.join(current, "AIGENCY.md");
|
|
42
|
+
await tryAdd(`cwd:${path.relative(root, current)}`, local);
|
|
43
|
+
await tryAdd(`cwd-root:${path.relative(root, current)}`, bare);
|
|
44
|
+
const parent = path.dirname(current);
|
|
45
|
+
if (parent === current)
|
|
46
|
+
break;
|
|
47
|
+
current = parent;
|
|
48
|
+
depth++;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
sources,
|
|
53
|
+
totalBytes,
|
|
54
|
+
combinedText: buildCombinedText(sources),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
async function readFileIfExists(p) {
|
|
58
|
+
try {
|
|
59
|
+
const stat = await fs.stat(p);
|
|
60
|
+
if (!stat.isFile())
|
|
61
|
+
return null;
|
|
62
|
+
const raw = await fs.readFile(p, "utf8");
|
|
63
|
+
return raw.includes("\u0000") ? null : raw;
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
const code = err?.code;
|
|
67
|
+
if (code && code !== "ENOENT") {
|
|
68
|
+
log.debug(`AIGENCY.md okuma hatası: ${err.message}`);
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function isInside(child, parent) {
|
|
74
|
+
const rel = path.relative(path.resolve(parent), path.resolve(child));
|
|
75
|
+
return !rel.startsWith("..") && !path.isAbsolute(rel);
|
|
76
|
+
}
|
|
77
|
+
function buildCombinedText(sources) {
|
|
78
|
+
if (sources.length === 0)
|
|
79
|
+
return "";
|
|
80
|
+
const parts = [
|
|
81
|
+
"## Kullanıcı Talimatları (AIGENCY.md)",
|
|
82
|
+
"Projede geçerli olan ve her oturumda zorunlu uygulanan talimatlar aşağıdadır.",
|
|
83
|
+
"",
|
|
84
|
+
];
|
|
85
|
+
for (const src of sources) {
|
|
86
|
+
parts.push(`### Kaynak: ${src.label}`);
|
|
87
|
+
parts.push("```markdown");
|
|
88
|
+
parts.push(src.content.trim());
|
|
89
|
+
parts.push("```");
|
|
90
|
+
parts.push("");
|
|
91
|
+
}
|
|
92
|
+
parts.push("Yukarıdaki talimatlar SİSTEM KURALLARINDAN sonra, kullanıcı mesajından ÖNCE geçerlidir.", "Birden fazla kaynak çelişirse: lokal (kişisel) > proje > global sırasıyla öncelik ver.");
|
|
93
|
+
return parts.join("\n");
|
|
94
|
+
}
|