Files
deepwork/README.md
T
Alex CubeandClaude Opus 5 f34e07e807 README для новичка, ASCII в батнике, лицензия
README переписан под человека, который видит проект впервые: что это вообще
такое (схемой), что понадобится, установка по шагам с проверкой на каждом,
как пользоваться пультом и консолью, чего ожидать по времени, таблица
"если не работает" на десять строк и отдельный раздел про безопасность.

Замеры и выводы прошлых прогонов сохранены — это самое ценное, что тут есть,
но убраны под "Что проверено вживую", а не вперемешку с инструкцией.

Поправлено попутно:
- start-deepwork.cmd стучался в порт 9333 и советовал запустить start-browser.cmd
  в ollama_orchestro; теперь проверяет deepseek-api на 11500. Заодно батник
  снова стал чисто ASCII, как ему и положено;
- в USAGE --timeout и --check ссылались на мост, --chat не знал про vision;
- добавлена LICENSE (MIT), на которую README ссылается, и .gitattributes:
  без него start-deepwork.cmd уехал бы в репозиторий с LF.

Раздел про обрезанные ответы поправлен по существу: обе поломки лечатся
в deepseek-api (отрисовка и кнопка Continue живут в его browser.mjs),
а не в ollama_orchestro, как было написано.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 13:53:54 +03:00

