@goodandready/dsh-cost-meter 0.7.9 → 0.8.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 CHANGED
@@ -138,3 +138,10 @@ npm test
138
138
  ## 📄 License
139
139
 
140
140
  MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY)
141
+
142
+ ### Performance & Smart Cost Features (v0.8.1)
143
+ - **O(K) Rate Change Calculation**: Next schedule transition is resolved in $O(K)$ boundary hops instead of full-day iterations.
144
+ - **Server Cache & ETag**: High-throughput state polling with `304 Not Modified` support and internal tariff LRU cache.
145
+ - **Manual Catalog Sync**: On-demand catalog fetch via `POST /dsh-cost-meter/refresh` or UI "Sync Now" button.
146
+ - **Savings Advice & Budget Threshold**: Popover hints on impending off-peak discounts (50% off) and optional warning thresholds (`budgetThreshold`).
147
+ - **Quick Summary Export**: Instant markdown/text summary copy to clipboard.
package/docs/README.ru.md CHANGED
@@ -138,3 +138,9 @@ npm test
138
138
  ## 📄 Лицензия
139
139
 
140
140
  MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY)
141
+
142
+ ### Производительность и интеллектуальные подсказки (v0.8.1)
143
+ - **Алгоритм O(K)**: Моментальный расчёт границ смены тарифов и мемоизация экстремумов без лишних циклов в браузере.
144
+ - **Серверный кэш и ETag**: Поддержка заголовка `304 Not Modified` для маршрута `/state` и кэширование сопоставлений моделей.
145
+ - **Ручная синхронизация**: Кнопка «Синхронизировать сейчас» в настройках с защитой от флуда (`POST /dsh-cost-meter/refresh`).
146
+ - **Подсказки экономии и порог бюджета**: Отсчёт времени до льготного окна (скидка 50%), порог сессии (`budgetThreshold`) и экспорт сводки в буфер обмена.
@@ -22,7 +22,11 @@
22
22
  - Документация:
23
23
  - README.md, index.md, docs/testing/public-route.md, docs/testing/projection-lifecycle.md, docs/deployment/public-release.md.
24
24
 
25
- ## Visual Direction
25
+ ## Visual Direction (Unified with dsh-clinebot)
26
+ - Атмосфера: Строгий утилитарный нативный интерфейс DSH, высокая информационная плотность без визуального шума.
27
+ - Утверждённые референсы: Эталонный плагин `@goodandready/dsh-clinebot`, дизайн-система DeepSeek Harness (`--dsw-alias-*`), карточки секций `.dcm-section-card`, бейджи статуса `.dcm-badge`, адаптивная сетка параметров `.dcm-grid-2`, чипы в шапке сессии.
28
+ - Отказоустойчивость: Обязательный `ErrorBoundary` вокруг карточки настроек и поповера шапки (предотвращает исчезновение слотов ядра при исключениях рендеринга).
29
+ - Синхронизация зеркал: `refreshMirrorUntilVisible(ctx)` для надёжного доступа к зеркалу `settingsScope`.
26
30
  - Атмосфера: Строгий утилитарный нативный интерфейс DSH, высокая информационная плотность без визуального шума.
27
31
  - Утверждённые референсы: Дизайн-система DeepSeek Harness (`--dsw-alias-*`), чипы в шапке сессии (`dsh-key-rotation`, `dsh-context-lens`), стандарт карточек настроек DSH.
28
32
  - Не копировать: Избыточные градиенты, внешние модальные окна, тяжелые тени, кастомные несогласованные шрифты.
@@ -41,7 +45,7 @@
41
45
  - Сетка и отступы:
42
46
  - Чип: высота 22px, padding: 0 8px, gap: 6px, border-radius: 6px.
43
47
  - Панель: padding: 12px 14px, border-radius: 10px, ширина 320px.
44
- - Карточка настроек: нативный складной контейнер (`.dcm-settings-card`), отступы полей, бейдж статуса снимка (`ready`, `loading`, `unavailable`).
48
+ - Карточка настроек: нативный складной контейнер (`.dcm-card`) с шапкой, статусами-бейджами (`dcm-badge-ok`, `dcm-badge-warn`, `dcm-badge-bad`), 3 структурированными секциями (`Основные параметры`, `Каталог OpenRouter`, `Диагностика и статус`), защитой ввода и кнопкой сохранения (`dcm-btn-primary`).
45
49
 
