zames_pro 2.88.2 → 2.89.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/dist/config.js CHANGED
@@ -3,9 +3,12 @@ import path from 'path';
3
3
  import os from 'os';
4
4
  import { DEFAULT_DIAGNOSTICS } from './diagnostics.js';
5
5
  import { DEFAULT_LOCALE } from './i18n.js';
6
+ // The /config schema is DATA ONLY and lives in its own module; re-exported
7
+ // here so every existing importer keeps working.
8
+ export { CONFIG_SCHEMA, CONFIG_TOP_GROUPS, getConfigField, fieldsOfTopGroup, subgroupsOf, topGroupModified, } from './config-schema.js';
9
+ import { getConfigField } from './config-schema.js';
6
10
  import { writeJsonAtomic } from './fsutil.js';
7
- import { PROVIDER_IDS } from './providers.js';
8
- import { DEFAULT_THEME, themeNames } from './theme.js';
11
+ import { DEFAULT_THEME } from './theme.js';
9
12
  const ZAMES_HOME = path.join(os.homedir(), '.zames');
10
13
  const HOME_CONFIG = path.join(ZAMES_HOME, 'config.json');
11
14
  // The PROJECT config path is resolved LAZILY: `/cd` changes process.cwd() at
@@ -276,409 +279,6 @@ function deepMerge(target, source) {
276
279
  }
277
280
  }
278
281
  }