392 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# deepwork
**DeepSeek, который сам читает вашу папку с кодом.**
Обычный веб-чат видит только то, что вы вставили в вопрос. Спросишь «почему
падает вот эта функция» — и в ответ получишь три догадки, потому что остального
кода он не видел.
Здесь у него появляется обратное направление. DeepSeek отвечает не текстом,
а **запросом**: «пришлите мне файл `server.js`», «покажите, где встречается
`waitForAnswer`». Программа исполняет запрос, досылает данные, и так по кругу,
пока он не соберёт всё нужное и не ответит по существу.
```
вы: "почему падает загрузка?"
DeepSeek ──► "=== NEED: upload.js ==="
│ │
│ программа читает файл и досылает
│ │
▼ ▼
DeepSeek ──► "=== FIND: parseBody ==="
│ │
▼ ▼
DeepSeek ──► ответ по существу + исправленный файл
```
Читает он только вашу папку и только на чтение. Правки возвращает файлами,
которые вы записываете нажатием кнопки — или не записываете.
---
## Оглавление
1. [Что понадобится](#что-понадобится)
2. [Установка по шагам](#установка-по-шагам)
3. [Как пользоваться](#как-пользоваться)
4. [Что он умеет запрашивать](#что-он-умеет-запрашивать)
5. [Правки файлов](#правки-файлов)
6. [Настройка](#настройка)
7. [Если не работает](#если-не-работает)
8. [Безопасность](#безопасность)
9. [Как это устроено внутри](#как-это-устроено-внутри)
10. [Что проверено вживую](#что-проверено-вживую)
---
## Что понадобится
| Что | Зачем | Как проверить |
|---|---|---|
| **Windows** | скрипт запуска написан под неё | — |
| **Node.js 22 или новее** | на нём написана программа | `node --version``v22.…` и выше |
| **Сервис `deepseek-api`** | через него идёт разговор с DeepSeek | см. шаг 1 |
Node.js, если его нет, ставится с [nodejs.org](https://nodejs.org) — берите
версию LTS. После установки **закройте и откройте заново** командную строку,
иначе `node` в ней не найдётся.
---
## Установка по шагам
### Шаг 1. Поднять deepseek-api
У веб-версии DeepSeek нет API — только вкладка в браузере. Разговором с ней
занимается отдельная программа
[deepseek-api](https://git.08h.ru/alex/deepseek-api): она держит вкладку
и отдаёт наружу обычный HTTP.
Поставьте и запустите её по инструкции в её README — это отдельные пять шагов,
включая вход в аккаунт DeepSeek. Возвращайтесь сюда, когда заработает.
> **Проверка:**
> ```cmd
> curl http://localhost:11500/api/tags
> ```
> должен вернуть список из трёх «моделей». Окно `deepseek-api` при этом
> остаётся открытым — пока оно живо, работает и сервис.
### Шаг 2. Скачать deepwork
```cmd
cd C:\#Projects
git clone https://git.08h.ru/alex/deepwork.git
```
Без git — скачайте ZIP с той же страницы и распакуйте. Папка может лежать где
угодно; рядом с чем-то конкретным её класть не нужно.
> **Проверка:**
> ```cmd
> cd C:\#Projects\deepwork
> node deepwork.mjs --selftest
> ```
> Ответ `самопроверка пройдена`. Ничего никуда не отправляется.
### Шаг 3. Проверить связку
```cmd
node deepwork.mjs --check
```
Три возможных ответа:
| Что видно | Что это значит |
|---|---|
| `готов: браузер поднят, вкладка DeepSeek открыта` | всё на месте, можно работать |
| `не готов (HTTP 503)` | сервис жив, но браузер ещё не поднят — встанет сам на первом вопросе |
| `не отвечает: …` | `deepseek-api` не запущен, вернитесь к шагу 1 |
**Готово.** Настраивать больше нечего: адрес `http://localhost:11500` вшит
как значение по умолчанию.
---
## Как пользоваться
### Способ 1: пульт (обычный путь)
**Перетащите папку своего проекта мышкой на файл `start-deepwork.cmd`.**
Откроется страница в браузере:
- слева файлы папки — отметьте галочками те, что точно нужны (можно ни одного);
- поле вопроса;
- ход работы построчно: видно, что DeepSeek запросил и сколько это заняло;
- у каждого пришедшего файла кнопка «Записать».
Пульт открывается в браузере **по умолчанию**, а не в том, которым управляет
`deepseek-api`: иначе он занял бы там вкладку, и вкладка с чатом потерялась бы.
Порт 8787.
Остановить — `Ctrl+C` в чёрном окне.
### Способ 2: командная строка
Работает в **текущей** папке: её читает, в неё же пишет правки.
```cmd
cd C:\мой\проект
node C:\#Projects\deepwork\deepwork.mjs "почему падает загрузка файла?"
```
Полезные флаги:
| Флаг | Что делает |
|---|---|
| `--files a.js,b.js` | положить эти файлы в вопрос сразу |
| `--steps 6` | сколько кругов позволить (по умолчанию 4) |
| `--apply` | записать пришедшие файлы на диск (без него только покажет) |
| `--chat search` | режим с поиском в интернете вместо обычного |
| `--check` | проверить связку и выйти |
| `--selftest` | внутренние проверки, ничего не отправляя |
### Чего ожидать по времени
Один круг — 7–15 секунд. Обычная задача укладывается в два-три круга, то есть
полминуты. Если DeepSeek запросил много файлов, вопрос на следующем круге
вырастает до десятков килобайт — это нормально.
---
## Что он умеет запрашивать
Только чтение и только внутри текущей папки:
| Блок в ответе | Что делает |
|---|---|
| `=== NEED: путь, путь ===` | прислать файлы целиком |
| `=== LIST: **/*.mjs ===` | список файлов по маске |
| `=== FIND: текст ===` | где встречается текст, с номерами строк |
**Запуска команд (`RUN`) нет, и не будет.** Исполнять строки, пришедшие
из интернета, без белого списка и подтверждения нельзя — а белого списка,
который был бы и полезен, и безопасен, придумать не вышло.
Лимиты на один круг: `NEED` — 200 000 символов суммарно, `FIND` — 100
попаданий, `LIST` — 300 путей. Обрезанное помечается прямо в тексте, чтобы
DeepSeek видел, что данные неполные.
Цикл останавливается, когда запросов в ответе больше нет, когда кончились
круги или когда пришёл тот же самый запрос второй раз подряд — это петля,
данные ему уже присылали.
---
## Правки файлов
Исправленный код DeepSeek возвращает блоками:
```
=== FILE: src/upload.js ===
```
...содержимое целиком...
```
=== END FILE ===
```
Записываются они **только по вашей команде** — кнопкой «Записать» в пульте
или флагом `--apply` в консоли. Без этого программа просто перечислит, что
пришло.
**Прежняя версия не пропадает:** перед записью она уезжает в папку `backup/`
внутри проекта. Файлы вне рабочей папки не пишутся вовсе — путь проверяется.
---
## Настройка
Нужна редко. `config.json` рядом с программой (в репозиторий не попадает,
образец — `config.example.json`):
```json
{
"deepseekHost": "http://localhost:11500",
"deepseekModel": "deepseek:think",
"steps": 4,
"timeout": 240
}
```
| Ключ | По умолчанию | Смысл |
|---|---|---|
| `deepseekHost` | `http://localhost:11500` | адрес сервиса `deepseek-api` |
| `deepseekModel` | `deepseek:think` | режим чата: `think`, `search` или `vision` |
| `steps` | `4` | сколько кругов позволить |
| `timeout` | `240` | секунд на один круг (сверх этого сервису дают ещё две минуты на очередь) |
| `uiPort` | `8787` | порт пульта |
Без файла всё работает на значениях по умолчанию. А вот **битый** `config.json`
не молчит: программа скажет об ошибке, а не откатится тихо к умолчаниям —
иначе правка в настройках не действует, и понять почему невозможно.
---
## Если не работает
| Что видно | В чём дело | Что делать |
|---|---|---|
| `deepseek-api не отвечает по адресу …` | сервис не запущен | Запустите `start.cmd` в папке `deepseek-api` |
| `--check` говорит `не готов (HTTP 503)` | сервис жив, браузера ещё нет | Ничего: браузер встанет на первом же вопросе |
| `deepseek-api ответил 500` | что-то со вкладкой | `curl http://localhost:11500/api/probe` покажет, что там видно |
| **Ответ пришёл обрезанным**, код оборван на середине | окно браузера свёрнуто | Разверните его. Свёрнутое окно Windows не отрисовывает, а DeepSeek рисует блоки кода лениво — см. [ниже](#обрезанные-ответы-причина-найдена) |
| `шаг 1: запросов нет, готово`, а ответ — догадки | DeepSeek поленился спросить и придумал | Спросите конкретнее либо дайте файл сразу через `--files`. Так бывает; напоминание в конце вопроса помогает, но не всегда |
| `тот же запрос повторно — петля, выхожу` | он не принял присланные данные | Обычно значит, что запрошенного файла нет или он пуст. Посмотрите журнал шагов |
| `шаги кончились, а запросы ещё идут` | задача крупнее четырёх кругов | `--steps 6`, но сначала подумайте, не проще ли разбить вопрос |
| `DeepSeek занят: «Server is busy»` | лимиты на стороне DeepSeek | Подождите минуту |
| `node не является внутренней или внешней командой` | Node не установлен или консоль открыта до установки | Поставьте Node, **закройте и откройте заново** консоль |
| Чаты в DeepSeek пропадают сами | тот же профиль браузера использует другая программа | Дайте `deepseek-api` отдельный профиль |
---
## Безопасность
- **Ваш код уходит на серверы DeepSeek.** Не только присланные файлы: он сам
запрашивает то, что считает нужным, из всей рабочей папки. Для закрытых
проектов это не годится.
- **Ключей и паролей в папке быть не должно.** `.env`, `config.json` с токенами,
приватные ключи — всё это он может запросить, и это уедет наружу. Убирайте
такое из рабочей папки заранее.
- **Правки не применяются сами.** Только кнопкой или флагом `--apply`,
и прежняя версия всегда сохраняется в `backup/`.
- **За пределы рабочей папки программа не пишет** и не читает: путь
проверяется, `..` не проходит.
- **Пульт слушает только этот компьютер** (`127.0.0.1`), из сети к нему
не подключиться.
---
## Как это устроено внутри
### Разговор помним мы, а не DeepSeek
Сервис `deepseek-api` **без памяти**: каждый запрос он кладёт в чат целиком,
затирая прошлый. Поэтому стенограмму ведёт `deepwork` — функция
`growTranscript` подклеивает к отправленному тексту прошлый ответ модели
(между метками `=== ТВОЙ ПРЕДЫДУЩИЙ ОТВЕТ ===` и `=== END ===`) и результаты
запросов, и следующим кругом уезжает всё сразу.
Раньше память держал сам чат DeepSeek. Своя стенограмма надёжнее: видно
в одном месте, что именно уедет модели, а чужая программа, вклинившаяся между
нашими кругами, ничего не портит — мы всё приносим заново. Плата — вопрос
растёт на длину прошлого ответа; при четырёх кругах это единицы килобайт
против 22 КБ первого сообщения.
### Что уезжает в первом сообщении
1. Приставка из `agent-prompt.md` — кто он и какие блоки может вернуть.
2. **Дерево рабочей папки.** Без него первый живой прогон ушёл на угадывание
имён файлов, см. замеры ниже.
3. Файлы, отмеченные галочками (или переданные через `--files`).
4. **Напоминание про инструменты — вплотную к вопросу.** Не в начале: между
приставкой и вопросом ложатся килобайты файлов, и инструкция теряется.
5. Сам вопрос.
### Файлы
| Файл | Что в нём |
|---|---|
| `deepwork.mjs` | всё: цикл, инструменты, разбор ответов, пульт |
| `agent-prompt.md` | приставка к первому сообщению |
| `ui.html` | страница пульта |
| `config.json` | настройки (не в репозитории) |
| `start-deepwork.cmd` | запуск пульта перетаскиванием папки |
Зависимостей нет — только то, что есть в Node 22.
---
## Что проверено вживую
### Внутренние проверки (`--selftest`)
Разбор запросов, отказ пути за пределы папки, маски `*` и `**`, снятие тройных
кавычек и подписи языка. Строка вида `=== NEED: … ===` **внутри** блока
`=== FILE: ===` за запрос не принимается — иначе правка файла с описанием
формата запускала бы запрос сама. Пропавший файл в `NEED` возвращает «файла
нет» и цикл не роняет. `--steps 1` отдаёт ответ с пометкой «шаги кончились»,
а не зависает.
### Из чего выросли два правила, 11.08.2026
Задача одна и та же: спросить, где решается, что ответ дописан до конца, дав
в вопросе **заведомо не тот файл**. Правильный ответ достижим только через
инструменты.
| Прогон | Кругов | Что вышло |
|---|---|---|
| 1. приставка только в начале сообщения | 1 | **запросов нет.** «Точный код в серверном файле» и три догадки |
| 2. + напоминание вплотную к вопросу | 4 | нашёл, но два круга ушли на угадывание имён файлов |
| 3. + дерево папки в первом сообщении | **2** | запросил нужный файл сразу, ответил по существу |
- **Инструкция в начале сообщения не работает.** Между приставкой и вопросом
легли 22 КБ файла, и DeepSeek инструменты просто не заметил.
- **Дерево папки надо давать сразу.** Без него он угадывал имена (`server.js`,
`bridge.js` — таких в проекте нет), потом просил `LIST *.js` (проект
на `.mjs`, пусто), потом `LIST **/*`. Дерево — 600 символов против двух
кругов по минуте.
### Пульт, 11.08.2026
Вопрос без единого приложенного файла — «какая функция решает, что ответ
дописан?». 36 секунд, три круга: пять блоков `FIND` сразу, затем `NEED`
на найденный файл, и точный ответ с номером строки. Журнал кругов обновлялся
на странице по ходу.
### Обрезанные ответы: причина найдена
Один из прогонов оборвался посреди блока кода на `// Бы`. Это не «конец
определён раньше времени» и не кнопка `Continue`.
**Браузер работал в фоне.** У неактивного окна страница не отрисовывается,
а DeepSeek рисует блоки кода лениво: пока блок не нарисован, в DOM от него
лежат первые две строки, а остального нет вовсе — его не достать ни
`innerText`, ни `textContent`. Прокрутка не помогает.
Помогает единственное — заставить браузер отрисовать страницу. Замеры на живых
ответах:
| | до отрисовки | после |
|---|---|---|
| ответ про TaskQueue | 2068 | 24 362 |
| ответ про EventBus | 3136 | 30 817 |
| ответ про Router | 258 | **32 045** |
Вторая причина обрезания — кнопка **Continue**: DeepSeek режет длинный ответ
по своему лимиту и предлагает дописать, а генерация при этом честно
завершается. Сквозная проверка после починки — ответ на 47 414 символов
с целыми кодом и тестами.
Обе поломки лечатся в `deepseek-api`, а не здесь: отрисовка и кнопка `Continue`
живут в его `browser.mjs`. Отсюда остаётся одно требование — **не сворачивать
окно браузера**.
### Переезд на deepseek-api, 26.08.2026
Раньше `deepwork` вызывал мост `ask.mjs` из проекта DeepShim дочерним процессом
и гонял текст через временные файлы. Теперь это `POST /api/chat`, а память
кругов переехала из чата в стенограмму (см. выше).
Проверено живым прогоном: круг 1 — 2094 символа, ответ `NEED: deepwork.mjs`;
круг 2 — 28 447 символов стенограммы, ответ дословно верный и по вопросу
из **первого** сообщения. Два круга за 17 с.
---
## Лицензия
MIT.