46
50
  ## Components & States
47
51
  - Чип:
@@ -82,6 +86,15 @@
82
86
  - Не допускать утечек локальных путей и инфраструктурных данных в коде или документации.
83
87
 
84
88
  ## History & Decisions
89
+ - 2026-09-12 (v0.8.1):
90
+ - Оптимизация производительности расчёта тарифов: замена 1440-минутного цикла на алгоритм O(K) по точкам перехода и мемоизация экстремумов через WeakMap.
91
+ - Серверный кэш разрешения тарифов resolveTariffCache (Map) с автоматической очисткой при обновлении каталога.
92
+ - Поддержка ETag и ответа 304 Not Modified на эндпоинте /dsh-cost-meter/state.
93
+ - Кнопка ручной синхронизации каталога цен в секции OpenRouter с защитой от флуда (cooldown 30 сек).
94
+ - Интеллектуальные подсказки экономии: плашка скорого наступления льготного тарифа (скидка 50%) и отсчёт времени.
95
+ - Поддержка настраиваемого порога бюджета сессии (budgetThreshold) с предупреждающей подсветкой чипа.
96
+ - Кнопка быстрого копирования текстового отчёта о расходах в буфер обмена.
97
+ - Таблица нормализации алиасов вендоров (z-ai -> zai, deepseek-official -> deepseek, gemini -> google).
85
98
  - 2026-09-05 (v0.7.9):