279
- export const CONFIG_SCHEMA = [
280
- {
281
- path: 'ui.locale',
282
- type: 'enum',
283
- values: ['ru', 'en'],
284
- labelKey: 'cfg.f.ui_locale',
285
- groupKey: 'cfg.group.ui',
286
- },
287
- {
288
- path: 'maxIterations',
289
- type: 'number',
290
- min: 0,
291
- max: 100000,
292
- labelKey: 'cfg.f.maxIterations',
293
- groupKey: 'cfg.group.agent',
294
- },
295
- {
296
- path: 'ui.inputBorder',
297
- type: 'enum',
298
- values: ['round', 'single', 'double', 'bold', 'none'],
299
- labelKey: 'cfg.f.ui_inputBorder',
300
- groupKey: 'cfg.group.ui',
301
- },
302
- {
303
- path: 'ui.theme',
304
- type: 'enum',
305
- values: themeNames(),
306
- labelKey: 'cfg.f.ui_theme',
307
- groupKey: 'cfg.group.ui',
308
- },
309
- {
310
- path: 'ui.answerWidth',
311
- type: 'number',
312
- min: 0,
313
- max: 1000,
314
- labelKey: 'cfg.f.ui_answerWidth',
315
- groupKey: 'cfg.group.ui',
316
- },
317
- {
318
- path: 'ui.tui',
319
- type: 'boolean',
320
- labelKey: 'cfg.f.ui_tui',
321
- groupKey: 'cfg.group.ui',
322
- },
323
- {
324
- path: 'ui.alternateScreen',
325
- type: 'boolean',
326
- labelKey: 'cfg.f.ui_alternateScreen',
327
- groupKey: 'cfg.group.ui',
328
- },
329
- {
330
- path: 'ui.mouseScroll',
331
- type: 'boolean',
332
- labelKey: 'cfg.f.ui_mouseScroll',
333
- groupKey: 'cfg.group.ui',
334
- },
335
- {
336
- path: 'headless',
337
- type: 'boolean',
338
- labelKey: 'cfg.f.headless',
339
- groupKey: 'cfg.group.agent',
340
- },
341
- {
342
- path: 'browser.auth.username',
343
- type: 'string',
344
- labelKey: 'cfg.f.browser_authUsername',
345
- groupKey: 'cfg.group.browser',
346
- },
347
- {
348
- path: 'browser.auth.password',
349
- type: 'string',
350
- labelKey: 'cfg.f.browser_authPassword',
351
- groupKey: 'cfg.group.browser',
352
- },
353
- {
354
- path: 'browser.auth.saveSession',
355
- type: 'boolean',
356
- labelKey: 'cfg.f.browser_authSaveSession',
357
- groupKey: 'cfg.group.browser',
358
- },
359
- // Each non-DeepSeek provider owns its credentials, so a DeepSeek login is
360
- // never typed into a Qwen/GLM form (and vice versa). They MUST be in the
361
- // schema: writeConfigValue rejects an unknown key, which silently dropped
362
- // every GLM/Qwen credential saved from the login window.
363
- {
364
- path: 'qwen.auth.username',
365
- type: 'string',
366
- labelKey: 'cfg.f.qwen_authUsername',
367
- groupKey: 'cfg.group.browser',
368
- },
369
- {
370
- path: 'qwen.auth.password',
371
- type: 'string',
372
- labelKey: 'cfg.f.qwen_authPassword',
373
- groupKey: 'cfg.group.browser',
374
- },
375
- {
376
- path: 'glm.auth.username',
377
- type: 'string',
378
- labelKey: 'cfg.f.glm_authUsername',
379
- groupKey: 'cfg.group.browser',
380
- },
381
- {
382
- path: 'glm.auth.password',
383
- type: 'string',
384
- labelKey: 'cfg.f.glm_authPassword',
385
- groupKey: 'cfg.group.browser',
386
- },
387
- {
388
- path: 'provider',
389
- type: 'enum',
390
- values: [...PROVIDER_IDS],
391
- labelKey: 'cfg.f.provider',
392
- groupKey: 'cfg.group.browser',
393
- },
394
- {
395
- path: 'qwen.model',
396
- type: 'string',
397
- labelKey: 'cfg.f.qwen_model',
398
- groupKey: 'cfg.group.browser',
399
- },
400
- {
401
- path: 'qwen.contextLimit',
402
- type: 'number',
403
- min: 10_000,
404
- max: 10_000_000,
405
- labelKey: 'cfg.f.qwen_contextLimit',
406
- groupKey: 'cfg.group.browser',
407
- },
408
- {
409
- path: 'qwen.minSendIntervalMs',
410
- type: 'number',
411
- min: 0,
412
- max: 600000,
413
- labelKey: 'cfg.f.qwen_minSendIntervalMs',
414
- groupKey: 'cfg.group.browser',
415
- },
416
- {
417
- path: 'qwen.answerTimeoutMs',
418
- type: 'number',
419
- min: 1000,
420
- max: 3600000,
421
- labelKey: 'cfg.f.qwen_answerTimeoutMs',
422
- groupKey: 'cfg.group.browser',
423
- },
424
- {
425
- path: 'glm.model',
426
- type: 'string',
427
- labelKey: 'cfg.f.glm_model',
428
- groupKey: 'cfg.group.browser',
429
- },
430
- {
431
- path: 'glm.contextLimit',
432
- type: 'number',
433
- min: 10_000,
434
- max: 10_000_000,
435
- labelKey: 'cfg.f.glm_contextLimit',
436
- groupKey: 'cfg.group.browser',
437
- },
438
- {
439
- path: 'glm.minSendIntervalMs',
440
- type: 'number',
441
- min: 0,
442
- max: 600000,
443
- labelKey: 'cfg.f.glm_minSendIntervalMs',
444
- groupKey: 'cfg.group.browser',
445
- },
446
- {
447
- path: 'glm.answerTimeoutMs',
448
- type: 'number',
449
- min: 1000,
450
- max: 3600000,
451
- labelKey: 'cfg.f.glm_answerTimeoutMs',
452
- groupKey: 'cfg.group.browser',
453
- },
454
- {
455
- path: 'debug',
456
- type: 'boolean',
457
- labelKey: 'cfg.f.debug',
458
- groupKey: 'cfg.group.agent',
459
- },
460
- {
461
- path: 'hotReload',
462
- type: 'boolean',
463
- labelKey: 'cfg.f.hotReload',
464
- groupKey: 'cfg.group.agent',
465
- },
466
- {
467
- path: 'undo.enabled',
468
- type: 'boolean',
469
- labelKey: 'cfg.f.undo_enabled',
470
- groupKey: 'cfg.group.undo',
471
- },
472
- {
473
- path: 'undo.maxBackups',
474
- type: 'number',
475
- min: 1,
476
- max: 100000,
477
- labelKey: 'cfg.f.undo_maxBackups',
478
- groupKey: 'cfg.group.undo',
479
- },
480
- {
481
- path: 'checkpoint.enabled',
482
- type: 'boolean',
483
- labelKey: 'cfg.f.checkpoint_enabled',
484
- groupKey: 'cfg.group.checkpoint',
485
- },
486
- {
487
- path: 'checkpoint.maxBackups',
488
- type: 'number',
489
- min: 1,
490
- max: 1000,
491
- labelKey: 'cfg.f.checkpoint_maxBackups',
492
- groupKey: 'cfg.group.checkpoint',
493
- },
494
- {
495
- path: 'transcript.enabled',
496
- type: 'boolean',
497
- labelKey: 'cfg.f.transcript_enabled',
498
- groupKey: 'cfg.group.transcript',
499
- },
500
- {
501
- path: 'browser.answerTimeoutMs',
502
- type: 'number',
503
- min: 1000,
504
- max: 3600000,
505
- labelKey: 'cfg.f.browser_answerTimeoutMs',
506
- groupKey: 'cfg.group.browser',
507
- },
508
- {
509
- path: 'browser.askRetries',
510
- type: 'number',
511
- min: 1,
512
- max: 100,
513
- labelKey: 'cfg.f.browser_askRetries',
514
- groupKey: 'cfg.group.browser',
515
- },
516
- {
517
- path: 'browser.stabilityChecks',
518
- type: 'number',
519
- min: 1,
520
- max: 100,
521
- labelKey: 'cfg.f.browser_stabilityChecks',
522
- groupKey: 'cfg.group.browser',
523
- },
524
- {
525
- path: 'browser.stabilityDelayMs',
526
- type: 'number',
527
- min: 0,
528
- max: 60000,
529
- labelKey: 'cfg.f.browser_stabilityDelayMs',
530
- groupKey: 'cfg.group.browser',
531
- },
532
- {
533
- path: 'browser.minSendIntervalMs',
534
- type: 'number',
535
- min: 0,
536
- max: 600000,
537
- labelKey: 'cfg.f.browser_minSendIntervalMs',
538
- groupKey: 'cfg.group.browser',
539
- },
540
- {
541
- path: 'browser.thinkingExtraMs',
542
- type: 'number',
543
- min: 0,
544
- max: 600000,
545
- labelKey: 'cfg.f.browser_thinkingExtraMs',
546
- groupKey: 'cfg.group.browser',
547
- },
548
- {
549
- path: 'browser.rateLimitWaitMs',
550
- type: 'number',
551
- min: 0,
552
- max: 3600000,
553
- labelKey: 'cfg.f.browser_rateLimitWaitMs',
554
- groupKey: 'cfg.group.browser',
555
- },
556
- {
557
- path: 'browser.maxRateLimitRetries',
558
- type: 'number',
559
- min: 0,
560
- max: 100,
561
- labelKey: 'cfg.f.browser_maxRateLimitRetries',
562
- groupKey: 'cfg.group.browser',
563
- },
564
- {
565
- path: 'browser.maxIncompleteRetries',
566
- type: 'number',
567
- min: 0,
568
- max: 100,
569
- labelKey: 'cfg.f.browser_maxIncompleteRetries',
570
- groupKey: 'cfg.group.browser',
571
- },
572
- {
573
- path: 'browser.incompleteWaitMs',
574
- type: 'number',
575
- min: 0,
576
- max: 600000,
577
- labelKey: 'cfg.f.browser_incompleteWaitMs',
578
- groupKey: 'cfg.group.browser',
579
- },
580
- {
581
- path: 'browser.autoContinue',
582
- type: 'boolean',
583
- labelKey: 'cfg.f.browser_autoContinue',
584
- groupKey: 'cfg.group.browser',
585
- },
586
- {
587
- path: 'browser.sendTelemetry',
588
- type: 'boolean',
589
- labelKey: 'cfg.f.browser_sendTelemetry',
590
- groupKey: 'cfg.group.browser',
591
- },
592
- {
593
- path: 'browser.loginTimeoutMs',
594
- type: 'number',
595
- min: 30_000,
596
- max: 3_600_000,
597
- labelKey: 'cfg.f.browser_loginTimeoutMs',
598
- groupKey: 'cfg.group.browser',
599
- },
600
- {
601
- path: 'browser.continueMinGapMs',
602
- type: 'number',
603
- min: 0,
604
- max: 600000,
605
- labelKey: 'cfg.f.browser_continueMinGapMs',
606
- groupKey: 'cfg.group.browser',
607
- },
608
- {
609
- path: 'browser.askDeadlineMs',
610
- type: 'number',
611
- min: 30000,
612
- max: 1800000,
613
- labelKey: 'cfg.f.browser_askDeadlineMs',
614
- groupKey: 'cfg.group.browser',
615
- },
616
- {
617
- path: 'browser.maxAfterToolRetries',
618
- type: 'number',
619
- min: 0,
620
- max: 50,
621
- labelKey: 'cfg.f.browser_maxAfterToolRetries',
622
- groupKey: 'cfg.group.browser',
623
- },
624
- {
625
- path: 'browser.autoCompact',
626
- type: 'boolean',
627
- labelKey: 'cfg.f.browser_autoCompact',
628
- groupKey: 'cfg.group.browser',
629
- },
630
- {
631
- path: 'browser.autoCompactPct',
632
- type: 'number',
633
- min: 50,
634
- max: 100,
635
- labelKey: 'cfg.f.browser_autoCompactPct',
636
- groupKey: 'cfg.group.browser',
637
- },
638
- {
639
- path: 'browser.resendPromptOnResume',
640
- type: 'boolean',
641
- labelKey: 'cfg.f.browser_resendPromptOnResume',
642
- groupKey: 'cfg.group.browser',
643
- },
644
- {
645
- path: 'browser.subagents',
646
- type: 'boolean',
647
- labelKey: 'cfg.f.browser_subagents',
648
- groupKey: 'cfg.group.browser',
649
- },
650
- {
651
- path: 'browser.maxSubagents',
652
- type: 'number',
653
- min: 0,
654
- max: 20,
655
- labelKey: 'cfg.f.browser_maxSubagents',
656
- groupKey: 'cfg.group.browser',
657
- },
658
- {
659
- path: 'browser.deepThinking',
660
- type: 'boolean',
661
- labelKey: 'cfg.f.browser_deepThinking',
662
- groupKey: 'cfg.group.browser',
663
- },
664
- {
665
- path: 'browser.webSearch',
666
- type: 'boolean',
667
- labelKey: 'cfg.f.browser_webSearch',
668
- groupKey: 'cfg.group.browser',
669
- },
670
- {
671
- path: 'ui.contextLimit',
672
- type: 'number',
673
- min: 10_000,
674
- max: 10_000_000,
675
- labelKey: 'cfg.f.ui_contextLimit',
676
- groupKey: 'cfg.group.ui',
677
- },
678
- ];
679
- export function getConfigField(path) {
680
- return CONFIG_SCHEMA.find((f) => f.path === path);
681
- }
682
282
  export function getByPath(obj, path) {
683
283
  const parts = path.split('.');
684
284
  // Two guards, both load-bearing. UNSAFE_PATH_KEYS keeps a dotted path off
@@ -1,11 +1,33 @@
1
1
  // Config menu and config command messages.
2
2
  export const configMessages = {
3
- 'cfg.group.ui': { ru: 'Интерфейс', en: 'Interface' },
4
- 'cfg.group.agent': { ru: 'Агент', en: 'Agent' },
3
+ // Top-level menu groups (/config opens a list of THESE).
4
+ 'cfg.top.agent': { ru: 'Агент', en: 'Agent' },
5
+ 'cfg.top.browser': { ru: 'Браузер и чат', en: 'Browser & chat' },
6
+ 'cfg.top.providers': { ru: 'Провайдеры', en: 'Providers' },
7
+ 'cfg.top.ui': { ru: 'Интерфейс', en: 'Interface' },
8
+ 'cfg.top.files': { ru: 'Файлы и история', en: 'Files & history' },
9
+ 'cfg.top.diagnostics': { ru: 'Диагностика', en: 'Diagnostics' },
10
+ // Sections INSIDE a top-level group.
11
+ 'cfg.group.agent': { ru: 'Основное', en: 'General' },
12
+ 'cfg.group.chat': { ru: 'Сессия чата', en: 'Chat session' },
13
+ 'cfg.group.throttle': { ru: 'Паузы и лимиты', en: 'Pacing & limits' },
14
+ 'cfg.group.recovery': {
15
+ ru: 'Сбои и восстановление',
16
+ en: 'Failures & recovery',
17
+ },
18
+ 'cfg.group.login': { ru: 'Вход в аккаунт', en: 'Sign-in' },
19
+ 'cfg.group.telemetry': { ru: 'Телеметрия', en: 'Telemetry' },
20
+ 'cfg.group.qwen': { ru: 'Qwen', en: 'Qwen' },
21
+ 'cfg.group.glm': { ru: 'GLM', en: 'GLM' },
22
+ 'cfg.group.look': { ru: 'Язык и оформление', en: 'Language & look' },
23
+ 'cfg.group.tui': { ru: 'Терминальный TUI', en: 'Terminal TUI' },
5
24
  'cfg.group.undo': { ru: 'Откат (undo)', en: 'Undo' },
6
25
  'cfg.group.checkpoint': { ru: 'Чекпойнты', en: 'Checkpoints' },
7
26
  'cfg.group.transcript': { ru: 'Транскрипт', en: 'Transcript' },
8
- 'cfg.group.browser': { ru: 'Браузер / чат', en: 'Browser / chat' },
27
+ 'cfg.group.diagnostics': {
28
+ ru: 'Проверка после правки',
29
+ en: 'Post-edit check',
30
+ },
9
31
  'cfg.f.provider': { ru: 'Провайдер чата', en: 'Chat provider' },
10
32
  'cfg.f.qwen_model': {
11
33
  ru: 'Модель Qwen (id)',
@@ -314,4 +336,41 @@ export const configMessages = {
314
336
  ru: 'Этот параметр применится после перезапуска.',
315
337
  en: 'This setting takes effect after a restart.',
316
338
  },
339
+ 'cfg.f.diagnostics_enabled': {
340
+ ru: 'Запускать проверку после правки файлов',
341
+ en: 'Run the check after a file edit',
342
+ },
343
+ 'cfg.f.diagnostics_command': {
344
+ ru: 'Команда проверки (например, npx tsc --noEmit)',
345
+ en: 'Check command (e.g. npx tsc --noEmit)',
346
+ },
347
+ 'cfg.f.diagnostics_timeoutMs': {
348
+ ru: 'Таймаут проверки, мс',
349
+ en: 'Check timeout, ms',
350
+ },
351
+ 'cfg.f.diagnostics_maxChars': {
352
+ ru: 'Сколько символов вывода проверки отдавать агенту',
353
+ en: 'How many output chars of the check go to the agent',
354
+ },
355
+ // Two-level menu: group list, then the settings inside a group.
356
+ 'cfg.menu.groups_title': {
357
+ ru: '⚙ Настройки — выбери группу',
358
+ en: '⚙ Settings — choose a group',
359
+ },
360
+ 'cfg.menu.group_hint': {
361
+ ru: '↑/↓ — выбор, Enter — открыть группу, q/Esc — выйти',
362
+ en: '↑/↓ select, Enter open the group, q/Esc quit',
363
+ },
364
+ 'cfg.menu.group_count': {
365
+ ru: 'настроек: {n}',
366
+ en: 'settings: {n}',
367
+ },
368
+ 'cfg.menu.group_modified': {
369
+ ru: 'изменено: {n}',
370
+ en: 'changed: {n}',
371
+ },
372
+ 'cfg.menu.back_hint': {
373
+ ru: 'Esc — назад к группам',
374
+ en: 'Esc — back to the groups',
375
+ },
317
376
  };
@@ -137,6 +137,7 @@ export const deepseekMessages = {
137
137
  'tui.hint.reset': { ru: 'сброс', en: 'reset' },
138
138
  'tui.hint.quit': { ru: 'выход', en: 'quit' },
139
139
  'tui.hint.change': { ru: 'изменить', en: 'change' },
140
+ 'tui.hint.back': { ru: 'назад', en: 'back' },
140
141
  // Marks the CURRENT entry in a list menu (e.g. the active Qwen model).
141
142
  'tui.list.current': { ru: '← текущая', en: '← current' },
142
143
  'auth.form.note_saved': {
package/dist/index.js CHANGED
@@ -696,10 +696,15 @@ function buildSlashCommands() {
696
696
  // We put the agent's temporary files (one-off scripts, etc.) in
697
697
  // <project>/tmp — this folder is in .gitignore and is cleaned on every launch.
698
698
  const TMP_DIR = path.join(__dirname, '..', 'tmp');
699
+ // An explicit override keeps a test/verification run from WIPING the real
700
+ // <project>/tmp on launch (that directory holds the operator's attachments).
701
+ const EFFECTIVE_TMP_DIR = process.env.ZAMES_TMP_DIR
702
+ ? path.resolve(process.env.ZAMES_TMP_DIR)
703
+ : TMP_DIR;
699
704
  async function cleanTmpDir() {
700
705
  try {
701
- await fs.rm(TMP_DIR, { recursive: true, force: true });
702
- await fs.mkdir(TMP_DIR, { recursive: true });
706
+ await fs.rm(EFFECTIVE_TMP_DIR, { recursive: true, force: true });
707
+ await fs.mkdir(EFFECTIVE_TMP_DIR, { recursive: true });
703
708
  }
704
709
  catch (e) {
705
710
  if (debug)
@@ -1537,7 +1542,7 @@ async function main() {
1537
1542
  locale: currentLocale,
1538
1543
  });
1539
1544
  editor = ed;
1540
- ed.setTmpDir(TMP_DIR);
1545
+ ed.setTmpDir(EFFECTIVE_TMP_DIR);
1541
1546
  // Provider badge: show which backend is answering ([Qwen]/[DeepSeek]).
1542
1547
  ed.setProvider(providerLabel(config.provider));
1543
1548
  // Header for full-screen mode (title / version / working directory).
@@ -1676,7 +1681,7 @@ async function main() {
1676
1681
  const image = parseImagePaste(raw);
1677
1682
  if (image) {
1678
1683
  const name = 'paste' + extForMime(image.mime);
1679
- const p = await saveToTemp(TMP_DIR, name, image.data);
1684
+ const p = await saveToTemp(EFFECTIVE_TMP_DIR, name, image.data);
1680
1685
  const att = ed.attachments.add({
1681
1686
  path: p,
1682
1687
  name,
@@ -1750,7 +1755,7 @@ async function main() {
1750
1755
  }
1751
1756
  const mime = sniffMime(res.data) || 'image/png';
1752
1757
  const name = 'clipboard-' + Date.now() + (extForMime(mime) || '.png');
1753
- const p = await saveToTemp(TMP_DIR, name, res.data);
1758
+ const p = await saveToTemp(EFFECTIVE_TMP_DIR, name, res.data);
1754
1759
  const att = ed.attachments.add({
1755
1760
  path: p,
1756
1761
  name,