cliskill 1.0.0 → 1.0.2
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 +159 -44
- package/dist/bootstrap/cli.js +1 -1
- package/dist/{chunk-ULZHJVWD.js → chunk-GCXQJ2SV.js} +110 -18
- package/dist/chunk-GCXQJ2SV.js.map +1 -0
- package/dist/index.d.ts +16 -7
- package/dist/index.js +1 -1
- package/package.json +1 -2
- package/dist/chunk-ULZHJVWD.js.map +0 -1
package/README.md
CHANGED
|
@@ -6,9 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
**Независимый AI-ассистент для терминала с поддержкой любых LLM провайдеров**
|
|
8
8
|
|
|
9
|
-
[]()
|
|
10
9
|
[](LICENSE)
|
|
11
|
-
[]()
|
|
12
11
|
[]()
|
|
13
12
|
|
|
14
13
|
[Бесплатный](#) · [Без подписок](#) · [Без vendor lock-in](#) · [Универсальный](#)
|
|
@@ -21,10 +20,13 @@
|
|
|
21
20
|
|
|
22
21
|
- [О проекте](#-о-проекте)
|
|
23
22
|
- [Возможности](#-возможности)
|
|
24
|
-
- [
|
|
23
|
+
- [Быстрый старт](#-быстрый-старт)
|
|
25
24
|
- [Использование](#-использование)
|
|
26
25
|
- [Конфигурация](#-конфигурация)
|
|
26
|
+
- [Инструменты](#-инструменты)
|
|
27
|
+
- [Агентская система](#-агентская-система)
|
|
27
28
|
- [Архитектура](#-архитектура)
|
|
29
|
+
- [API провайдеры](#-api-провайдеры)
|
|
28
30
|
- [Разработка](#-разработка)
|
|
29
31
|
- [Технологии](#-технологии)
|
|
30
32
|
- [Лицензия](#-лицензия)
|
|
@@ -58,37 +60,6 @@
|
|
|
58
60
|
- **Автоматический fallback** — переключение на резервные модели при ошибках
|
|
59
61
|
- **Rate Limit Handler** — корректная обработка лимитов без upsell
|
|
60
62
|
|
|
61
|
-
### 🔧 Инструменты (15 штук)
|
|
62
|
-
|
|
63
|
-
| Инструмент | Описание |
|
|
64
|
-
|------------|----------|
|
|
65
|
-
| 🖥️ **Bash Tool** | Выполнение shell команд с инспекцией безопасности |
|
|
66
|
-
| 📄 **File Read** | Чтение файлов с поддержкой изображений |
|
|
67
|
-
| ✏️ **File Write** | Создание и перезапись файлов |
|
|
68
|
-
| 📝 **File Edit** | Точечное редактирование файлов (search/replace) |
|
|
69
|
-
| 🔍 **Glob** | Поиск файлов по паттернам |
|
|
70
|
-
| 🔎 **Grep** | Поиск текста с поддержкой regex |
|
|
71
|
-
| 🌐 **Web Search** | Веб-поиск через поисковые системы |
|
|
72
|
-
| 🌍 **Web Fetch** | Загрузка и парсинг веб-страниц |
|
|
73
|
-
| 🤖 **Agent Tool** | Порождение суб-агентов для подзадач |
|
|
74
|
-
| 📡 **LSP Tool** | Интеграция с Language Server Protocol |
|
|
75
|
-
| ✅ **Todo Write** | Управление списками задач |
|
|
76
|
-
| 🖱️ **Computer Use** | Управление мышью и клавиатурой |
|
|
77
|
-
| 🔗 **Remote Tool** | Выполнение команд на удалённых серверах через SSH |
|
|
78
|
-
| 🌳 **Worktree Tool** | Управление git worktree для параллельной работы |
|
|
79
|
-
| 📋 **Plan Mode** | Планирование с 3 параллельными агентами |
|
|
80
|
-
|
|
81
|
-
### 🤖 Агентская система
|
|
82
|
-
|
|
83
|
-
- **Auto Mode** — 3 уровня автономности:
|
|
84
|
-
- `full-auto` — полная автономия, все действия без подтверждения
|
|
85
|
-
- `safe-auto` — автоматическое выполнение безопасных операций
|
|
86
|
-
- `ask` — подтверждение каждого действия (по умолчанию)
|
|
87
|
-
- **Fast Mode** — оптимизации скорости ответов
|
|
88
|
-
- **Multi-Agent Plan Mode V2** — 3 параллельных агента для планирования
|
|
89
|
-
- **Swarm Coordinator** — мульти-агентная координация сложных задач
|
|
90
|
-
- **Task System** — фоновые задачи с отслеживанием статуса
|
|
91
|
-
|
|
92
63
|
### 🏗️ Инфраструктура
|
|
93
64
|
|
|
94
65
|
| Система | Описание |
|
|
@@ -105,7 +76,7 @@
|
|
|
105
76
|
### 🛠️ Утилиты
|
|
106
77
|
|
|
107
78
|
- 🎬 **Asciicast Recording** — запись сессий в формате asciicast v2
|
|
108
|
-
- 🎨 **ANSI→SVG** —
|
|
79
|
+
- 🎨 **ANSI→SVG** — рендеринг терминального вывода в SVG
|
|
109
80
|
- 🔄 **Conversation Recovery** — умное восстановление сессий с ремонтом
|
|
110
81
|
- 🔗 **Deep Links** — протокол `cliskill://` для интеграции с ОС
|
|
111
82
|
- 🧹 **Background Housekeeping** — автоматическая очистка и обслуживание
|
|
@@ -116,13 +87,13 @@
|
|
|
116
87
|
|
|
117
88
|
---
|
|
118
89
|
|
|
119
|
-
## 📦
|
|
90
|
+
## 📦 Быстрый старт
|
|
120
91
|
|
|
121
|
-
###
|
|
92
|
+
### Установка из исходников
|
|
122
93
|
|
|
123
94
|
```bash
|
|
124
95
|
# Клонирование репозитория
|
|
125
|
-
git clone
|
|
96
|
+
git clone https://github.com/nic11/cliskill.git
|
|
126
97
|
cd cliskill
|
|
127
98
|
|
|
128
99
|
# Установка зависимостей
|
|
@@ -135,11 +106,27 @@ npm run build
|
|
|
135
106
|
npm link
|
|
136
107
|
```
|
|
137
108
|
|
|
109
|
+
### Установка из npm
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
npm install -g cliskill
|
|
113
|
+
```
|
|
114
|
+
|
|
138
115
|
### Требования
|
|
139
116
|
|
|
140
117
|
- **Node.js** >= 20.0.0
|
|
141
118
|
- **npm** >= 9.0.0
|
|
142
119
|
|
|
120
|
+
### Первый запуск
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
# Интерактивный мастер настройки
|
|
124
|
+
cliskill
|
|
125
|
+
|
|
126
|
+
# Или с явным указанием провайдера
|
|
127
|
+
cliskill --base-url https://api.example.com/v1 --api-key your-key
|
|
128
|
+
```
|
|
129
|
+
|
|
143
130
|
---
|
|
144
131
|
|
|
145
132
|
## 🚀 Использование
|
|
@@ -289,8 +276,8 @@ cliskill open-uri "cliskill://prompt?text=hello" # обработать URI
|
|
|
289
276
|
### Переменные окружения
|
|
290
277
|
|
|
291
278
|
```bash
|
|
292
|
-
export CLISKILL_API_KEY="
|
|
293
|
-
export CLISKILL_BASE_URL="https://api.
|
|
279
|
+
export CLISKILL_API_KEY="your-api-key"
|
|
280
|
+
export CLISKILL_BASE_URL="https://api.example.com/v1"
|
|
294
281
|
```
|
|
295
282
|
|
|
296
283
|
### Форматы провайдеров
|
|
@@ -326,6 +313,68 @@ description: Описание навыка
|
|
|
326
313
|
|
|
327
314
|
---
|
|
328
315
|
|
|
316
|
+
## 🔧 Инструменты
|
|
317
|
+
|
|
318
|
+
cliskill включает 15 встроенных инструментов для полноценной работы:
|
|
319
|
+
|
|
320
|
+
| # | Инструмент | Описание | Категория |
|
|
321
|
+
|---|------------|----------|-----------|
|
|
322
|
+
| 1 | 🖥️ **Bash** | Выполнение shell команд с инспекцией безопасности | Выполнение |
|
|
323
|
+
| 2 | 📄 **File Read** | Чтение файлов с поддержкой изображений | Файлы |
|
|
324
|
+
| 3 | ✏️ **File Write** | Создание и перезапись файлов | Файлы |
|
|
325
|
+
| 4 | 📝 **File Edit** | Точечное редактирование файлов (search/replace) | Файлы |
|
|
326
|
+
| 5 | 🔍 **Glob** | Поиск файлов по паттернам | Поиск |
|
|
327
|
+
| 6 | 🔎 **Grep** | Поиск текста с поддержкой regex | Поиск |
|
|
328
|
+
| 7 | 🌐 **Web Search** | Веб-поиск через поисковые системы | Веб |
|
|
329
|
+
| 8 | 🌍 **Web Fetch** | Загрузка и парсинг веб-страниц | Веб |
|
|
330
|
+
| 9 | 🤖 **Agent** | Порождение суб-агентов для подзадач | Агенты |
|
|
331
|
+
| 10 | 📡 **LSP** | Интеграция с Language Server Protocol | IDE |
|
|
332
|
+
| 11 | ✅ **Todo Write** | Управление списками задач | Планирование |
|
|
333
|
+
| 12 | 🖱️ **Computer Use** | Управление мышью и клавиатурой | Автоматизация |
|
|
334
|
+
| 13 | 🔗 **Remote** | Выполнение команд на удалённых серверах через SSH | Удалённый доступ |
|
|
335
|
+
| 14 | 🌳 **Worktree** | Управление git worktree для параллельной работы | Git |
|
|
336
|
+
| 15 | 📋 **Plan Mode** | Планирование с 3 параллельными агентами | Планирование |
|
|
337
|
+
|
|
338
|
+
### Безопасность инструментов
|
|
339
|
+
|
|
340
|
+
Инструменты классифицируются по уровню безопасности:
|
|
341
|
+
|
|
342
|
+
- **readOnly** (Glob, Grep, File Read, LSP) — могут выполняться параллельно
|
|
343
|
+
- **write** (File Write, File Edit, Bash) — выполняются эксклюзивно
|
|
344
|
+
- **network** (Web Search, Web Fetch) — контролируемые сетевые операции
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
## 🤖 Агентская система
|
|
349
|
+
|
|
350
|
+
### Auto Mode
|
|
351
|
+
|
|
352
|
+
3 уровня автономности для автоматического выполнения задач:
|
|
353
|
+
|
|
354
|
+
| Уровень | Описание | Подтверждение |
|
|
355
|
+
|---------|----------|---------------|
|
|
356
|
+
| `full-auto` | Полная автономия | Все действия без подтверждения |
|
|
357
|
+
| `safe-auto` | Безопасная автономия | Только потенциально опасные операции |
|
|
358
|
+
| `ask` | Ручное управление | Каждое действие (по умолчанию) |
|
|
359
|
+
|
|
360
|
+
### Multi-Agent система
|
|
361
|
+
|
|
362
|
+
- **Fast Mode** — оптимизации скорости ответов
|
|
363
|
+
- **Multi-Agent Plan Mode V2** — 3 параллельных агента для планирования
|
|
364
|
+
- **Swarm Coordinator** — мульти-агентная координация сложных задач
|
|
365
|
+
- **Task System** — фоновые задачи с отслеживанием статуса
|
|
366
|
+
|
|
367
|
+
### Agent Loop
|
|
368
|
+
|
|
369
|
+
Ядро системы — агентский цикл с поддержкой:
|
|
370
|
+
|
|
371
|
+
- **Streaming** — потоковая обработка ответов LLM
|
|
372
|
+
- **Tool calling** — параллельный вызов инструментов
|
|
373
|
+
- **Error recovery** — 3-уровневая стратегия восстановления при `max_tokens`
|
|
374
|
+
- **Context management** — автоматическое сжатие при переполнении контекста
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
329
378
|
## 🏛️ Архитектура
|
|
330
379
|
|
|
331
380
|
```
|
|
@@ -344,7 +393,7 @@ src/
|
|
|
344
393
|
├── 🐝 swarm/ — Мульти-агентная координация
|
|
345
394
|
├── 📋 tasks/ — Фоновые задачи
|
|
346
395
|
├── 🔗 remote/ — SSH сессии
|
|
347
|
-
├── 🧩 extensions/ — Расширения
|
|
396
|
+
├── 🧩 extensions/ — Расширения и навыки
|
|
348
397
|
├── 🏗️ infra/ — Инфраструктурные модули
|
|
349
398
|
└── 🔀 utils/ — Общие утилиты
|
|
350
399
|
```
|
|
@@ -372,6 +421,60 @@ graph TB
|
|
|
372
421
|
Swarm --> Tasks[Task System]
|
|
373
422
|
```
|
|
374
423
|
|
|
424
|
+
### Поток данных
|
|
425
|
+
|
|
426
|
+
```mermaid
|
|
427
|
+
sequenceDiagram
|
|
428
|
+
participant U as User
|
|
429
|
+
participant R as REPL/TUI
|
|
430
|
+
participant L as Agent Loop
|
|
431
|
+
participant P as Provider Adapter
|
|
432
|
+
participant T as Tool System
|
|
433
|
+
|
|
434
|
+
U->>R: Ввод запроса
|
|
435
|
+
R->>L: Передача сообщения
|
|
436
|
+
L->>P: API запрос (streaming)
|
|
437
|
+
P-->>L: Потоковый ответ
|
|
438
|
+
L->>T: Вызов инструментов
|
|
439
|
+
T-->>L: Результат выполнения
|
|
440
|
+
L->>P: Продолжение диалога
|
|
441
|
+
P-->>L: Финальный ответ
|
|
442
|
+
L-->>R: Событие результата
|
|
443
|
+
R-->>U: Отображение ответа
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
## 🌐 API провайдеры
|
|
449
|
+
|
|
450
|
+
### Поддерживаемые форматы
|
|
451
|
+
|
|
452
|
+
cliskill работает с **любым** API, совместимым с OpenAI `/chat/completions`:
|
|
453
|
+
|
|
454
|
+
| Провайдер | Base URL | Формат |
|
|
455
|
+
|-----------|----------|--------|
|
|
456
|
+
| OpenAI | `https://api.openai.com/v1` | `openai-compatible` |
|
|
457
|
+
| GLM / Z.AI | `https://api.z.ai/api/coding/paas/v4` | `openai-compatible` |
|
|
458
|
+
| DeepSeek | `https://api.deepseek.com/v1` | `openai-compatible` |
|
|
459
|
+
| LocalAI | `http://localhost:8080/v1` | `openai-compatible` |
|
|
460
|
+
| Ollama | `http://localhost:11434/v1` | `openai-compatible` |
|
|
461
|
+
| LM Studio | `http://localhost:1234/v1` | `openai-compatible` |
|
|
462
|
+
| Любой другой | `<your-endpoint>/v1` | `openai-compatible` |
|
|
463
|
+
|
|
464
|
+
### Модель алиасов
|
|
465
|
+
|
|
466
|
+
Предустановленные алиасы для быстрого переключения моделей:
|
|
467
|
+
|
|
468
|
+
| Алиас | Описание | Модель по умолчанию |
|
|
469
|
+
|-------|----------|---------------------|
|
|
470
|
+
| `smart` | Максимальное качество | `gpt-4o` |
|
|
471
|
+
| `fast` | Быстрые ответы | `gpt-4o-mini` |
|
|
472
|
+
| `balanced` | Баланс качества/скорости | `gpt-4o` |
|
|
473
|
+
| `reasoning` | Логические задачи | `o1` |
|
|
474
|
+
| `code` | Код-специфичные задачи | `gpt-4o` |
|
|
475
|
+
|
|
476
|
+
Алиасы настраиваются в `.cliskillrc.json` → `models.aliases`.
|
|
477
|
+
|
|
375
478
|
---
|
|
376
479
|
|
|
377
480
|
## 👨💻 Разработка
|
|
@@ -382,7 +485,7 @@ graph TB
|
|
|
382
485
|
npm install # Установить зависимости
|
|
383
486
|
npm run build # Сборка проекта (tsup)
|
|
384
487
|
npm run dev # Разработка с watch-режимом
|
|
385
|
-
npm test # Запустить тесты (
|
|
488
|
+
npm test # Запустить тесты (Vitest)
|
|
386
489
|
npm run test:watch # Тесты в watch-режиме
|
|
387
490
|
npm run typecheck # Проверка типов TypeScript
|
|
388
491
|
npm run lint # Линтинг (= typecheck)
|
|
@@ -423,6 +526,19 @@ src/
|
|
|
423
526
|
└── bash-parser.ts / .test.ts
|
|
424
527
|
```
|
|
425
528
|
|
|
529
|
+
### Добавление нового инструмента
|
|
530
|
+
|
|
531
|
+
1. Создайте файл в `src/tools/builtins/your-tool.ts`
|
|
532
|
+
2. Реализуйте интерфейс `Tool` из `src/tools/types.ts`
|
|
533
|
+
3. Зарегистрируйте в `src/tools/builtins/index.ts`
|
|
534
|
+
4. Добавьте тесты `your-tool.test.ts`
|
|
535
|
+
|
|
536
|
+
### Добавление нового провайдера
|
|
537
|
+
|
|
538
|
+
1. Создайте адаптер в `src/connect/your-adapter.ts`
|
|
539
|
+
2. Реализуйте интерфейс `ProviderAdapter` из `src/connect/types.ts`
|
|
540
|
+
3. Зарегистрируйте в `src/connect/registry.ts`
|
|
541
|
+
|
|
426
542
|
---
|
|
427
543
|
|
|
428
544
|
## 🧪 Технологии
|
|
@@ -445,14 +561,13 @@ src/
|
|
|
445
561
|
| [Ink](https://github.com/vadimdemedes/ink) / [React](https://react.dev) | Terminal UI |
|
|
446
562
|
| [Ora](https://github.com/sindresorhus/ora) | Спиннеры загрузки |
|
|
447
563
|
| [ssh2](https://github.com/mscdex/ssh2) | SSH подключения |
|
|
448
|
-
| [dotenv](https://github.com/motdotla/dotenv) | Переменные окружения |
|
|
449
564
|
|
|
450
565
|
### Dev-зависимости
|
|
451
566
|
|
|
452
567
|
| Библиотека | Назначение |
|
|
453
568
|
|------------|------------|
|
|
454
569
|
| [tsup](https://tsup.egoist.dev) | Сборка (esbuild-based) |
|
|
455
|
-
| [Vitest](https://vitest.dev) | Тестирование
|
|
570
|
+
| [Vitest](https://vitest.dev) | Тестирование |
|
|
456
571
|
| [TypeScript](https://www.typescriptlang.org) | Компилятор и проверка типов |
|
|
457
572
|
|
|
458
573
|
---
|
package/dist/bootstrap/cli.js
CHANGED
|
@@ -388,6 +388,19 @@ var BaseAdapter = class {
|
|
|
388
388
|
}
|
|
389
389
|
return timeoutSignal;
|
|
390
390
|
}
|
|
391
|
+
/**
|
|
392
|
+
* Build an AbortSignal for streaming requests with extended timeout.
|
|
393
|
+
* Streaming responses can take much longer than regular requests,
|
|
394
|
+
* so we use 3x the configured timeout to avoid premature aborts.
|
|
395
|
+
*/
|
|
396
|
+
buildStreamingSignal(external) {
|
|
397
|
+
const streamTimeout = Math.max(this.config.timeout * 3, 6e5);
|
|
398
|
+
const timeoutSignal = AbortSignal.timeout(streamTimeout);
|
|
399
|
+
if (external) {
|
|
400
|
+
return AbortSignal.any([timeoutSignal, external]);
|
|
401
|
+
}
|
|
402
|
+
return timeoutSignal;
|
|
403
|
+
}
|
|
391
404
|
/**
|
|
392
405
|
* Fetch with automatic retry for rate-limit (429), server errors (5xx),
|
|
393
406
|
* and network failures (TypeError: fetch failed).
|
|
@@ -461,7 +474,7 @@ var GenericCompatAdapter = class extends BaseAdapter {
|
|
|
461
474
|
method: "POST",
|
|
462
475
|
headers: this.buildHeaders(),
|
|
463
476
|
body: JSON.stringify(body),
|
|
464
|
-
signal: this.
|
|
477
|
+
signal: this.buildStreamingSignal(request.signal)
|
|
465
478
|
}));
|
|
466
479
|
if (!response.ok) {
|
|
467
480
|
const text = await response.text().catch(() => "unknown error");
|
|
@@ -670,7 +683,7 @@ var GLMAdapter = class extends BaseAdapter {
|
|
|
670
683
|
method: "POST",
|
|
671
684
|
headers: this.buildHeaders(),
|
|
672
685
|
body: JSON.stringify(body),
|
|
673
|
-
signal: this.
|
|
686
|
+
signal: this.buildStreamingSignal(request.signal)
|
|
674
687
|
}));
|
|
675
688
|
if (!response.ok) {
|
|
676
689
|
const text = await response.text().catch(() => "unknown error");
|
|
@@ -2061,14 +2074,16 @@ import { z as z13 } from "zod";
|
|
|
2061
2074
|
var webSearchInputSchema = z13.object({
|
|
2062
2075
|
query: z13.string().describe("Search query"),
|
|
2063
2076
|
max_results: z13.number().default(5).describe("Maximum number of results"),
|
|
2064
|
-
search_engine: z13.enum(["duckduckgo", "
|
|
2077
|
+
search_engine: z13.enum(["duckduckgo", "wikipedia"]).default("duckduckgo").describe("Search engine to use")
|
|
2065
2078
|
});
|
|
2066
2079
|
var SEARCH_TIMEOUT_MS = 15e3;
|
|
2067
2080
|
var DDG_HTML_URL = "https://html.duckduckgo.com/html/?q=";
|
|
2068
2081
|
var DDG_LITE_URL = "https://lite.duckduckgo.com/lite/?q=";
|
|
2082
|
+
var WIKI_API_URL = "https://en.wikipedia.org/w/api.php";
|
|
2069
2083
|
var COMMON_HEADERS = {
|
|
2070
|
-
"User-Agent": "Mozilla/5.0 (
|
|
2071
|
-
Accept: "text/html"
|
|
2084
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
|
|
2085
|
+
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
2086
|
+
"Accept-Language": "en-US,en;q=0.5"
|
|
2072
2087
|
};
|
|
2073
2088
|
function parseDuckDuckGoHtml(html, maxResults) {
|
|
2074
2089
|
const results = [];
|
|
@@ -2120,6 +2135,15 @@ function parseDuckDuckGoLite(html, maxResults) {
|
|
|
2120
2135
|
}
|
|
2121
2136
|
return results;
|
|
2122
2137
|
}
|
|
2138
|
+
function parseWikipediaResults(data, maxResults) {
|
|
2139
|
+
const search = data.query?.search;
|
|
2140
|
+
if (!search) return [];
|
|
2141
|
+
return search.slice(0, maxResults).map((item) => ({
|
|
2142
|
+
title: item.title,
|
|
2143
|
+
url: `https://en.wikipedia.org/wiki/${encodeURIComponent(item.title.replace(/ /g, "_"))}`,
|
|
2144
|
+
snippet: stripTags(item.snippet)
|
|
2145
|
+
}));
|
|
2146
|
+
}
|
|
2123
2147
|
function stripTags(html) {
|
|
2124
2148
|
return html.replace(/<[^>]+>/g, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/ /g, " ").trim();
|
|
2125
2149
|
}
|
|
@@ -2141,13 +2165,13 @@ No results found. Try rephrasing your query or use web_fetch for specific URLs.`
|
|
|
2141
2165
|
}
|
|
2142
2166
|
return lines.join("\n").trim();
|
|
2143
2167
|
}
|
|
2144
|
-
async function fetchWithTimeout(url) {
|
|
2168
|
+
async function fetchWithTimeout(url, headers) {
|
|
2145
2169
|
const controller = new AbortController();
|
|
2146
2170
|
const timeout = setTimeout(() => controller.abort(), SEARCH_TIMEOUT_MS);
|
|
2147
2171
|
try {
|
|
2148
2172
|
const response = await fetch(url, {
|
|
2149
2173
|
signal: controller.signal,
|
|
2150
|
-
headers: COMMON_HEADERS,
|
|
2174
|
+
headers: headers ?? COMMON_HEADERS,
|
|
2151
2175
|
redirect: "follow"
|
|
2152
2176
|
});
|
|
2153
2177
|
return response;
|
|
@@ -2157,32 +2181,58 @@ async function fetchWithTimeout(url) {
|
|
|
2157
2181
|
}
|
|
2158
2182
|
var WebSearchTool = class extends BaseTool {
|
|
2159
2183
|
name = "web_search";
|
|
2160
|
-
description = "Search the web for information";
|
|
2184
|
+
description = "Search the web for information using DuckDuckGo or Wikipedia";
|
|
2161
2185
|
inputSchema = webSearchInputSchema;
|
|
2162
2186
|
riskLevel = "safe";
|
|
2163
2187
|
concurrencySafe = true;
|
|
2164
2188
|
readOnly = true;
|
|
2165
2189
|
async execute(input, _context) {
|
|
2166
|
-
if (input.search_engine !== "duckduckgo") {
|
|
2167
|
-
return `Error: Only DuckDuckGo search engine is currently supported. Use web_fetch for other sources.`;
|
|
2168
|
-
}
|
|
2169
2190
|
const encodedQuery = encodeURIComponent(input.query);
|
|
2191
|
+
if (input.search_engine === "wikipedia") {
|
|
2192
|
+
return this.searchWikipedia(input.query, encodedQuery, input.max_results);
|
|
2193
|
+
}
|
|
2194
|
+
return this.searchDuckDuckGo(input.query, encodedQuery, input.max_results);
|
|
2195
|
+
}
|
|
2196
|
+
async searchDuckDuckGo(query, encodedQuery, maxResults) {
|
|
2170
2197
|
try {
|
|
2171
2198
|
const response = await fetchWithTimeout(`${DDG_HTML_URL}${encodedQuery}`);
|
|
2172
2199
|
if (!response.ok) {
|
|
2173
|
-
return
|
|
2200
|
+
return this.fallbackToWikipedia(
|
|
2201
|
+
query,
|
|
2202
|
+
encodedQuery,
|
|
2203
|
+
maxResults,
|
|
2204
|
+
`DuckDuckGo returned HTTP ${response.status}`
|
|
2205
|
+
);
|
|
2174
2206
|
}
|
|
2175
2207
|
const html = await response.text();
|
|
2176
|
-
let results = parseDuckDuckGoHtml(html,
|
|
2208
|
+
let results = parseDuckDuckGoHtml(html, maxResults);
|
|
2177
2209
|
if (results.length === 0) {
|
|
2178
|
-
results = await this.fallbackLiteSearch(encodedQuery,
|
|
2210
|
+
results = await this.fallbackLiteSearch(encodedQuery, maxResults);
|
|
2179
2211
|
}
|
|
2180
|
-
|
|
2212
|
+
if (results.length === 0) {
|
|
2213
|
+
return this.fallbackToWikipedia(
|
|
2214
|
+
query,
|
|
2215
|
+
encodedQuery,
|
|
2216
|
+
maxResults,
|
|
2217
|
+
"DuckDuckGo returned no results"
|
|
2218
|
+
);
|
|
2219
|
+
}
|
|
2220
|
+
return formatResults(query, results);
|
|
2181
2221
|
} catch (err) {
|
|
2182
2222
|
if (err.name === "AbortError") {
|
|
2183
|
-
return
|
|
2223
|
+
return this.fallbackToWikipedia(
|
|
2224
|
+
query,
|
|
2225
|
+
encodedQuery,
|
|
2226
|
+
maxResults,
|
|
2227
|
+
"DuckDuckGo request timed out"
|
|
2228
|
+
);
|
|
2184
2229
|
}
|
|
2185
|
-
return
|
|
2230
|
+
return this.fallbackToWikipedia(
|
|
2231
|
+
query,
|
|
2232
|
+
encodedQuery,
|
|
2233
|
+
maxResults,
|
|
2234
|
+
err.message
|
|
2235
|
+
);
|
|
2186
2236
|
}
|
|
2187
2237
|
}
|
|
2188
2238
|
async fallbackLiteSearch(encodedQuery, maxResults) {
|
|
@@ -2195,6 +2245,48 @@ var WebSearchTool = class extends BaseTool {
|
|
|
2195
2245
|
return [];
|
|
2196
2246
|
}
|
|
2197
2247
|
}
|
|
2248
|
+
async searchWikipedia(query, encodedQuery, maxResults) {
|
|
2249
|
+
try {
|
|
2250
|
+
const url = `${WIKI_API_URL}?action=query&list=search&srsearch=${encodedQuery}&srlimit=${maxResults}&format=json&origin=*`;
|
|
2251
|
+
const response = await fetchWithTimeout(url, {
|
|
2252
|
+
"User-Agent": "cliskill/1.0 (https://github.com/nic11/cliskill)"
|
|
2253
|
+
});
|
|
2254
|
+
if (!response.ok) {
|
|
2255
|
+
return `Error: Wikipedia search failed with HTTP ${response.status}. Try web_fetch instead.`;
|
|
2256
|
+
}
|
|
2257
|
+
const data = await response.json();
|
|
2258
|
+
const results = parseWikipediaResults(data, maxResults);
|
|
2259
|
+
return formatResults(query, results);
|
|
2260
|
+
} catch (err) {
|
|
2261
|
+
if (err.name === "AbortError") {
|
|
2262
|
+
return "Error: Wikipedia search timed out after 15 seconds. Try web_fetch instead.";
|
|
2263
|
+
}
|
|
2264
|
+
return `Error searching Wikipedia: ${err.message}. Try web_fetch instead.`;
|
|
2265
|
+
}
|
|
2266
|
+
}
|
|
2267
|
+
async fallbackToWikipedia(query, encodedQuery, maxResults, reason) {
|
|
2268
|
+
const wikiResults = await this.searchWikipediaRaw(encodedQuery, maxResults);
|
|
2269
|
+
if (wikiResults.length > 0) {
|
|
2270
|
+
const header = `\u26A0\uFE0F DuckDuckGo unavailable (${reason}). Showing Wikipedia results:
|
|
2271
|
+
|
|
2272
|
+
`;
|
|
2273
|
+
return header + formatResults(query, wikiResults);
|
|
2274
|
+
}
|
|
2275
|
+
return `Error: Search failed (${reason}) and Wikipedia fallback returned no results. Try web_fetch for specific URLs.`;
|
|
2276
|
+
}
|
|
2277
|
+
async searchWikipediaRaw(encodedQuery, maxResults) {
|
|
2278
|
+
try {
|
|
2279
|
+
const url = `${WIKI_API_URL}?action=query&list=search&srsearch=${encodedQuery}&srlimit=${maxResults}&format=json&origin=*`;
|
|
2280
|
+
const response = await fetchWithTimeout(url, {
|
|
2281
|
+
"User-Agent": "cliskill/1.0 (https://github.com/nic11/cliskill)"
|
|
2282
|
+
});
|
|
2283
|
+
if (!response.ok) return [];
|
|
2284
|
+
const data = await response.json();
|
|
2285
|
+
return parseWikipediaResults(data, maxResults);
|
|
2286
|
+
} catch {
|
|
2287
|
+
return [];
|
|
2288
|
+
}
|
|
2289
|
+
}
|
|
2198
2290
|
};
|
|
2199
2291
|
|
|
2200
2292
|
// src/tools/builtins/lsp-tool.ts
|
|
@@ -9942,4 +10034,4 @@ export {
|
|
|
9942
10034
|
MessageList,
|
|
9943
10035
|
runCli
|
|
9944
10036
|
};
|
|
9945
|
-
//# sourceMappingURL=chunk-
|
|
10037
|
+
//# sourceMappingURL=chunk-GCXQJ2SV.js.map
|