86
99
  - Hotfix: исправлен ReferenceError (t is not defined) в объекте словаря ru (lib/client.js) (#15).
87
100
  - Добавлен автоматический тест на чистое исполнение фабрики client loader (`test/public-route.test.mjs`).
@@ -1,22 +1,17 @@
1
- # Technical Findings (Issue #21)
1
+ # Findings: Issue #25 (v0.8.1)
2
2
 
3
- ## 1. Config Fields Breakdown
4
- The plugin `Config` defines 10 fields:
5
- 1. `currency` (string, default '$') -> Present in UI
6
- 2. `usdRate` (number, default 1) -> Present in UI
7
- 3. `displayTimeZone` (string, default 'Europe/Moscow') -> Present in UI
8
- 4. `useOpenRouter` (boolean, default true) -> Missing in UI -> To be added as a checkbox in `CostMeterCard`
9
- 5. `refreshHours` (number, default 24) -> Missing in UI -> To be added as a numeric input in `CostMeterCard`
10
- 6. `modelMap` (dict of string -> string) -> Advanced JSON/YAML route mapping
11
- 7. `prices` (dict of PriceRow) -> Advanced manual pricing rules
12
- 8. `deepseekPeakPrices` (dict of PriceRow) -> Advanced DeepSeek peak overrides
13
- 9. `manualPeakWindowsUtc` (array of string) -> Advanced manual time windows
14
- 10. `manualOffPeakMultiplier` (number) -> Advanced discount multiplier for manual rates
3
+ ## 1. Клиентские вычисления расписания
4
+ - В `lib/client.js`: `extremes()` и `minutesUntilChange()` вызывались на каждом тике таймера (15 сек) и перерисовывали 1440-минутный цикл:
5
+ `for (let minute = 0; minute < 1440; minute++)` с поиском в `windows`.
6
+ - В сутках конечное число окон $K$ (обычно 2–4). Смена тарифа может происходить только на границах интервалов: `window.start` и `window.end`.
7
+ - Замена на $O(K)$ даёт мгновенный расчёт без аллокации сотен объектов в секунду при активных сессиях.
15
8
 
16
- By adding `useOpenRouter` and `refreshHours` to `CostMeterCard`, all 5 primary scalar/control settings are directly configurable in the DSH Settings GUI. The 5 advanced structured override rules (`prices`, `modelMap`, `deepseekPeakPrices`, `manualPeakWindowsUtc`, `manualOffPeakMultiplier`) are explicitly documented in README.md and DESIGN.md as YAML configuration rows.
9
+ ## 2. Разрешение тарифов на сервере
10
+ - `resolveTariff(cfg, catalog.index, route)` перебирает регулярные выражения и суффиксы.
11
+ - Кэширование в `Map<string, ResolvedTariff>` с очисткой при обновлении каталога полностью снимает нагрузку на CPU при частом пуллинге `/state` клиентами DSH.
17
12
 
18
- ## 2. Service Access Pattern
19
- In `lib/index.js`, we have:
20
- `const settings = ctx.get('settings')` (canonical).
21
- In `lib/client.js`, `ctx.settingsScope` is accessed directly. We should safely check `(ctx.get && ctx.get('settingsScope')) || ctx.settingsScope || (ctx.services && ctx.services.settingsScope)`.
22
- Same for `ctx.locale` and `ctx.slots`.
13
+ ## 3. Поддержка ETag
14
+ - Для `/dsh-cost-meter/state` генерация слабого ETag (`W/"<hash>"`) на основе `updatedAt`, `fetchedAt` и счетчиков токенов позволяет клиентам передавать `If-None-Match` и получать `304 Not Modified`, экономя полосу пропускания и парсинг JSON.
15
+
16
+ ## 4. Алиасы вендоров
17
+ - Разные провайдеры в DSH могут передавать вендоров как `z-ai`, `zai`, `google`, `gemini`, `deepseek-ai`, `deepseek`. Единая нормализация исключит ситуации fallback на generic тариф.
@@ -1,17 +1,12 @@
1
- # Progress Log (Issue #21 / v0.7.9)
1
+ # Progress: Issue #25 (v0.8.1)
2
2
 
3
- - [x] Analyze Issue #21
4
- - [x] Create worktree `.worktrees/issue-21`
5
- - [x] Initialize plans (`task_plan.md`, `findings.md`, `progress.md`)
6
- - [x] Bump version to 0.7.9 in `package.json`
7
- - [x] Implement settings card additions (`useOpenRouter`, `refreshHours`) in `lib/client.js`
8
- - [x] Safe service resolution with `ctx.get('...')` in `lib/client.js`
9
- - [x] Update documentation with full 10-field matrix (`README.md`, `docs/README.ru.md`, `docs/design/DESIGN.md`)
10
- - [x] Add regression test `test/settings-card-fields.test.mjs` (12/12 passing)
11
- - [ ] Commit changes with conventional commits (`git-antigravity`)
12
- - [ ] Create Pull Request and merge into `main`
13
- - [ ] Test package on MiniPC isolated test server (`192.168.1.123:3082`)
14
- - [ ] Smoke-test package on production candidate (`192.168.1.111:3080`)
15
- - [ ] Publish v0.7.9 to npm and GitHub Release
16
- - [ ] Install v0.7.9 from npm on MiniAI and verify live health
17
- - [ ] Close Gitea Issue #21 and clean up worktree
3
+ - **2026-09-12 19:10**:
4
+ - Создана Gitea Issue #25.
5
+ - Создан worktree `.worktrees/issue-25` от `origin/main` (ветка `feat/issue-25-perf-and-smart-features`).
6
+ - Инициализированы планы в `docs/plans/`.
7
+
8
+ - **2026-09-12 19:16**:
9
+ - Реализованы оптимизации в `lib/index.js` (resolveTariffCache, ETag / 304, POST /refresh, budgetThreshold, VENDOR_ALIASES).
10
+ - Реализованы улучшения в `lib/client.js` (O(K) minutesUntilChange, memoized extremes, кнопка синхронизации с cooldown, порог бюджета, плашка экономии, копирование сводки).
11
+ - Добавлены тесты в `test/v081-perf-smart.test.mjs` (все 20 тестов успешно пройдены).
12
+ - Версия поднята до `0.8.1`.
@@ -1,32 +1,31 @@
1
- # Task Plan: Address Issue #21 (Settings Card Schema Fields & Service Access)
1
+ # Task Plan: Issue #25 (v0.8.1) — Оптимизация производительности, ручная синхронизация каталога и подсказки экономии
2
2
 
3
- ## 1. Goal
4
- Fulfill Gitea Issue #21 requirements:
5
- 1. **Schema Fields Availability in Settings Card**:
6
- - Audit all 10 fields of `Config`:
7
- - UI fields: `currency`, `usdRate`, `displayTimeZone`.
8
- - Boolean toggle: `useOpenRouter` (checkbox / toggle in settings card).
9
- - Numeric: `refreshHours` (catalog refresh frequency, e.g. 24 hours).
10
- - Complex structured overrides: `prices` (dict), `modelMap` (dict), `deepseekPeakPrices` (dict), `manualPeakWindowsUtc` (array), `manualOffPeakMultiplier` (number).
11
- - Add `useOpenRouter` and `refreshHours` directly to the `CostMeterCard` form so all scalar/toggle configuration is editable in GUI.
12
- - Document structured dict/array fields (`prices`, `modelMap`, `deepseekPeakPrices`, `manualPeakWindowsUtc`, `manualOffPeakMultiplier`) in documentation, READMEs and DESIGN.md as YAML-only/advanced configuration rows.
13
- 2. **Context Service Access Hygiene**:
14
- - Inspect all `ctx.settings` / `ctx.settingsScope` / `ctx.locale` / `ctx.webServer` calls.
15
- - Use `ctx.get('...')` or inject where appropriate, or guard against undefined proxiable properties.
16
- 3. **Locale & Translations**:
17
- - Provide clean English locale strings as canonical with ru dictionaries, and hint descriptions for all new fields.
3
+ ## Цели
4
+ 1. **Скорость**:
5
+ - Оптимизация алгоритма расчета времени смены тарифа (`minutesUntilChange`) и экстремумов (`extremes`) с $O(1440)$ до $O(K)$ без полного минутного цикла.
6
+ - Серверный кэш `resolveTariffCache` для быстрого разрешения моделей.
7
+ - Поддержка ETag / 304 Not Modified на эндпоинте `/dsh-cost-meter/state`.
8
+ 2. **Качество и управление**:
9
+ - Маршрут `POST /dsh-cost-meter/refresh` с rate limit (cooldown 30 сек) и кнопка «Синхронизировать сейчас» в настройках.
10
+ - Таблица нормализации алиасов вендоров (Smart Vendor Aliases).
11
+ - Индикация stale-кэша каталога в UI.
12
+ 3. **Экономия**:
13
+ - Подсказка в поповере о приближении льготного тарифа (50% скидка).
14
+ - Конфигурируемый порог сессии `budgetThreshold` с предупреждающей подсветкой чипа.
15
+ - Кнопка «Скопировать сводку» в поповере.
16
+ 4. **Стандарты и релиз**:
17
+ - 100% прохождение тестов `npm test`.
18
+ - Проверка размера файлов (< 256 KiB).
19
+ - Тестирование на test server (MiniPC :3082), затем на MiniAI candidate (:3080).
20
+ - Запрос подтверждения пользователя -> публикация v0.8.1 в npm/GitHub -> rollout на прод.
18
21
 
19
- ## 2. Checklist
20
- - [ ] Bump version to 0.7.9 in `package.json`
21
- - [ ] Add `useOpenRouter` and `refreshHours` fields to `CostMeterCard` in `lib/client.js`
22
- - [ ] Update `en` and `ru` dictionaries for new fields
23
- - [ ] Audit and refine service accesses in `lib/index.js` and `lib/client.js`
24
- - [ ] Update `README.md`, `docs/README.ru.md`, `docs/README.zh.md`, and `docs/design/DESIGN.md`
25
- - [ ] Add unit test verifying settings card field contract
26
- - [ ] Run `npm test` (all tests passing)
27
- - [ ] Conventional commit & push
28
- - [ ] Gitea PR & merge
29
- - [ ] Test on MiniPC test server (`192.168.1.123`)
30
- - [ ] Install on production MiniAI (`192.168.1.111`) & verify
31
- - [ ] Release v0.7.9 on GitHub & npm
32
- - [ ] Close Issue #21 & cleanup worktree
22
+ ## Статус выполнения
23
+ - [x] Issue #25 создана
24
+ - [x] Worktree `.worktrees/issue-25` развёрнут
25
+ - [x] Реализация серверной части (`lib/index.js`)
26
+ - [x] Реализация клиентской части (`lib/client.js`)
27
+ - [x] Добавление unit-тестов в `test/`
28
+ - [x] Обновление документации (`DESIGN.md`, `README.md`, `README.ru.md`)
29
+ - [ ] Тестирование на стендах (:3082, :3080)
30
+ - [ ] Публикация релиза v0.8.1
31
+ - [ ] Закрытие Issue #25 и очистка worktree