Перейти до вмісту

Team Tracker

Team Tracker записує активні хвилини (тики раз на хвилину), класифікує їх для кожного workspace як internal або external за Git remote активного редактора, і надсилає агрегати в team API SnakeFlow. Функція вимкнена, доки ви не увійдете й не ввімкнете її.

Облік хвилин не залежить від Wake Lock → (запобігання сну ОС): трекер не вважає «людина активна» за фактом утримання wake lock.

Вимоги

  • SnakeFlow: Team Tracker — Login (GitHub OAuth у редакторі).
  • devManager.team.enabled = true (команда входу може увімкнути це автоматично).
  • Для системної миші та клавіатури поза редактором: ActivityWatch (aw-qt) на машині (рекомендовано; див. нижче).

ActivityWatch і статус-бар

Коли ActivityWatch запущений, розширення бачить активність у інших програмах (браузер, зовнішній термінал тощо), щоб не переходити в IDLE лише через відсутність подій у VS Code. Якщо є window watcher (bucket aw-watcher-window_*), раз на хвилину зчитується назва програми та заголовок вікна (коротке кешування) для allowlist програм і підказки в статус-барі.

  • Клік по елементу Team Tracker у статус-барізапуск aw-qt (якщо встановлено) або зупинка ActivityWatch (завершує локальні процеси ActivityWatch на ОС).
  • Якщо aw-qt не знайдено — пропозиція відкрити сторінку завантаження.
  • SnakeFlow: Team Tracker — Show Activity Log (Command Palette) — детальний лог (ACTIVE / IDLE / GATED).

Жорстка вимога (requireActivityWatch)

Якщо devManager.team.requireActivityWatch = true (за замовчуванням), хвилини не рахуються, доки REST API ActivityWatch недоступний за activityWatchUrl. У статус-барі — червоний індикатор і підказка, що час не записується, доки не запустити ActivityWatch.

Вимкніть requireActivityWatch лише для ролей, яких не потрібно примушувати (наприклад адміни на власних ПК).

Що вважається «активним»

Кожен 60-секундний тик спершу перевіряє опційний Інтервал сну (примусовий IDLE, якщо локальний час потрапляє в idleSleepWindow).

Інакше collector потребує доступного ActivityWatch (див. Жорстка вимога). Далі оцінюються три сигнали:

СигналДжерелоРоль
Ввід AWREST до bucket afk / input«ActivityWatch бачив клавіатуру/мишу в межах вікна тиші».
Простій ОСWindows GetLastInputInfo, macOS HIDIdleTime, Linux xprintidle (якщо встановлено)«Справжній вік останнього вводу» — стійкіше до синтетичного вводу, який обманює лише AW.
Фокус IDEwindow.state.focused + час останнього фокусуПідтверджує AW, коли вікно VS Code недавно мало системний фокус.

«Годинник» активності (lastAwAt) оновлюється лише коли виконується одна з умов trustworthy:

  1. AW і ОС згодні — обидва звітують недавній ввід (найсильніший сигнал).
  2. Лише ОС (Windows / macOS) — API простою каже «недавній ввід» (навіть якщо AW розходиться).
  3. AW + недавній фокус IDE — AW каже «активно» і це вікно VS Code мало OS-фокус у межах вікна тиші (захист від синтетики, коли ви не біля редактора).
  4. Fallback Linux — якщо helper простою недоступний (немає xprintidle), лишається поведінка «лише AW», щоб не ламати Linux без X-утиліт.

Якщо жодна умова не виконується довше за ефективне вікно тиші, хвилина — IDLE. Ефективне вікно = мінімум idle_window_minutes з усіх workspace, до яких ви належите (налаштування адміна на сервері). Без membership використовується вбудовані 5 хв до вступу в workspace.

Добу обмежує бекенд (див. API-документацію).

Internal vs external

