zames_pro 1.0.3 → 1.1.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 +1 -1
- package/package.json +14 -3
- package/src/agent-loop.js +5 -1
- package/src/browser.js +150 -13
- package/src/confirm.js +10 -10
- package/src/diff.js +21 -113
- package/src/index.js +159 -107
- package/src/markdown.js +49 -0
- package/src/self-review.js +30 -30
- package/src/spinner.js +15 -22
- package/src/theme.js +34 -0
package/src/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import path from 'path'
|
|
3
3
|
import fs from 'fs/promises'
|
|
4
|
-
import chalk from 'chalk'
|
|
5
4
|
import { fileURLToPath } from 'url'
|
|
6
5
|
import * as readlinePromises from 'readline/promises'
|
|
6
|
+
import { theme } from './theme.js'
|
|
7
7
|
|
|
8
8
|
import { DeepSeekBrowser } from './browser.js'
|
|
9
9
|
import { createTools } from './tools.js'
|
|
@@ -61,8 +61,10 @@ const chatIdArg = getArg('--chat', null)
|
|
|
61
61
|
// заставляет дослать его заново — например, если промпт обновился.
|
|
62
62
|
const resendPrompt = hasFlag('--resend-prompt')
|
|
63
63
|
// --new-chat: намеренно начать с чистого чата, игнорируя сохранённый
|
|
64
|
-
// last
|
|
65
|
-
|
|
64
|
+
// --resume-last: при старте вернуться в последний сохранённый чат.
|
|
65
|
+
// По умолчанию НЕ восстанавливаем — открывается новый чат.
|
|
66
|
+
// (Флаг --new-chat сохранён для совместимости и ничего не меняет.)
|
|
67
|
+
const resumeLastFlag = hasFlag('--resume-last')
|
|
66
68
|
|
|
67
69
|
// ---------- last chat persistence ----------
|
|
68
70
|
// Запоминаем последний открытый chat id, чтобы после перезапуска процесса
|
|
@@ -171,9 +173,9 @@ async function autoReload() {
|
|
|
171
173
|
const { errors } = await reloadModules()
|
|
172
174
|
if (errors.length) {
|
|
173
175
|
console.error(
|
|
174
|
-
|
|
176
|
+
theme.warn('⚠ авто-reload: часть модулей не загрузилась, работаю на прежней версии:'),
|
|
175
177
|
)
|
|
176
|
-
for (const e of errors) console.error(
|
|
178
|
+
for (const e of errors) console.error(theme.warn(' ' + e))
|
|
177
179
|
}
|
|
178
180
|
}
|
|
179
181
|
|
|
@@ -182,13 +184,14 @@ async function autoReload() {
|
|
|
182
184
|
|
|
183
185
|
function printHelp() {
|
|
184
186
|
console.log(`
|
|
185
|
-
${
|
|
187
|
+
${theme.bold('zames')} — агент поверх chat.deepseek.com через Playwright
|
|
186
188
|
|
|
187
|
-
${
|
|
189
|
+
${theme.bold('Опции CLI:')}
|
|
188
190
|
--dir <path> рабочая директория агента
|
|
189
191
|
--task <text> задача одной строкой
|
|
190
192
|
--chat <id> продолжить существующий чат по id
|
|
191
|
-
--
|
|
193
|
+
--resume-last вернуться в последний сохранённый чат
|
|
194
|
+
--new-chat начать новый чат (по умолчанию и так новый)
|
|
192
195
|
--resend-prompt дослать system-prompt в существующий чат
|
|
193
196
|
--max-iter <n> лимит итераций (по умолчанию ${config.maxIterations})
|
|
194
197
|
--headless браузер без UI
|
|
@@ -198,7 +201,7 @@ ${chalk.bold('Опции CLI:')}
|
|
|
198
201
|
--version, -v показать версию
|
|
199
202
|
--help, -h эта справка
|
|
200
203
|
|
|
201
|
-
${
|
|
204
|
+
${theme.bold('Обычные команды:')}
|
|
202
205
|
/new, /clear новый чат (сброс контекста)
|
|
203
206
|
/chats список последних чатов DeepSeek
|
|
204
207
|
/resume <n> открыть чат №n из /chats
|
|
@@ -215,7 +218,7 @@ ${chalk.bold('Обычные команды:')}
|
|
|
215
218
|
/help, help справка
|
|
216
219
|
/exit, /quit, exit выход
|
|
217
220
|
|
|
218
|
-
${
|
|
221
|
+
${theme.bold('Самообзор (отладка агента):')}
|
|
219
222
|
/self-review [фокус] снять снапшот src/ и запустить ревью
|
|
220
223
|
после этой команды ты остаёшься В СНАПШОТЕ
|
|
221
224
|
и можешь писать «исправь ошибки» и т.п.
|
|
@@ -225,11 +228,12 @@ ${chalk.bold('Самообзор (отладка агента):')}
|
|
|
225
228
|
/self-diff <name> различия между текущим src/ и снапшотом
|
|
226
229
|
/self-apply <name> применить снапшот к src/ (с бэкапом)
|
|
227
230
|
|
|
228
|
-
${
|
|
231
|
+
${theme.bold('Файлы:')}
|
|
229
232
|
Логи: ${config.transcript.dir}
|
|
230
233
|
Undo: ~/.zames/undo
|
|
231
234
|
Профиль: ~/.zames/profile
|
|
232
235
|
Снапшоты: ~/.zames/snapshots
|
|
236
|
+
Временные: <проект>/tmp (в .gitignore, чистится при запуске)
|
|
233
237
|
Конфиг: ${CONFIG_PATHS.HOME_CONFIG}
|
|
234
238
|
${CONFIG_PATHS.PROJECT_CONFIG}
|
|
235
239
|
`)
|
|
@@ -239,6 +243,19 @@ function dirLabel(p) {
|
|
|
239
243
|
return path.basename(p) || p
|
|
240
244
|
}
|
|
241
245
|
|
|
246
|
+
// Временные файлы агента (одноразовые скрипты и т.п.) складываем в
|
|
247
|
+
// <проект>/tmp — эта папка в .gitignore и очищается при каждом запуске.
|
|
248
|
+
const TMP_DIR = path.join(__dirname, '..', 'tmp')
|
|
249
|
+
|
|
250
|
+
async function cleanTmpDir() {
|
|
251
|
+
try {
|
|
252
|
+
await fs.rm(TMP_DIR, { recursive: true, force: true })
|
|
253
|
+
await fs.mkdir(TMP_DIR, { recursive: true })
|
|
254
|
+
} catch (e) {
|
|
255
|
+
if (debug) console.error('tmp: не удалось очистить:', e.message)
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
242
259
|
async function promptOnce(question) {
|
|
243
260
|
process.stdin.resume()
|
|
244
261
|
if (process.stdin.isTTY && process.stdin.setRawMode) {
|
|
@@ -255,6 +272,26 @@ async function promptOnce(question) {
|
|
|
255
272
|
}
|
|
256
273
|
}
|
|
257
274
|
|
|
275
|
+
// Слежение за клавиатурой во время работы агента.
|
|
276
|
+
// Esc — прервать текущую генерацию (клик Stop в браузере).
|
|
277
|
+
function watchEscape(onEscape) {
|
|
278
|
+
const stdin = process.stdin
|
|
279
|
+
if (!stdin.isTTY) return () => {}
|
|
280
|
+
const wasRaw = stdin.isRaw
|
|
281
|
+
if (stdin.setRawMode) stdin.setRawMode(true)
|
|
282
|
+
stdin.resume()
|
|
283
|
+
const handler = (buf) => {
|
|
284
|
+
if (buf.length === 1 && buf[0] === 27) {
|
|
285
|
+
onEscape()
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
stdin.on('data', handler)
|
|
289
|
+
return () => {
|
|
290
|
+
stdin.removeListener('data', handler)
|
|
291
|
+
if (stdin.setRawMode) stdin.setRawMode(wasRaw || false)
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
258
295
|
// ---------- workdir resolution ----------
|
|
259
296
|
|
|
260
297
|
// ---------- workdir resolution ----------
|
|
@@ -277,9 +314,15 @@ async function runTask(browser, tools, taskText, workdir, opts) {
|
|
|
277
314
|
const { transcript, freshChat, sendSystemPrompt } = opts
|
|
278
315
|
|
|
279
316
|
const ui = mod.createSpinner()
|
|
280
|
-
ui.taskHeader(taskText)
|
|
281
317
|
ui.thinking()
|
|
282
318
|
|
|
319
|
+
// Esc во время работы — прервать генерацию.
|
|
320
|
+
const stopWatching = watchEscape(() => {
|
|
321
|
+
ui.stop()
|
|
322
|
+
console.error(theme.warn('⏹ Esc — прерываю генерацию...'))
|
|
323
|
+
browser.stopGeneration().catch(() => {})
|
|
324
|
+
})
|
|
325
|
+
|
|
283
326
|
let finished = false
|
|
284
327
|
|
|
285
328
|
try {
|
|
@@ -299,13 +342,15 @@ async function runTask(browser, tools, taskText, workdir, opts) {
|
|
|
299
342
|
ui.assistant(msg)
|
|
300
343
|
finished = true
|
|
301
344
|
},
|
|
345
|
+
debugLog: debug,
|
|
302
346
|
})
|
|
303
347
|
} catch (e) {
|
|
304
348
|
ui.stop()
|
|
305
|
-
console.error(
|
|
349
|
+
console.error(theme.error('\n✖ Ошибка агента:'), e.message)
|
|
306
350
|
if (debug) console.error(e.stack)
|
|
307
351
|
transcript?.log('agent_error', { error: e.message })
|
|
308
352
|
} finally {
|
|
353
|
+
stopWatching()
|
|
309
354
|
if (!finished) ui.stop()
|
|
310
355
|
}
|
|
311
356
|
}
|
|
@@ -327,9 +372,11 @@ async function main() {
|
|
|
327
372
|
}
|
|
328
373
|
|
|
329
374
|
if (calibrate) {
|
|
330
|
-
console.log(
|
|
375
|
+
console.log(theme.warn('\n🔧 Режим калибровки селекторов\n'))
|
|
331
376
|
}
|
|
332
377
|
|
|
378
|
+
await cleanTmpDir()
|
|
379
|
+
|
|
333
380
|
let currentWorkdir
|
|
334
381
|
try {
|
|
335
382
|
currentWorkdir = await resolveWorkdir()
|
|
@@ -337,13 +384,13 @@ async function main() {
|
|
|
337
384
|
const sandboxRoot = currentWorkdir
|
|
338
385
|
} catch (e) {
|
|
339
386
|
console.error(
|
|
340
|
-
|
|
387
|
+
theme.error('Не удалось определить рабочую директорию:'),
|
|
341
388
|
e.message,
|
|
342
389
|
)
|
|
343
390
|
process.exit(1)
|
|
344
391
|
}
|
|
345
392
|
|
|
346
|
-
console.log(
|
|
393
|
+
console.log(theme.system(`Рабочая директория: ${currentWorkdir}`))
|
|
347
394
|
|
|
348
395
|
const transcript = new Transcript({
|
|
349
396
|
dir: config.transcript.dir,
|
|
@@ -351,7 +398,7 @@ async function main() {
|
|
|
351
398
|
sessionName: dirLabel(currentWorkdir),
|
|
352
399
|
})
|
|
353
400
|
if (transcript.file) {
|
|
354
|
-
console.log(
|
|
401
|
+
console.log(theme.system(`Транскрипт: ${transcript.file}`))
|
|
355
402
|
}
|
|
356
403
|
|
|
357
404
|
const undo = new UndoStore(config.undo)
|
|
@@ -372,7 +419,7 @@ async function main() {
|
|
|
372
419
|
await browser.waitForLogin()
|
|
373
420
|
} catch (e) {
|
|
374
421
|
bootSpinner.stop()
|
|
375
|
-
console.error(
|
|
422
|
+
console.error(theme.error('Не удалось запустить браузер:'), e.message)
|
|
376
423
|
if (debug) console.error(e.stack)
|
|
377
424
|
await browser.close().catch(() => {})
|
|
378
425
|
transcript.close()
|
|
@@ -386,21 +433,23 @@ async function main() {
|
|
|
386
433
|
let freshChat = true
|
|
387
434
|
let sendSystemPrompt = true
|
|
388
435
|
|
|
389
|
-
//
|
|
436
|
+
// По умолчанию — новый чат. Продолжить прошлый можно явно:
|
|
437
|
+
// --chat <id> открыть конкретный чат
|
|
438
|
+
// --resume-last вернуться в последний сохранённый чат
|
|
390
439
|
let resumeId = chatIdArg
|
|
391
|
-
if (!resumeId &&
|
|
440
|
+
if (!resumeId && resumeLastFlag) {
|
|
392
441
|
resumeId = await loadLastChat()
|
|
393
|
-
if (resumeId) console.log(
|
|
442
|
+
if (resumeId) console.log(theme.system(`Восстанавливаю чат ${resumeId}...`))
|
|
394
443
|
}
|
|
395
444
|
|
|
396
445
|
if (resumeId) {
|
|
397
446
|
try {
|
|
398
|
-
console.log(
|
|
447
|
+
console.log(theme.system(`Открываю чат ${resumeId}...`))
|
|
399
448
|
await browser.openChat(resumeId)
|
|
400
449
|
freshChat = false
|
|
401
450
|
sendSystemPrompt = resendPrompt
|
|
402
451
|
} catch (e) {
|
|
403
|
-
console.error(
|
|
452
|
+
console.error(theme.error(`Не удалось открыть чат: ${e.message}`))
|
|
404
453
|
}
|
|
405
454
|
}
|
|
406
455
|
|
|
@@ -418,7 +467,7 @@ async function main() {
|
|
|
418
467
|
}
|
|
419
468
|
|
|
420
469
|
console.log(
|
|
421
|
-
|
|
470
|
+
theme.system(
|
|
422
471
|
'Интерактивный режим. Введите задачу. Команды — /help. Выход — /exit.\n',
|
|
423
472
|
),
|
|
424
473
|
)
|
|
@@ -442,42 +491,45 @@ async function main() {
|
|
|
442
491
|
// висеть отдельным процессом после выхода агента.
|
|
443
492
|
await mod.closeWeb().catch(() => {})
|
|
444
493
|
transcript.close()
|
|
445
|
-
console.log(
|
|
494
|
+
console.log(theme.system('\nВыход.'))
|
|
446
495
|
process.exit(0)
|
|
447
496
|
})
|
|
448
497
|
|
|
449
|
-
//
|
|
498
|
+
// По умолчанию — новый чат. Продолжить прошлый можно явно:
|
|
499
|
+
// --chat <id> открыть конкретный чат
|
|
500
|
+
// --resume-last вернуться в последний сохранённый чат
|
|
450
501
|
let resumeId = chatIdArg
|
|
451
|
-
if (!resumeId &&
|
|
502
|
+
if (!resumeId && resumeLastFlag) {
|
|
452
503
|
resumeId = await loadLastChat()
|
|
504
|
+
if (resumeId) console.log(theme.system(`Восстанавливаю чат ${resumeId}...`))
|
|
453
505
|
}
|
|
454
506
|
|
|
455
507
|
if (resumeId) {
|
|
456
508
|
try {
|
|
457
|
-
console.log(
|
|
509
|
+
console.log(theme.system(`Открываю чат ${resumeId}...`))
|
|
458
510
|
await browser.openChat(resumeId)
|
|
459
511
|
currentChatId = resumeId
|
|
460
512
|
freshChatNext = false
|
|
461
513
|
sendSystemPromptNext = resendPrompt
|
|
462
514
|
await saveLastChat(resumeId)
|
|
463
|
-
console.log(
|
|
515
|
+
console.log(theme.system(`Чат открыт: ${resumeId}\n`))
|
|
464
516
|
} catch (e) {
|
|
465
|
-
console.error(
|
|
517
|
+
console.error(theme.error(`Не удалось открыть чат: ${e.message}`))
|
|
466
518
|
}
|
|
467
519
|
}
|
|
468
520
|
|
|
469
521
|
while (running) {
|
|
470
522
|
let input
|
|
471
523
|
try {
|
|
472
|
-
|
|
524
|
+
// Компактное приглашение: золотая стрелка + светло-голубая директория.
|
|
525
|
+
let tail
|
|
473
526
|
if (reviewMode) {
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
label = `zames[${dirLabel(currentWorkdir)}|${currentChatId.slice(0, 6)}]> `
|
|
527
|
+
tail =
|
|
528
|
+
theme.warn('REVIEW') + theme.dim(':') + theme.dir(reviewMode.snapName)
|
|
477
529
|
} else {
|
|
478
|
-
|
|
530
|
+
tail = theme.dir(dirLabel(currentWorkdir))
|
|
479
531
|
}
|
|
480
|
-
input = await promptOnce(
|
|
532
|
+
input = await promptOnce(theme.prompt('❯ ') + tail + theme.dim(' › '))
|
|
481
533
|
} catch {
|
|
482
534
|
break
|
|
483
535
|
}
|
|
@@ -495,7 +547,7 @@ async function main() {
|
|
|
495
547
|
}
|
|
496
548
|
|
|
497
549
|
if (['/new', '/clear', 'new'].includes(lower)) {
|
|
498
|
-
console.log(
|
|
550
|
+
console.log(theme.system('Создаю новый чат...'))
|
|
499
551
|
try {
|
|
500
552
|
await browser.newChat()
|
|
501
553
|
freshChatNext = false
|
|
@@ -503,9 +555,9 @@ async function main() {
|
|
|
503
555
|
currentChatId = await browser.getCurrentChatId()
|
|
504
556
|
await saveLastChat(currentChatId)
|
|
505
557
|
transcript.log('new_chat')
|
|
506
|
-
console.log(
|
|
558
|
+
console.log(theme.system('Новый чат.\n'))
|
|
507
559
|
} catch (e) {
|
|
508
|
-
console.error(
|
|
560
|
+
console.error(theme.error('Не удалось создать новый чат:'), e.message)
|
|
509
561
|
}
|
|
510
562
|
continue
|
|
511
563
|
}
|
|
@@ -544,7 +596,7 @@ async function main() {
|
|
|
544
596
|
await saveLastChat(currentChatId)
|
|
545
597
|
|
|
546
598
|
console.log(
|
|
547
|
-
|
|
599
|
+
theme.user(
|
|
548
600
|
'\n💡 Теперь ты в режиме ревью. Просто пиши агенту, например:\n' +
|
|
549
601
|
' «исправь ошибки»\n' +
|
|
550
602
|
' «доработай обработку ошибок в ask()»\n' +
|
|
@@ -555,7 +607,7 @@ async function main() {
|
|
|
555
607
|
),
|
|
556
608
|
)
|
|
557
609
|
} catch (e) {
|
|
558
|
-
console.error(
|
|
610
|
+
console.error(theme.error('Самообзор провалился:'), e.message)
|
|
559
611
|
if (debug) console.error(e.stack)
|
|
560
612
|
}
|
|
561
613
|
continue
|
|
@@ -564,7 +616,7 @@ async function main() {
|
|
|
564
616
|
if (lower === '/self-fix' || lower.startsWith('/self-fix ')) {
|
|
565
617
|
const rest = trimmed.slice('/self-fix'.length).trim()
|
|
566
618
|
if (!rest) {
|
|
567
|
-
console.error(
|
|
619
|
+
console.error(theme.error('Использование: /self-fix <name> [фокус]'))
|
|
568
620
|
continue
|
|
569
621
|
}
|
|
570
622
|
const sp = rest.indexOf(' ')
|
|
@@ -574,7 +626,7 @@ async function main() {
|
|
|
574
626
|
const snapRoot = path.join(ZAMES_HOME, 'snapshots', name)
|
|
575
627
|
const stat = await fs.stat(snapRoot).catch(() => null)
|
|
576
628
|
if (!stat || !stat.isDirectory()) {
|
|
577
|
-
console.error(
|
|
629
|
+
console.error(theme.error(`Снапшот не найден: ${snapRoot}`))
|
|
578
630
|
continue
|
|
579
631
|
}
|
|
580
632
|
|
|
@@ -593,7 +645,7 @@ async function main() {
|
|
|
593
645
|
workdir: snapRoot,
|
|
594
646
|
tools,
|
|
595
647
|
})
|
|
596
|
-
console.log(
|
|
648
|
+
console.log(theme.system('Инициализирую review-чат для снапшота...'))
|
|
597
649
|
await browser.ask(sysPrompt, { timeout: 60_000 })
|
|
598
650
|
|
|
599
651
|
if (focus) {
|
|
@@ -611,7 +663,7 @@ async function main() {
|
|
|
611
663
|
onThinking: () => ui.thinking(),
|
|
612
664
|
onAssistantThought: (text) => {
|
|
613
665
|
ui.stop()
|
|
614
|
-
console.log(
|
|
666
|
+
console.log(theme.system('\n💭 ' + text.slice(0, 1200) + '\n'))
|
|
615
667
|
},
|
|
616
668
|
onToolCall: (name, toolArgs) => ui.toolCall(name, toolArgs),
|
|
617
669
|
onToolResult: (r) => ui.toolResult(r),
|
|
@@ -633,19 +685,19 @@ async function main() {
|
|
|
633
685
|
await saveLastChat(currentChatId)
|
|
634
686
|
|
|
635
687
|
console.log(
|
|
636
|
-
|
|
688
|
+
theme.user(
|
|
637
689
|
`\n💡 Режим ревью по снапшоту ${name}. Пиши агенту задачу или /self-done.\n`,
|
|
638
690
|
),
|
|
639
691
|
)
|
|
640
692
|
} catch (e) {
|
|
641
|
-
console.error(
|
|
693
|
+
console.error(theme.error('Не удалось войти в снапшот:'), e.message)
|
|
642
694
|
}
|
|
643
695
|
continue
|
|
644
696
|
}
|
|
645
697
|
|
|
646
698
|
if (lower === '/self-done') {
|
|
647
699
|
if (!reviewMode) {
|
|
648
|
-
console.log(
|
|
700
|
+
console.log(theme.system('Ты и так не в режиме ревью.'))
|
|
649
701
|
continue
|
|
650
702
|
}
|
|
651
703
|
const back = reviewMode.originalWorkdir
|
|
@@ -655,7 +707,7 @@ async function main() {
|
|
|
655
707
|
freshChatNext = true
|
|
656
708
|
sendSystemPromptNext = true
|
|
657
709
|
console.log(
|
|
658
|
-
|
|
710
|
+
theme.system(`Вернулся в ${back}. Следующая задача начнёт новый чат.\n`),
|
|
659
711
|
)
|
|
660
712
|
continue
|
|
661
713
|
}
|
|
@@ -664,7 +716,7 @@ async function main() {
|
|
|
664
716
|
try {
|
|
665
717
|
await mod.selfList({ config })
|
|
666
718
|
} catch (e) {
|
|
667
|
-
console.error(
|
|
719
|
+
console.error(theme.error('Ошибка:'), e.message)
|
|
668
720
|
}
|
|
669
721
|
continue
|
|
670
722
|
}
|
|
@@ -672,13 +724,13 @@ async function main() {
|
|
|
672
724
|
if (lower === '/self-diff' || lower.startsWith('/self-diff ')) {
|
|
673
725
|
const name = trimmed.slice('/self-diff'.length).trim()
|
|
674
726
|
if (!name) {
|
|
675
|
-
console.error(
|
|
727
|
+
console.error(theme.error('Использование: /self-diff <name>'))
|
|
676
728
|
continue
|
|
677
729
|
}
|
|
678
730
|
try {
|
|
679
731
|
await mod.selfDiff({ config, name })
|
|
680
732
|
} catch (e) {
|
|
681
|
-
console.error(
|
|
733
|
+
console.error(theme.error('Ошибка:'), e.message)
|
|
682
734
|
}
|
|
683
735
|
continue
|
|
684
736
|
}
|
|
@@ -686,13 +738,13 @@ async function main() {
|
|
|
686
738
|
if (lower === '/self-apply' || lower.startsWith('/self-apply ')) {
|
|
687
739
|
const name = trimmed.slice('/self-apply'.length).trim()
|
|
688
740
|
if (!name) {
|
|
689
|
-
console.error(
|
|
741
|
+
console.error(theme.error('Использование: /self-apply <name>'))
|
|
690
742
|
continue
|
|
691
743
|
}
|
|
692
744
|
try {
|
|
693
745
|
await mod.selfApply({ config, name })
|
|
694
746
|
} catch (e) {
|
|
695
|
-
console.error(
|
|
747
|
+
console.error(theme.error('Ошибка:'), e.message)
|
|
696
748
|
}
|
|
697
749
|
continue
|
|
698
750
|
}
|
|
@@ -707,23 +759,23 @@ async function main() {
|
|
|
707
759
|
spin.stop()
|
|
708
760
|
if (!lastChats.length) {
|
|
709
761
|
console.log(
|
|
710
|
-
|
|
762
|
+
theme.system(
|
|
711
763
|
'Чатов не найдено. Возможно, сайдбар свёрнут или селекторы устарели.',
|
|
712
764
|
),
|
|
713
765
|
)
|
|
714
766
|
} else {
|
|
715
|
-
console.log(
|
|
767
|
+
console.log(theme.system('Последние чаты DeepSeek:'))
|
|
716
768
|
lastChats.forEach((c, i) => {
|
|
717
769
|
const n = String(i + 1).padStart(2, ' ')
|
|
718
770
|
console.log(
|
|
719
|
-
` ${
|
|
771
|
+
` ${theme.user(n)}. ${c.title} ${theme.system('(' + c.id.slice(0, 8) + '…)')}`,
|
|
720
772
|
)
|
|
721
773
|
})
|
|
722
|
-
console.log(
|
|
774
|
+
console.log(theme.system('\nИспользуй /resume <n> для продолжения.\n'))
|
|
723
775
|
}
|
|
724
776
|
} catch (e) {
|
|
725
777
|
spin.stop()
|
|
726
|
-
console.error(
|
|
778
|
+
console.error(theme.error('Не удалось получить список:'), e.message)
|
|
727
779
|
}
|
|
728
780
|
continue
|
|
729
781
|
}
|
|
@@ -732,26 +784,26 @@ async function main() {
|
|
|
732
784
|
const arg = trimmed.slice(7).trim()
|
|
733
785
|
if (!arg) {
|
|
734
786
|
console.error(
|
|
735
|
-
|
|
787
|
+
theme.error('Использование: /resume <n> (или /chats для списка)'),
|
|
736
788
|
)
|
|
737
789
|
continue
|
|
738
790
|
}
|
|
739
791
|
const n = Number(arg)
|
|
740
792
|
if (!Number.isFinite(n) || n < 1) {
|
|
741
|
-
console.error(
|
|
793
|
+
console.error(theme.error('Нужен номер из /chats.'))
|
|
742
794
|
continue
|
|
743
795
|
}
|
|
744
796
|
if (!lastChats.length) {
|
|
745
|
-
console.error(
|
|
797
|
+
console.error(theme.error('Сначала выполни /chats.'))
|
|
746
798
|
continue
|
|
747
799
|
}
|
|
748
800
|
const pick = lastChats[n - 1]
|
|
749
801
|
if (!pick) {
|
|
750
|
-
console.error(
|
|
802
|
+
console.error(theme.error(`Нет чата №${n}. Всего: ${lastChats.length}.`))
|
|
751
803
|
continue
|
|
752
804
|
}
|
|
753
805
|
|
|
754
|
-
console.log(
|
|
806
|
+
console.log(theme.system(`Открываю: ${pick.title}`))
|
|
755
807
|
try {
|
|
756
808
|
await browser.openChat(pick.id)
|
|
757
809
|
currentChatId = pick.id
|
|
@@ -760,94 +812,94 @@ async function main() {
|
|
|
760
812
|
await saveLastChat(pick.id)
|
|
761
813
|
transcript.log('resume_chat', { id: pick.id, title: pick.title })
|
|
762
814
|
console.log(
|
|
763
|
-
|
|
764
|
-
|
|
815
|
+
theme.assistant(`Чат открыт.`) +
|
|
816
|
+
theme.system(
|
|
765
817
|
resendPrompt ? ' Системный промпт будет переслан на следующей задаче.\n' : ' Контекст чата сохранён. Системный промпт не пересылается (--resend-prompt чтобы дослать).\n',
|
|
766
818
|
),
|
|
767
819
|
)
|
|
768
820
|
} catch (e) {
|
|
769
|
-
console.error(
|
|
821
|
+
console.error(theme.error('Не удалось открыть чат:'), e.message)
|
|
770
822
|
}
|
|
771
823
|
continue
|
|
772
824
|
}
|
|
773
825
|
|
|
774
826
|
if (lower === '/chat') {
|
|
775
827
|
if (currentChatId) {
|
|
776
|
-
console.log(
|
|
828
|
+
console.log(theme.system(`Текущий chat id: ${currentChatId}`))
|
|
777
829
|
console.log(
|
|
778
|
-
|
|
830
|
+
theme.system(
|
|
779
831
|
`URL: https://chat.deepseek.com/a/chat/s/${currentChatId}`,
|
|
780
832
|
),
|
|
781
833
|
)
|
|
782
834
|
} else {
|
|
783
835
|
const id = await browser.getCurrentChatId()
|
|
784
836
|
console.log(
|
|
785
|
-
|
|
837
|
+
theme.system(id ? `Текущий chat id: ${id}` : 'Чат ещё не создан.'),
|
|
786
838
|
)
|
|
787
839
|
}
|
|
788
840
|
continue
|
|
789
841
|
}
|
|
790
842
|
|
|
791
843
|
if (lower === '/pwd') {
|
|
792
|
-
console.log(
|
|
844
|
+
console.log(theme.system(currentWorkdir))
|
|
793
845
|
continue
|
|
794
846
|
}
|
|
795
847
|
|
|
796
848
|
if (lower === '/reload') {
|
|
797
|
-
console.log(
|
|
849
|
+
console.log(theme.system('Перечитываю модули логики...'))
|
|
798
850
|
try {
|
|
799
851
|
const { count, errors } = await reloadModules()
|
|
800
852
|
if (errors.length) {
|
|
801
|
-
console.error(
|
|
802
|
-
for (const e of errors) console.error(
|
|
853
|
+
console.error(theme.error('Часть модулей не перезагрузилась:'))
|
|
854
|
+
for (const e of errors) console.error(theme.error(' ' + e))
|
|
803
855
|
} else {
|
|
804
856
|
console.log(
|
|
805
|
-
|
|
857
|
+
theme.assistant(
|
|
806
858
|
`Перезагружено модулей: ${count}. Браузер и чат не тронуты.`,
|
|
807
859
|
),
|
|
808
860
|
)
|
|
809
861
|
}
|
|
810
862
|
} catch (e) {
|
|
811
|
-
console.error(
|
|
863
|
+
console.error(theme.error('Ошибка reload:'), e.message)
|
|
812
864
|
}
|
|
813
865
|
continue
|
|
814
866
|
}
|
|
815
867
|
|
|
816
868
|
if (lower === '/status') {
|
|
817
|
-
console.log(
|
|
869
|
+
console.log(theme.system(`Рабочая директория: ${currentWorkdir}`))
|
|
818
870
|
console.log(
|
|
819
|
-
|
|
871
|
+
theme.system(`Режим ревью: ${reviewMode ? reviewMode.snapName : 'нет'}`),
|
|
820
872
|
)
|
|
821
873
|
if (reviewMode) {
|
|
822
874
|
console.log(
|
|
823
|
-
|
|
875
|
+
theme.system(`Исходная директория: ${reviewMode.originalWorkdir}`),
|
|
824
876
|
)
|
|
825
877
|
}
|
|
826
|
-
console.log(
|
|
878
|
+
console.log(theme.system(`Текущий чат: ${currentChatId || '(нет)'}`))
|
|
827
879
|
console.log(
|
|
828
|
-
|
|
880
|
+
theme.system(
|
|
829
881
|
`Fresh chat на след. задаче: ${freshChatNext ? 'да' : 'нет'}`,
|
|
830
882
|
),
|
|
831
883
|
)
|
|
832
884
|
console.log(
|
|
833
|
-
|
|
885
|
+
theme.system(
|
|
834
886
|
`System prompt на след. задаче: ${sendSystemPromptNext ? 'да' : 'нет'}`,
|
|
835
887
|
),
|
|
836
888
|
)
|
|
837
889
|
console.log(
|
|
838
|
-
|
|
890
|
+
theme.system(`Resend prompt (--resend-prompt): ${resendPrompt ? 'да' : 'нет'}`),
|
|
839
891
|
)
|
|
840
892
|
console.log(
|
|
841
|
-
|
|
893
|
+
theme.system(`Last chat: ${(await loadLastChat()) || 'нет'}`),
|
|
842
894
|
)
|
|
843
895
|
console.log(
|
|
844
|
-
|
|
896
|
+
theme.system(`Dev mode (auto-reload): ${devMode ? 'вкл' : 'выкл'}`),
|
|
845
897
|
)
|
|
846
|
-
console.log(
|
|
847
|
-
console.log(
|
|
848
|
-
console.log(
|
|
849
|
-
console.log(
|
|
850
|
-
console.log(
|
|
898
|
+
console.log(theme.system(`Лимит итераций: ${maxIter}`))
|
|
899
|
+
console.log(theme.system(`Headless: ${headless ? 'да' : 'нет'}`))
|
|
900
|
+
console.log(theme.system(`Debug: ${debug ? 'да' : 'нет'}`))
|
|
901
|
+
console.log(theme.system(`Undo: ${config.undo.enabled ? 'вкл' : 'выкл'}`))
|
|
902
|
+
console.log(theme.system(`Транскрипт: ${transcript.file || 'выкл'}`))
|
|
851
903
|
continue
|
|
852
904
|
}
|
|
853
905
|
|
|
@@ -857,7 +909,7 @@ async function main() {
|
|
|
857
909
|
}
|
|
858
910
|
|
|
859
911
|
if (lower === '/transcript') {
|
|
860
|
-
console.log(
|
|
912
|
+
console.log(theme.system(transcript.file || '(выключен)'))
|
|
861
913
|
continue
|
|
862
914
|
}
|
|
863
915
|
|
|
@@ -865,14 +917,14 @@ async function main() {
|
|
|
865
917
|
const result = await undo.undoLast()
|
|
866
918
|
if (result.ok) {
|
|
867
919
|
console.log(
|
|
868
|
-
|
|
869
|
-
|
|
920
|
+
theme.assistant(`↶ Откатили: ${result.record.originalPath}`) +
|
|
921
|
+
theme.system(
|
|
870
922
|
result.record.existed ? ' (восстановлено)' : ' (удалено)',
|
|
871
923
|
),
|
|
872
924
|
)
|
|
873
925
|
transcript.log('undo', { path: result.record.originalPath })
|
|
874
926
|
} else {
|
|
875
|
-
console.error(
|
|
927
|
+
console.error(theme.error(`Не удалось откатить: ${result.reason}`))
|
|
876
928
|
}
|
|
877
929
|
continue
|
|
878
930
|
}
|
|
@@ -880,12 +932,12 @@ async function main() {
|
|
|
880
932
|
if (lower === '/undo-list' || lower === '/history') {
|
|
881
933
|
const list = await undo.list(10)
|
|
882
934
|
if (!list.length) {
|
|
883
|
-
console.log(
|
|
935
|
+
console.log(theme.system('История пуста.'))
|
|
884
936
|
} else {
|
|
885
937
|
for (const r of list) {
|
|
886
938
|
const stamp = new Date(r.stamp).toLocaleString()
|
|
887
939
|
const flag = r.existed ? 'изменён' : 'создан'
|
|
888
|
-
console.log(
|
|
940
|
+
console.log(theme.system(`${stamp} [${flag}] ${r.originalPath}`))
|
|
889
941
|
}
|
|
890
942
|
}
|
|
891
943
|
continue
|
|
@@ -896,11 +948,11 @@ async function main() {
|
|
|
896
948
|
const file = path.join(config.transcript.dir, `dom-${stamp}.html`)
|
|
897
949
|
try {
|
|
898
950
|
const result = await browser.dumpDom(file)
|
|
899
|
-
console.log(
|
|
900
|
-
console.log(
|
|
951
|
+
console.log(theme.assistant(`HTML сохранён: ${result.file}`))
|
|
952
|
+
console.log(theme.system('Селекторы:'))
|
|
901
953
|
console.log(JSON.stringify(result.selectors, null, 2))
|
|
902
954
|
} catch (e) {
|
|
903
|
-
console.error(
|
|
955
|
+
console.error(theme.error('Не удалось сохранить DOM:'), e.message)
|
|
904
956
|
}
|
|
905
957
|
continue
|
|
906
958
|
}
|
|
@@ -913,34 +965,34 @@ async function main() {
|
|
|
913
965
|
: sandboxRoot
|
|
914
966
|
const rel = path.relative(sandboxRoot, newDir)
|
|
915
967
|
if (rel.startsWith('..') || path.isAbsolute(rel)) {
|
|
916
|
-
console.error(
|
|
968
|
+
console.error(theme.error('Нельзя выйти за пределы: ' + sandboxRoot))
|
|
917
969
|
continue
|
|
918
970
|
}
|
|
919
971
|
const stat = await fs.stat(newDir).catch(() => null)
|
|
920
972
|
if (!stat || !stat.isDirectory()) {
|
|
921
|
-
console.error(
|
|
973
|
+
console.error(theme.error('Не директория: ' + newDir))
|
|
922
974
|
continue
|
|
923
975
|
}
|
|
924
976
|
if (newDir === currentWorkdir) {
|
|
925
|
-
console.log(
|
|
977
|
+
console.log(theme.system('Уже здесь.'))
|
|
926
978
|
continue
|
|
927
979
|
}
|
|
928
980
|
if (reviewMode) {
|
|
929
|
-
console.log(
|
|
981
|
+
console.log(theme.system('Вышел из режима ревью (/cd).'))
|
|
930
982
|
reviewMode = null
|
|
931
983
|
}
|
|
932
984
|
currentWorkdir = newDir
|
|
933
985
|
freshChatNext = true
|
|
934
986
|
sendSystemPromptNext = true
|
|
935
|
-
console.log(
|
|
987
|
+
console.log(theme.system('Рабочая директория: ' + newDir))
|
|
936
988
|
} catch (e) {
|
|
937
|
-
console.error(
|
|
989
|
+
console.error(theme.error('Не удалось перейти: ' + e.message))
|
|
938
990
|
}
|
|
939
991
|
continue
|
|
940
992
|
}
|
|
941
993
|
|
|
942
994
|
if (lower.startsWith('/')) {
|
|
943
|
-
console.error(
|
|
995
|
+
console.error(theme.error(`Неизвестная команда: ${trimmed}. Набери /help.`))
|
|
944
996
|
continue
|
|
945
997
|
}
|
|
946
998
|
|
|
@@ -972,7 +1024,7 @@ async function main() {
|
|
|
972
1024
|
}
|
|
973
1025
|
|
|
974
1026
|
main().catch((e) => {
|
|
975
|
-
console.error(
|
|
1027
|
+
console.error(theme.error('Критическая ошибка:'), e.message)
|
|
976
1028
|
if (debug) console.error(e.stack)
|
|
977
1029
|
process.exit(1)
|
|
978
1030
|
})
|