diff --git a/CHANGELOG.md b/CHANGELOG.md index 39c82f0..ea9a9b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,33 @@ # Changelog +## [4.0.32] - 2026-09-19 + +### Added + +- 🎨 **Свой цвет текста** — в разделе «Шрифт» появилась пипетка с HEX-полем, чтобы красить шрифт интерфейса и страницы в любой цвет: + - выбираешь цвет — он применяется мгновенно и к интерфейсу Cookie Code, и к странице DeepSeek; + - кнопка **«Сбросить»** возвращает системный цвет; + - панель Cookie Code исключена из перекраски — у неё своя цветовая схема, так что кастомный цвет её не ломает. +- 🔤 **Шрифт Ndot 47 из коробки** — в предустановленных появился точечно-матричный Ndot 47: выбирается одним кликом, как встроенный Anthropic Mono. +- 📊 **Точный учёт сообщений в статистике** — сообщения теперь считаются по появлению в DOM (.ds-message) с двойной дедупликацией: + - один DOM-узел учитывается ровно один раз (WeakSet); + - стабильный хэш (роль + позиция) уходит в главный процесс, поэтому повторный рендер диалога при SPA-навигации туда-обратно не раздувает счётчики; + - служебные сообщения Cookie Code (результаты инструментов, JS-сводки, контекст) больше не считаются пользовательскими. +- 📜 **Кодекс поведения** — добавлен bilingual CODE_OF_CONDUCT.md; в CONTRIBUTING.md появилась ссылка на него, а лицензия проекта исправлена на **MIT** (было указано GPL-3.0). + +### Changed + +- ⚡ **Превью в настройках больше не тормозят при пролистывании** — сетки фонов, шрифтов и чубриков перерисованы под лёгкий скролл: + - картинки превью грузятся лениво — полноразмерный data-URI подставляется только при приближении плитки к экрану, а не для всех сразу; + - невидимые плитки исключены из layout и отрисовки (content-visibility + contain); + - убраны дорогие hover-анимации (подъём и тень), которые заставляли браузер перерисовывать плитки на каждом кадре прокрутки. +- 🎨 **Кастомный скроллбар в настройках** — полоса прокрутки панели настроек оформлена в стиле темы: тонкий трек, скруглённый бегунок с подсветкой при наведении (webkit + scrollbar-width/color для Firefox). +- ✨ **Плавное появление окна инициализации** — first-time диалог теперь открывается и закрывается с анимацией (fade + лёгкий подъём/масштаб бокса) вместо резкого появления. + +### Fixed + +- 🐛 **Дашборд на домашней странице прячется, пока в поле ввода есть текст** — начал набирать сообщение — дашборд тут же уходит с глаз долой; очистил поле — возвращается. Реакция мгновенная, покрывает textarea и contenteditable, включая ввод через IME (compositionend). + ## [4.0.30] - 2026-09-18 ### Added diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..7d2cebf --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,225 @@ +# Кодекс поведения участника + +## Наше обязательство + +Мы, как участники, контрибьюторы и лидеры, обязуемся сделать участие в нашем +сообществе свободным от притеснений для всех — независимо от возраста, телосложения, +видимой или невидимой инвалидности, этнической принадлежности, половых признаков, +гендерной идентичности и самовыражения, уровня опыта, образования, социально-экономического +статуса, национальности, внешности, расы, религии, сексуальной идентичности и ориентации. + +Мы обязуемся действовать и взаимодействовать так, чтобы сообщество было открытым, +дружелюбным, разнообразным, инклюзивным и здоровым. + +## Наши стандарты + +Примеры поведения, которое создаёт позитивную атмосферу: + +- Проявление эмпатии и доброты к другим людям +- Уважение к разным мнениям, точкам зрения и опыту +- Конструктивная обратная связь и её достойное принятие +- Признание своих ошибок, извинения перед пострадавшими и извлечение уроков +- Ориентация на то, что лучше для сообщества в целом + +Примеры неприемлемого поведения: + +- Сексуализированные выражения или образы, нежелательное сексуальное внимание +- Троллинг, оскорбительные или уничижительные комментарии, личные или политические атаки +- Публичное или приватное преследование +- Публикация личной информации других лиц без их явного разрешения +- Иное поведение, которое разумно можно считать неуместным в профессиональной среде + +## Ответственность за соблюдение + +Лидеры сообщества отвечают за разъяснение и соблюдение наших стандартов и будут +принимать справедливые и соразмерные корректирующие меры в ответ на любое поведение, +которое они сочтут неуместным, угрожающим, оскорбительным или вредным. + +Лидеры сообщества имеют право и обязанность удалять, редактировать или отклонять +комментарии, коммиты, код, правки wiki, issues и другие вклады, не соответствующие +настоящему Кодексу поведения, и при необходимости сообщать причины своих решений. + +## Область применения + +Настоящий Кодекс поведения применяется во всех пространствах сообщества, а также +в тех случаях, когда человек официально представляет сообщество в публичных +пространствах. + +## Обеспечение соблюдения + +О случаях оскорбительного, преследующего или иного неприемлемого поведения можно +сообщить лидерам сообщества, ответственным за соблюдение Кодекса. +Все жалобы будут рассмотрены оперативно и справедливо. + +Лидеры сообщества обязаны уважать приватность и безопасность того, кто сообщает +о происшествии. + +## Руководство по применению + +Лидеры сообщества будут следовать этим правилам при определении последствий +для действий, нарушающих настоящий Кодекс: + +### 1. Исправление + +**Воздействие на сообщество:** неуместные выражения или иное поведение, +сочтённое непрофессиональным или нежелательным. + +**Последствие:** приватное письменное предупреждение от лидеров сообщества +с разъяснением характера нарушения и объяснением, почему поведение было +неуместным. Может быть запрошено публичное извинение. + +### 2. Предупреждение + +**Воздействие на сообщество:** нарушение в результате единичного инцидента +или серии действий. + +**Последствие:** предупреждение с последствиями при продолжении поведения. +Никакого взаимодействия с вовлечёнными лицами, включая нежелательный контакт +с теми, кто обеспечивает соблюдение Кодекса, в течение определённого времени. +Это включает избегание взаимодействия в пространствах сообщества, а также +во внешних каналах, таких как социальные сети. Нарушение этих условий может +привести к временному или постоянному бану. + +### 3. Временный бан + +**Воздействие на сообщество:** серьёзное нарушение стандартов сообщества, +включая устойчивое неуместное поведение. + +**Последствие:** временный запрет на любое взаимодействие или публичное +общение с сообществом на определённый срок. В этот период не допускается +публичное или приватное взаимодействие с вовлечёнными лицами, включая +нежелательный контакт с теми, кто обеспечивает соблюдение Кодекса. +Нарушение этих условий может привести к постоянному бану. + +### 4. Постоянный бан + +**Воздействие на сообщество:** демонстрация систематического нарушения +стандартов сообщества, включая устойчивое неуместное поведение, преследование +отдельного человека, агрессию или уничижение групп людей. + +**Последствие:** постоянный запрет на любое публичное взаимодействие +в рамках сообщества. + +## Атрибуция + +Настоящий Кодекс поведения адаптирован из +[Contributor Covenant](https://www.contributor-covenant.org), версия 2.1, +доступной по адресу +https://www.contributor-covenant.org/version/2/1/code_of_conduct.html. + +--- + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment: + +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +- Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior: + +- The use of sexualized language or imagery, and sexual attention or advances + of any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email address, + without their explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement. +All complaints will be reviewed and investigated promptly and fairly. + +Community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact:** Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence:** A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact:** A violation through a single incident or series of actions. + +**Consequence:** A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact:** A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence:** A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact:** Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence:** A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the +[Contributor Covenant](https://www.contributor-covenant.org), version 2.1, +available at +https://www.contributor-covenant.org/version/2/1/code_of_conduct.html. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index db74ba5..f282c02 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,10 +25,10 @@ - Добавляйте комментарии, особенно к сложной логике - Пишите просто, следуйте принципу «наименьшего удивления» - Перед началом работы создавайте отдельную ветку для feature или исправления. - Используйте формат `feature/` или `fix/`, например: - `feature/super-puper-update`. + Используйте формат `feature/` или `fix/`, например: + `feature/super-puper-update`. - Следуйте существующей архитектуре, структуре файлов, API и стилю проекта. - Не добавляйте новый подход, если в проекте уже есть подходящий шаблон. + Не добавляйте новый подход, если в проекте уже есть подходящий шаблон. ## Pull Request @@ -61,9 +61,13 @@ 4. Зарегистрируйте его в `ToolRegistry` (см. `src/main/tool-registry.js`). 5. Обновите `tools/rules.md` и `README.md`. +## Кодекс поведения + +Участвуя в проекте, вы соглашаетесь соблюдать [Кодекс поведения](CODE_OF_CONDUCT.md). + ## Лицензия -Проект распространяется под лицензией GPL-3.0. Все вклады подпадают под неё же. +Проект распространяется под лицензией MIT. Все вклады подпадают под неё же. --- @@ -80,12 +84,12 @@ Thank you for helping improve the project! We welcome all contributions: 1. Fork the repository and clone it locally. 2. Install dependencies: `npm install` - - If npm reports that the Electron postinstall script was blocked by - `allowScripts`, run: - - `npm install-scripts approve electron` - - then run `npm install` again. - - Otherwise, the Electron binary will not be downloaded and the app will - fail to start. + - If npm reports that the Electron postinstall script was blocked by + `allowScripts`, run: + - `npm install-scripts approve electron` + - then run `npm install` again. + - Otherwise, the Electron binary will not be downloaded and the app will + fail to start. 3. Start the application: `npm start` ## Code Style @@ -96,20 +100,20 @@ Thank you for helping improve the project! We welcome all contributions: - Add comments for complex logic where they improve maintainability. - Keep the implementation simple and follow the principle of least surprise. - Create a separate branch for every feature or fix before making changes. - Use `feature/` or `fix/`, for example: - `feature/super-puper-update`. + Use `feature/` or `fix/`, for example: + `feature/super-puper-update`. - Follow the existing project architecture, file structure, APIs, and coding - style. Do not introduce a new pattern when an existing one fits. + style. Do not introduce a new pattern when an existing one fits. ## Pull Requests 1. Base your branch on the latest `master`. 2. Test your changes before submitting them: `npm start`. 3. Keep commit messages short and precise. Use the project convention: - - `feat: add support for a new tool` - - `fix: fix command execution timeout` - - `docs: update README` - - `refactor: restructure tool registration` + - `feat: add support for a new tool` + - `fix: fix command execution timeout` + - `docs: update README` + - `refactor: restructure tool registration` 4. Describe what changed and how it was tested in the pull request. ## Bug Reports @@ -132,7 +136,12 @@ Use the existing implementations in `tools/` as a reference: 4. Register it in `ToolRegistry` (see `src/main/tool-registry.js`). 5. Update `tools/rules.md` and `README.md`. +## Code of Conduct + +By participating in this project, you agree to abide by the +[Code of Conduct](CODE_OF_CONDUCT.md). + ## License -The project is distributed under the GPL-3.0 license. All contributions are -subject to the same license. +The project is distributed under the MIT license. All contributions are subject +to the same license. diff --git a/src/main/settings-store.js b/src/main/settings-store.js index ed93b07..2104061 100644 --- a/src/main/settings-store.js +++ b/src/main/settings-store.js @@ -30,6 +30,8 @@ const DEFAULTS = { font: "system", // Жирность шрифта (100–900). Применяется и к системному, и к кастомному. fontWeight: 400, + // Кастомный цвет текста ("#rrggbb"). "" — системный (не переопределять). + fontColor: "", backgroundBlur: 0, // px — размытие самой картинки фона headerBlur: 12, // px — стекло верхней панели sidebarBlur: 12, // px — стекло левого сайдбара diff --git a/src/main/stats-store.js b/src/main/stats-store.js index f61de34..1dc5445 100644 --- a/src/main/stats-store.js +++ b/src/main/stats-store.js @@ -48,8 +48,14 @@ const EMPTY = { models: {}, // общий счётчик сообщений и токенов (для быстрого доступа) totals: { sessions: 0, messages: 0, tokens: 0 }, + // sessionId -> [hash, ...] — какие сообщения уже учтены (дедупликация). + // Ограничиваем список, чтобы файл не рос бесконечно. + countedHashes: {}, }; +// Максимум хранимых хэшей на сессию. +const MAX_HASHES_PER_SESSION = 500; + function readStats() { try { const file = getStatsPath(); @@ -62,6 +68,7 @@ function readStats() { days: parsed.days || {}, models: parsed.models || {}, totals: { ...EMPTY.totals, ...(parsed.totals || {}) }, + countedHashes: parsed.countedHashes || {}, }; } catch (err) { console.error("[Cookie Code] 读取 статистики失败:", err.message); @@ -85,6 +92,7 @@ function writeStats(stats) { * @param {object} ev * @param {string} [ev.sessionId] * @param {'user'|'ai'} ev.role + * @param {string} [ev.hash] стабильный хэш сообщения (для дедупликации) * @param {number} [ev.tokens] дельта токенов (если известна) * @param {string} [ev.model] */ @@ -96,6 +104,17 @@ function recordMessage(ev) { if (!stats.createdAt) stats.createdAt = now; + // Дедупликация по хэшу: одно и то же сообщение (в т.ч. после перерендера + // диалога при SPA-навигации) учитывается ровно один раз за сессию. + const hash = ev && ev.hash ? String(ev.hash) : ""; + if (hash) { + const seen = stats.countedHashes[sid] || []; + if (seen.indexOf(hash) !== -1) return stats; + seen.push(hash); + if (seen.length > MAX_HASHES_PER_SESSION) seen.shift(); + stats.countedHashes[sid] = seen; + } + // Сессия if (!stats.sessions[sid]) { stats.sessions[sid] = { diff --git a/src/preload/dom/fonts.js b/src/preload/dom/fonts.js index ce1b1f5..daa8906 100644 --- a/src/preload/dom/fonts.js +++ b/src/preload/dom/fonts.js @@ -29,6 +29,12 @@ const BUILTIN_FONTS = [ file: ["Anthropic Mono Web.otf", "Anthropic Mono Web Regular Italic.otf"], family: "Anthropic Mono", }, + { + id: "ndot-47", + label: "Ndot 47", + file: "ndot-47-inspired-by-nothing.otf", + family: "Ndot 47", + }, ]; const DEFAULT_ID = "system"; @@ -36,9 +42,11 @@ const DEFAULT_ID = "system"; // Жирность по умолчанию (обычное начертание). const DEFAULT_WEIGHT = 400; -// Текущий выбранный шрифт и жирность (для повторного применения). +// Текущий выбранный шрифт, жирность и цвет (для повторного применения). let currentFontId = DEFAULT_ID; let currentWeight = DEFAULT_WEIGHT; +// Кастомный цвет текста ("#rrggbb"). "" — системный (правило не применяется). +let currentColor = ""; // Стиль инъекции (id