Для кожного workspace тик internal лише якщо одночасно виконуються умови:

  1. Збіг репоremote активного текстового редактора (owner/repo) відповідає патернам репо workspace (glob, як раніше).
  2. Збіг програми (якщо налаштовано) — allowlist програм порожній (фільтр вимкнено), або хоча б один regex збігається з полем app або title вікна з ActivityWatch (без урахування регістру). Список зберігається на сервері; адміни редагують, усі учасники отримують через /api/team/me.

Інакше — +1 external для цього workspace:

  • Невірний репо → external з реальним owner/repo, якщо відомо.
  • Програма поза allowlist (список непорожній і вікно не підходить під жоден regex) → external з міткою _app:НазваПрограми — бекенд зберігає такі хвилини окремо від зовнішніх репо.

Порожній allowlist програм означає «будь-яка програма підходить» для фільтра за додатком; далі вирішують лише патерни репо.

Примітка: коли ActivityWatch фіксує активність у іншій програмі, класифікація за репо все одно береться з останнього активного редактора в Cursor/VS Code. Якщо в workspace непорожній allowlist, але немає window watcher (bucket), app/title можуть бути недоступні → тик не проходить фільтр програм і йде в external для цього workspace.

Allowlist програм (адмін)

Адміни workspace ведуть список regex на сервері:

  • SnakeFlow Cloud → вкладка Team → панель workspace → редагування allowlist програм (іконка камери) — той самий сценарій, що й команда нижче.
  • SnakeFlow: Team Tracker — Edit App Allowlist — regex через кому; порожній рядок очищає список (знову «усі програми дозволені»).

Сервер перевіряє кожен патерн як JavaScript RegExp (прапор без урахування регістру) і відхиляє невалідний синтаксис. Є обмеження на кількість патернів і довжину рядка (див. реалізацію API).

Порада: regex перевіряються і по назві процесу / app, і по заголовку вікна; за змістом це близько до категоризації ActivityWatch, але правила задає ваша команда для звітів SnakeFlow.

Налаштування

ПараметрТипЗа замовчуваннямОпис
devManager.team.enabledbooleanfalseГоловний перемикач Team Tracker.
devManager.team.idleWindowMinutesnumber5Заявлене вікно тиші (1–15); зміна перезапускає collector. Ефективне вікно з membership = мінімум серверного idle_window_minutes — див. Що вважається активним.
devManager.team.useActivityWatchbooleantrueЗапитувати локальний ActivityWatch для системного вводу.
devManager.team.requireActivityWatchbooleantrueЯкщо true — немає обліку, поки ActivityWatch недоступний.
devManager.team.activityWatchUrlstringhttp://localhost:5600Базовий URL aw-server.
devManager.team.requireTrackingbooleanfalseЯкщо true — попередження, коли трекінг вимкнено і сесію не запущено.
devManager.team.idleSleepWindowstring""Інтервал локального часу HH:MM-HH:MM, у якому трекер примусово IDLE — див. Інтервал сну.

Зміна цих ключів перезапускає collector без перезавантаження вікна.

Інтервал сну

devManager.team.idleSleepWindow (формат HH:MM-HH:MM у локальному часі, за замовчуванням порожньо) — додатковий запобіжник проти хибних спрацьовувань активності вночі. Поки поточний локальний час потрапляє в інтервал, collector примусово IDLE, незалежно від ActivityWatch, OS idle time чи фокусу VS Code.

Коли вмикати:

  • Синтетичний input від програм віддаленого керування або «anti-idle» утиліт (AnyDesk, mouse jiggler, окремі драйвери) вводить ActivityWatch в оману: він пише not-afk, поки ви спите.
  • Запущена довгограюча задача або витік wake lock тримає ОС активною всю ніч.

Інтервал коректно обгортає північ, якщо кінець менший за початок — 23:00-07:00 покриває типову нічну зміну. Порожній рядок вимикає режим.

Працює разом із правилами з розділу Що вважається активним: навіть без інтервалу сну collector віддає перевагу узгодженим сигналам (AW + ОС, лише ОС на Windows/macOS, або AW + недавній фокус VS Code), тож одиничний синтетичний ввід від віддалених утиліт рідко зарахує хвилину.

Команди

КомандаОпис
SnakeFlow: Team Tracker — LoginВхід; може увімкнути трекінг.
SnakeFlow: Team Tracker — LogoutЗупинка та вихід.
SnakeFlow: Team Tracker — StatusКороткий статус у повідомленні.
SnakeFlow: Team Tracker — Show Activity LogOutput-канал з причинами кожної хвилини.
SnakeFlow: Team Tracker — Start/Stop ActivityWatchТе саме, що клік у статус-барі.
SnakeFlow: Team Tracker — Edit App AllowlistАдмін workspace: allowlist regex для вікна ActivityWatch (на сервері).
SnakeFlow: Team Tracker — Create WorkspaceАдмін: новий workspace + invite.
SnakeFlow: Team Tracker — Join WorkspaceВхід за кодом запрошення.
SnakeFlow: Team Tracker — Manage WorkspacesСписок / контекст.
SnakeFlow: Team Tracker — Sync Commits (admin)Синхронізація агрегованих комітів для дашбордів.
SnakeFlow: Team Tracker — Sync Closed Issues (admin)Синхронізація закритих GitHub issues (assignee + UTC-день закриття) для дашбордів.

Синхронізація комітів і закритих issues (адмін)

Адміни workspace з увімкненим Team Tracker і сесією GitHub можуть синхронізувати агреговані дані GitHub у SnakeFlow Cloud (D1). Бекенд не отримує GitHub-токен; розширення питає GitHub Search і надсилає лічильники POST-запитами.

МетрикаЗапит GitHub (на учасника, UTC-день)ТаблицяInternal / external
Комітиauthor:{login} author-date:{YYYY-MM-DD}daily_commitsРепо відповідає repo patterns workspace
Закриті issuesassignee:{login} is:issue is:closed closed:{YYYY-MM-DD}daily_closed_issuesТі самі repo patterns
  • Для закритих issues потрібен assignee — issues без assignee не рахуються.
  • Хто закрив не важить — лише assignee та дата закриття.
  • Синхронізація щогодини під час трекінгу (admin workspace) або вручну командами вище (за замовчуванням 7 UTC-днів).
  • SnakeFlow Cloud → Activity показує колонки internal/external для обох метрик.

Погодинна смуга та часові пояси учасників

У SnakeFlow Cloud → Activity для кожного учасника показується добова смуга на 24 години (0h–23h). На бекенді погодинні бакети зберігаються в UTC (година на момент flush на сервері). Якщо лише так відображати дані, «9 ранку локально» у різних регіонах з’їхали б по різних колонках.

Після кожного успішного POST /api/team/active-minutes розширення надсилає IANA-часовий пояс учасника (з Intl.DateTimeFormat().resolvedOptions().timeZone, наприклад Europe/Kyiv). API зберігає його в рядку workspace_members для цього учасника (останнє значення перемагає).

Дашборд перетворює кожен збережений бакет (UTC-доба, UTC-година) у локальну календарну годину цього учасника перед відмальовуванням смуги. Виходить спільна вісь 0–23 «локальних робочих годин»: якщо один починає о 09:00 у Києві, а інший о 09:00 у Лондоні, обидва потрапляють у ту саму колонку (година 9) — зручно для читання «хто коли був активний».

  • Старі учасники, які ще не робили push клієнтом із полем timezone, у API мають null; інтерфейс для перетворення тимчасово використовує UTC, доки наступний flush не оновить поле.
  • Зміна часового поясу в ОС на машині оновить значення на наступному push; історичні бакети інтерпретуються з останнім збереженим поясом (для огляду активності команди це прийнятно).
  • Добові суми (daily_minutes) лишаються на UTC-календарних добах з сервера; зсув за поясом застосовується лише до погодинної візуалізації.

Окремого налаштування «часовий пояс воркспейсу» для цієї фічі немає — вирівнювання дає поєдиний пояс, який надсилає кожен учасник.

Див. також