Публічний реєстр
Звіт про здоров'я програмного забезпеченнясхема 0.27.0 · метрики 2.3.2 · 2026-07-29 00:14 UTC

Gaurav-Gosain / sip

Serve Bubble Tea apps through the browser - Drinking tea through the browser 🍵

JavaScript · GoMIT★ 25 зірок⑂ 3 форкиз груд. 2025 р.Переглянути на GitHub ↗
ТипІнструмент командного рядкаяк це визначено

Gaurav-Gosain/sip має індекс здоров’я 53 зі 100, що відповідає смузі «Помірний». Найвищий показник — Vitality (81/100), найнижчий — Security (27/100). Останнє оновлення було 2 дні тому. Більшість нещодавньої роботи виконує один учасник.

53
загалом / 100
Помірний

Індекс здоров'я програмного забезпечення

Метрики згруповано у зважені категорії на шкалі 1–100. Загальна оцінка починається як їхнє зважене середнє, відкаліброване за розподілом публічного реєстру, тож діапазони мають перцентильний зміст; коли публічні дані активують Політику юрисдикцій високого ризику, рейтинг коригується й отримує верхню межу 34 («У зоні ризику»).

53
Винятковий93-100Верхній щабель реєстру (≈ топ-5%); відповідає практично всім перевіреним критеріям
Відмінний80-92Сильний за всіма напрямами; незначні прогалини
Добрий65-79Здоровий; прогалини обмежені та керовані
Помірний50-64Прийнятний, але з помітними прогалинами; рекомендовано перевірку
Слабкий35-49Суттєві недоліки в кількох сферах
У зоні ризику20-34Суттєві слабкі місця; впровадження потребує обережності
Критичний1-19Серйозні проблеми (покинутий, єдиний мейнтейнер, без базової гігієни)
ЖиттєздатністьСпільнота тавпровадженняСталість таврядуванняІнженернаякістьБезпекаГотовність доШІ

Профіль оцінок

Кожна вісь — окрема категорія. Форма важить більше, ніж середнє: здоровий об'єкт заповнює всю фігуру, тоді як профіль із піками та провалами означає, що сила в одному вимірі маскує ризик в іншому.

Зважений загальний бал 52 калібровано до 53 за шкалою опублікованого індексу (калібрування реєстру 2026-08-02).

Власність

Gaurav GosainОсобистий обліковий запис
154 підписники120 публічних репозиторіївз вер. 2019 р.DMT

Цей репозиторій належить особистому обліковому запису. Проєкт з єдиним власником несе більший ризик безперервності, ніж підтримуваний організацією.

Пакетні екосистеми

РеєстрПакетВерсіяЗавантажень / місВерсіїОстання публікація
Gogithub.com/Gaurav-Gosain/sipv0.5.0-242 дні тому

Метрики за категоріями

Життєздатність

Чи живий проєкт — чи пишеться код і чи виходять релізи?

81Відмінний · 21% загального індексу
Як обчислюється оцінка
36/36Свіжість push — останній push 2 дн. тому
5.5/36Ритм комітів — 8/52 тижнів із комітами
17.7/18Обсяг комітів — 92 комітів за останній рік
10/10OpenSSF Scorecard: Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Використані вхідні дані
commits_last_year92
human_commit_share1
days_since_last_push2
active_weeks_last_year8
Як обчислюється оцінка
27/27Випускає релізи — опубліковано 9 релізів
36/36Свіжість релізів — останній реліз 7 дн. тому
27/27Ритм релізів — реліз кожні ~26,3 дн.
0/10OpenSSF Scorecard: Signed-Releases — немає даних
Використані вхідні дані
releases_count9
latest_release_tagv0.4.0
releases_from_tagsні
days_since_latest_release7
mean_days_between_releases26,3
Виключено з оцінювання (немає даних або не застосовно): OpenSSF Scorecard: Signed-Releases. Залишкові ваги перенормовано.

Спільнота та впровадження

Чи має проєкт користувачів, завантаження, увагу та влаштовані умови для контриб’юторів?

37Слабкий · 17% загального індексу
Як обчислюється оцінка
22.4/60Зірки — 25 зірок
2.5/25Форки — 3 форків
0/15Спостерігачі — 0 спостерігачів
Використані вхідні дані
forks3
stars25
watchers0
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Як обчислюється оцінка
22.5/22.5README
22.5/22.5Ліцензія — визнана ліцензія (MIT)
0/18Настанови CONTRIBUTING
0/13.5Кодекс поведінки
0/7.2Шаблон issue
0/6.3Шаблон PR
Використані вхідні дані
has_readmeтак
has_licenseтак
readme_badges
has_contributingні
has_issue_templateні
has_code_of_conductні
readme_badge_services
has_pull_request_templateні

Сталість та врядування

Чи переживе проєкт своїх людей — бас-фактор, реактивність, хто за ним стоїть і як супроводжуються пакети?

58Помірний · 23% загального індексу
Як обчислюється оцінка
9/54Бас-фактор — на 1 контриб’ютор(ів) припадає половина всіх комітів
0.2/22.5Розподіл комітів — головний контриб’ютор — автор 99% комітів
2.7/13.5Широта контриб’юторів — 2 контриб’юторів
6/10OpenSSF Scorecard: Contributors — project has 2 contributing companies or organizations -- score normalized to 6
Використані вхідні дані
bus_factor1
contributors_sampled2
top_contributor_share0,989
Як обчислюється оцінка
0/42Вирішення issue — немає issue або даних
30/30Прийняття PR — злито 2/2 вирішених PR
0/13Newcomer PR acceptance — за 30 дн. не вирішено жодного PR від новачка
0/15OpenSSF Scorecard: Code-Review — Found 0/10 approved changesets -- score normalized to 0
Використані вхідні дані
merged_prs2
open_issues0
closed_issues0
prs_merged_7d
prs_decided_7d
prs_merged_30d
prs_decided_30d
issue_closed_ratio
closed_unmerged_prs0
first_time_authors_30d
first_time_prs_merged_30d
first_time_prs_decided_30d
Виключено з оцінювання (немає даних або не застосовно): Вирішення issue, newcomer_pr_acceptance. Залишкові ваги перенормовано.
Як обчислюється оцінка
10/30Підтримка власника — особистий (користувацький) обліковий запис
0/20Верифікований домен — не застосовно до користувацьких облікових записів
15.7/25Охоплення власника — 154 підписників у Gaurav-Gosain
25/25Послужний список — 120 публічних репозиторіїв, вік облікового запису ~6 р.
Використані вхідні дані
followers154
owner_typeUser
is_verified
owner_loginGaurav-Gosain
public_repos120
account_age_days2 501
Виключено з оцінювання (немає даних або не застосовно): Верифікований домен. Залишкові ваги перенормовано.

Супровід пакетів

100Винятковий
Як обчислюється оцінка
25/25Опубліковано й доступно — 1 пакет(ів) у go
35/35Свіжість публікацій — остання публікація 2 дн. тому
20/20Історія версій — 24 опублікованих версій
20/20Не застарілий — активний, не deprecated і не yanked
Використані вхідні дані
packagesgithub.com/Gaurav-Gosain/sip
ecosystemsgo
any_deprecatedні
min_days_since_publish2

Інженерна якість

Чи наявні базові інженерні практики та документація?

44Слабкий · 19% загального індексу

Інженерні практики

24У зоні ризику
Як обчислюється оцінка
0/24Процеси CI
24/24Наявні тести
0/16Конфігурація лінтера
0/9.6Pre-commit-хуки
0/6.4.editorconfig
0/20OpenSSF Scorecard: CI-Tests — 0 out of 1 merged PRs checked by a CI test -- score normalized to 0
Використані вхідні дані
has_ciні
has_testsтак
has_editorconfigні
has_linter_configні
has_precommit_configні
Як обчислюється оцінка
30/30README
25/25Каталог документації
0/15Сайт документації / домашня сторінка
10/10Опис репозиторію
0/10Теми
10/10Wiki
Використані вхідні дані
topics
has_wikiтак
homepage
has_readmeтак
has_docs_dirтак
has_descriptionтак

Безпека

Чи міцні видимі практики безпеки й ланцюга постачання, без непослабленої пов’язаності з юрисдикціями високого ризику?

27У зоні ризику · 16% загального індексу

Стан безпеки

27У зоні ризику
Як обчислюється оцінка
7.5/7.5Binary-Artifacts — no binaries found in the repo
0/7.5Branch-Protection — branch protection not enabled on development/release branches
0/2.5CI-Tests — 0 out of 1 merged PRs checked by a CI test -- score normalized to 0
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 0/10 approved changesets -- score normalized to 0
1.5/2.5Contributors — project has 2 contributing companies or organizations -- score normalized to 6
0/10Dangerous-Workflow — немає даних
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5Ліцензія — license file detected
7.5/7.5Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
0/5Packaging — немає даних
0/5Pinned-Dependencies — немає даних
0/5SAST — SAST tool is not run on all commits -- score normalized to 0
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — немає даних
0/7.5Token-Permissions — немає даних
0/7.5Vulnerabilities — 32 existing vulnerabilities detected
Використані вхідні дані
sourceopenssf_scorecard
checks_evaluated13
scorecard_versionv5.5.0
checks_inconclusive5
scorecard_aggregate2,7
Виключено з оцінювання (немає даних або не застосовно): dangerous_workflow, packaging, pinned_dependencies, signed_releases, token_permissions. Залишкові ваги перенормовано.

Готовність до ШІ

Наскільки репозиторій оснащений для розробки та супроводу за участі ШІ-агентів? Має свідомо малу вагу (4%): агентний інструментарій — реальний сигнал супроводу, але репозиторій без нього все одно може отримати 100/100.

60Помірний · 4% загального індексу
Як обчислюється оцінка
45/45Інструкції для агентів — AGENTS.md
0/15Машиночитана документація (llms.txt)
40/40Читабельна історія комітів — намір зазначено у 90 з 92 людських комітів (структурований заголовок або пояснювальний текст)
Використані вхідні дані
has_llms_txtні
legible_history_share0,978
agent_instruction_filesAGENTS.md
agent_instruction_max_bytes32 096
Як обчислюється оцінка
12.6/18Розгортання однією командою — go.mod (домовленість інструментарію, без раннера задач)
22/22Автоматизовані тести
0/11Конфігурація лінтера / форматера
0/11Статична перевірка типів
10/10Відтворюване середовище — lockfile
0/10Підтверджена практика роботи з агентами — серед останніх 92 комітів немає створених агентом
0/8Автоматизоване супроводження — автоматичних оновлень залежностей не виявлено
0/10OpenSSF Scorecard: Pinned-Dependencies — немає даних
Використані вхідні дані
has_nixні
has_testsтак
lockfilesgo.sum, package-lock.json
has_dockerfileні
typed_languageні
bootstrap_files
has_devcontainerні
has_linter_configні
typecheck_configs
agent_commit_share0
toolchain_manifestsgo.mod
dependency_bot_commit_share0
Виключено з оцінювання (немає даних або не застосовно): OpenSSF Scorecard: Pinned-Dependencies. Залишкові ваги перенормовано.
Як обчислюється оцінка
0/45Типізований код — JavaScript без конфігурації перевірки типів
53.8/55Керовані розміри файлів — 1/46 файлів вихідного коду понад 60 КБ
Використані вхідні дані
primary_languageJavaScript
largest_source_bytes1 810 323
source_files_sampled46
oversized_source_files1
Як обчислюється оцінка
0/40Схема API (OpenAPI/GraphQL/proto)
0/20Сервер MCP
40/40Придатні до запуску приклади — examples
Використані вхідні дані
example_dirsexamples
has_mcp_signalні
api_schema_files

Ключові факти

25зірок GitHub
2контриб'юторів
92комітів за останні 12 місяців
2днів від останнього пушу
9релізів
1бас-фактор
0відкритих issue
Go, npmпакетних екосистем

Попередження щодо збору даних

  • Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token
  • GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Докладніше

Історія зірок і форків 0 ★ / 3 ⇿
0Зірки
3Форки
1Релізи

Коли додано кожну зірку й форк — зібрано з GitHub і згруповано за днями. Кумулятивне зростання розміщено просто над денними додаваннями, з яких воно складається, тож їх видно одне проти одного: рівномірне органічне накопичення виглядає зовсім інакше, ніж різкий короткочасний сплеск. Там, де цю різницю можна виміряти, її подано як автентичність росту.

12233312025-122025-122026-01
Мажорні 0Мінорні 0Патчі 1
OpenSSF Scorecard 2.7 / 10
2.7сукупно

Незалежна, не прив'язана до інструментів оцінка безпеки від відкритого проєкту OpenSSF Scorecard. Кожна перевірка винагороджує практику безпеки, а не інструмент конкретного постачальника. Перевірки, які Scorecard не зміг визначити, позначено н/д і виключено з оцінки безпеки (вони ніколи не зараховуються як нуль).Scorecard v5.5.0 · 2026-07-29 00:14 UTC

10Binary-Artifactsno binaries found in the repo
0Branch-Protectionbranch protection not enabled on development/release branches
0CI-Tests0 out of 1 merged PRs checked by a CI test -- score normalized to 0
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/10 approved changesets -- score normalized to 0
6Contributorsproject has 2 contributing companies or organizations -- score normalized to 6
н/дDangerous-Workflowno workflows found
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
10Maintained30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
н/дPackagingpackaging workflow not detected
н/дPinned-Dependenciesno dependencies found
0SASTSAST tool is not run on all commits -- score normalized to 0
0Security-Policysecurity policy file not detected
н/дSigned-Releasesno releases found
н/дToken-PermissionsNo tokens found
0Vulnerabilities32 existing vulnerabilities detected
Прямі залежності 10
РеєстрПакетОбмеження версіїМаніфест
Gocharm.land/bubbletea/v2v2.0.0-rc.2go.mod
Gocharm.land/lipgloss/v2v2.0.0-beta.3.0.20251114160003-3248589b24c9go.mod
Gogithub.com/charmbracelet/colorprofilev0.3.3go.mod
Gogithub.com/charmbracelet/fangv0.4.4go.mod
Gogithub.com/charmbracelet/logv0.4.2go.mod
Gogithub.com/charmbracelet/x/xptyv0.1.3go.mod
Gogithub.com/coder/websocketv1.8.14go.mod
Gogithub.com/quic-go/quic-gov0.57.1go.mod
Gogithub.com/quic-go/webtransport-gov0.9.0go.mod
Gogithub.com/spf13/cobrav1.10.1go.mod
Усі залежності не зібрано

Не вдалося зібрати розв'язаний набір залежностей для цього звіту: GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Звіт у форматі JSON машиночитний
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 5599,
      "has_wiki": true,
      "homepage": null,
      "languages": {
        "Go": 150968,
        "CSS": 17579,
        "HTML": 3772,
        "Shell": 4624,
        "JavaScript": 238051
      },
      "pushed_at": "2026-07-26T15:21:37Z",
      "created_at": "2025-12-02T19:09:04Z",
      "owner_type": "User",
      "updated_at": "2026-07-26T15:21:40Z",
      "description": "Serve Bubble Tea apps through the browser - Drinking tea through the browser 🍵",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "MIT",
      "default_branch": "main",
      "license_spdx_raw": "MIT",
      "primary_language": "JavaScript",
      "significant_languages": [
        "JavaScript",
        "Go"
      ]
    },
    "owner": {
      "blog": "me.gaurav.zip",
      "name": "Gaurav Gosain",
      "type": "User",
      "login": "Gaurav-Gosain",
      "company": "DMT",
      "location": "Abu Dhabi, United Arab Emirates",
      "followers": 154,
      "avatar_url": "https://avatars.githubusercontent.com/u/55647468?v=4",
      "created_at": "2019-09-22T06:03:20Z",
      "is_verified": null,
      "public_repos": 120,
      "account_age_days": 2501
    },
    "license": {
      "state": "standard",
      "spdx_id": "MIT",
      "raw_spdx": "MIT",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v0.4.0",
          "kind": "minor",
          "published_at": "2026-07-21T10:45:46Z"
        },
        {
          "tag": "v0.3.0",
          "kind": "minor",
          "published_at": "2026-07-20T10:55:02Z"
        },
        {
          "tag": "v0.2.2",
          "kind": "patch",
          "published_at": "2026-04-05T18:01:05Z"
        },
        {
          "tag": "v0.2.1",
          "kind": "patch",
          "published_at": "2026-04-05T17:52:19Z"
        },
        {
          "tag": "v0.2.0",
          "kind": "minor",
          "published_at": "2026-04-05T16:14:51Z"
        },
        {
          "tag": "v0.1.14",
          "kind": "patch",
          "published_at": "2026-04-05T15:58:49Z"
        },
        {
          "tag": "v0.1.13",
          "kind": "patch",
          "published_at": "2026-04-05T13:57:13Z"
        },
        {
          "tag": "v0.1.12",
          "kind": "patch",
          "published_at": "2026-04-05T13:02:09Z"
        },
        {
          "tag": "v0.1.11",
          "kind": "patch",
          "published_at": "2025-12-23T08:23:42Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "5a2ffb3f56651f9c53cbecaa5ae9758c6ad6087c",
          "body": "The browser fires resize on every layout tick while a window edge is\nbeing dragged, and the bridge forwarded each one as a WindowSizeMsg. A\nrepeated size costs the program a full re-layout and a full recomposite\nfor no visible change; the last size delivered is now remembered and a\nrepeat is dropped\n[…]\nal.js\nsince the webterm split, so a wasm build supplies its own page and drives\nbubbletea_read, bubbletea_write and bubbletea_resize itself. Say so\nrather than pointing at something that is not there.",
          "is_bot": false,
          "headline": "wasm: deduplicate a repeated resize, and say what the bridge actually is",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-26T14:27:27Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "224b30d2d0e76ff689b5bf9d798a6fbf974f6a97",
          "body": "A phone keyboard has no Escape, no Tab, no Ctrl and no arrows, which is\nmost of what a terminal is driven with, and when it opens it covers the\nbottom half of the terminal it was opened for. Neither was handled: the\nold mobile support was six lines that set an inline height from a\nvisualViewport res\n[…]\nPlaywright's touchscreen only taps, and\nasserts the shape of the fix: the strip moved, no event arrived\nnon-cancellable, focus never left xterm's textarea, and flicking past a\nbutton did not press it.",
          "is_bot": false,
          "headline": "client: make the terminal usable on a phone",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-26T14:27:20Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3a27e040fb90ec17168d6a946340beda33be66d4",
          "body": "Re-vendor the webterm standalone bundle built from the converged vtgl and\nwebterm mains, and add vtgl as a selectable backend in the settings panel.\nThe bundle carries the HarfBuzz-WASM Arabic shaper (correct joining,\nlam-alef ligatures, no WebGL2 seam) behind an explicit ?renderer=vtgl, the\nxterm W\n[…]\nand base-less emoji-modifier width fixes. The vtgl backend\nand shaper are chosen with the vtglBackend and vtglShaper query params.\nThis supersedes the older vendored bundles from the feature branches.",
          "is_bot": false,
          "headline": "client: add the vtgl renderer with the HarfBuzz Arabic shaper",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-21T10:38:49Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ae2bd7bc6db778eff629a96608c138011a273706",
          "body": "…ext tick\n\nThe resize applier was a pure trailing-edge throttle: apply queued the\nvalue and a ticker goroutine forwarded it on the next interval, up to a\nfull interval later. Input is written to the PTY unthrottled, on the same\nread loop that hands resizes to the applier, so a resize followed prompt\n[…]\n an\nidle session no longer wakes up every interval.\n\nSurfaced as a flaky clienttests resize assertion that failed about two runs\nin eight; the test was synchronising correctly and was not the problem.",
          "is_bot": false,
          "headline": "fix(server): apply an isolated resize immediately instead of on the n…",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-20T10:52:35Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9fbd2cd4b4b7d0fee53ed6f253568af06505aeb7",
          "body": "The rounding correction for the atlas cell width was a hand edit to the\nvendored xterm addon bundles. Moving the client onto the webterm package\ndeleted those files, and the correction went with them without any test\nnoticing until now: the HiDPI guard in clienttests/metrics.spec.mjs has\nbeen failin\n[…]\n have.\n\nwebterm now owns the correction, so this bundle carries it and future\nbundle bumps keep it. Nothing under static/ is patched after vendoring\nany more, and AGENTS.md no longer claims otherwise.",
          "is_bot": false,
          "headline": "fix(client): restore the rounded device cell width",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-20T10:40:29Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0117ec9db12cced9d9c01e355a1b5fb3745b30b0",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'docs/readme-banner-and-hero'",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-19T16:53:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d44a2895065255e5556261320eed25b6b8fe3903",
          "body": "The batching writer combined each frame into one reused scratch buffer\nand handed xterm a subarray of it. Terminal.write neither copies nor\nparses before returning; it queues the reference and drains it across\nlater tasks under a time budget. A frame that had not been parsed yet\nwas therefore overwr\n[…]\ntainer, so those pixels were never occupied and the terminal theme\nbackground showed through as a strip down the right edge. Expect the\ngrid to gain roughly 14px worth of columns and a resize on load.",
          "is_bot": false,
          "headline": "client: resync the bundle for the buffer-reuse and layout fixes",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-19T14:21:02Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5d79a114e352fbce017a457ae3a9451af975202b",
          "body": "yazi transmits images in kitty unicode placeholder mode and writes a grid\nof U+10EEEE cells to reserve the area. The bundled client had no\nplaceholder support at all: U=1 was read only as \"do not move the\ncursor\", so the image was anchored at the cursor rather than at the\ngrid, and its rectangle was\n[…]\nand a\ngrid whose image is missing or still in flight shows blank cells rather\nthan a field of tofu.\n\nMeasured on a captured yazi session: 1732 pixels of the placeholder\ncolour visible before, 0 after.",
          "is_bot": false,
          "headline": "client: resync the vendored bundle for unicode placeholder support",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-19T13:34:22Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d3eea72514958e27b383e26ec663108c214a119f",
          "body": "…rding\n\nBrings in the shared banner generator at scripts/banner, the same copy tuitest\nholds, and adds configs/sip.json alongside the existing family.\n\nsip is three letters with no morpheme boundary, so the family's two-tone\nwordmark has nothing to split on and every cut through it reads as a highli\n[…]\nting the other configs from this copy of the generator reproduces\ntuitest's committed banner and social preview byte for byte, so the cursor\noption changes nothing for the projects that do not set it.",
          "is_bot": false,
          "headline": "docs: give the README a banner, a social preview and a real hero reco…",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-19T13:16:05Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d792d931a6a3b8fdc95ab382f3adb3262b978838",
          "body": "Restore the xterm.js client and fix input, rendering, graphics and clipboard",
          "is_bot": false,
          "headline": "Merge pull request #2 from Gaurav-Gosain/fix/clipboard-copy",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-19T12:17:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8c3daee3d231df1103a7bc9dfa421a0e45d097f8",
          "body": "Picks up the overlay change that maps a client's image number to an id of\nits own, so images addressed by `I` no longer all land on id 0 and\noverwrite each other. The rounded device cell width patch is reapplied.",
          "is_bot": false,
          "headline": "chore(client): resync the webterm bundle for image-number resolution",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-19T11:12:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "03830281a88771bc2691d415c29f269334cadd80",
          "body": "The client assets are go:embed'ed, so a server left running from an\nearlier build keeps serving the previous static/ files. Editing static/\nand rerunning then exercised the old build and reported results that had\nnothing to do with the change, with nothing logged to say so. Three runs\nof the clipboard fix were spent on it.\n\nRebuild per run instead. The cost is a few seconds against results that\ncan be trusted.",
          "is_bot": false,
          "headline": "test(client): stop reusing a running server between browser runs",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-19T11:04:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "460c7c2e1a681c09b99f7bf06169215dae0fdcd8",
          "body": "Ctrl+C on a selection fell through to the key encoder, so it sent an\ninterrupt and copied nothing: webterm owns paste and OSC 52 but binds no\ncopy chord, and terminal.js never claimed the custom key handler slot.\n\nBind it here. The selection decides which meaning Ctrl+C takes: with a\nselection it co\n[…]\nch is what this looked like to begin with.\n\nPaste is deliberately left alone: xterm listens for the browser's native\npaste event, so both paste chords already work, and binding them would\npaste twice.",
          "is_bot": false,
          "headline": "fix(client): copy the selection on Ctrl+C",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-19T11:02:51Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "7501766e0c45382273613cdd2e8ed251458b0924",
          "body": "…cells\n\nRunning kitten icat displayed the image but the terminal reserved no cells\nfor it, so the shell prompt was drawn through it, and the image stayed\npinned to the screen while the text scrolled underneath.\n\nThe cell reservation is fixed in webterm, which now moves the cursor past a\nplacement as\n[…]\ntwo hundred lines of\nscrolling output. After, the prompt lands on row 10 with nine rows\nreserved and no text over the image, and the placement tracks the viewport\nup into the scrollback and back down.",
          "is_bot": false,
          "headline": "fix(client): anchor kitty images to the buffer row and reserve their …",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-19T08:17:01Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c0f0f0e9922ba8b461706e217694253773ac1bd6",
          "body": "The reusable half of the client moved out to the webterm package and comes\nback as one vendored standalone bundle: xterm.js and its addons, the kitty\ngraphics overlay, the layered clipboard, the unicode width overrides, input\nchunking, motion dedup, the context menu policy and Keyboard Lock.\n\nWhat s\n[…]\nth patch is re-applied to the vendored bundle. It is\nan upstream bug in the atlas renderers and webterm cannot carry the fix, since\nit takes the addons as peer dependencies rather than vendoring them.",
          "is_bot": false,
          "headline": "refactor(client): consume the webterm package",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-19T07:29:24Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2912d9908fca20debbe8390e8cd53bf9e97b36d8",
          "body": "Two rendering defects reported against the restored xterm.js client.\n\nNerd Font glyphs lost their right edge on HiDPI displays. Both atlas\nrenderers computed device.char.width as Math.floor(advance * dpr), and\nthe atlas rasterises every glyph into a box of exactly that width. At\ndpr 2 the 14px advan\n[…]\n39/45 and\ngrapheme-check.sh from 39/47 to 41/47 aligned rows. The six remaining\ndivergences are all a lone zero-width or defective character at column\n0, where there is no preceding cell to join onto.",
          "is_bot": false,
          "headline": "fix(client): round the device cell width and zero U+200B",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-19T06:59:40Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b6ddeb71d3be7b8bd7acfca28d82150098eb010f",
          "body": "Kitty graphics is a request/response protocol. kitten icat opens with\nthree a=q probes, one per transfer medium, then a primary device\nattributes request as a sentinel; if DA1 comes back with no graphics\nreply it reports that the terminal has no graphics support and never\nsends the image. The overla\n[…]\na browser cannot read,\nso those are reported unsupported and icat settles on stream mode, the\ndirect base64 form the overlay decodes. Quiet mode is honoured: q=1\ndrops successes, q=2 drops everything.",
          "is_bot": false,
          "headline": "fix(client): answer kitty graphics capability queries",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-19T06:39:16Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2bd93bacc88199b4ef6cedf85e3c7f9d3241f99a",
          "body": "The generator padded a four digit escape to seven hex digits, so printf\nread eight and swallowed the following character into it. Rows with a\nshort escape followed by a hex-like character rendered something else\nentirely: the zero width space case printed a CJK ideograph. Emitting the\ncharacters directly removes the escape parsing.",
          "is_bot": false,
          "headline": "fix(scripts): emit literal characters in the grapheme check",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-19T06:18:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2ce0e9d9aa0ba83b248be100a12addfaad6669ea",
          "body": "…fullscreen\n\nRight click over the terminal now reaches the program instead of raising\nthe browser menu, which hid whatever the program wanted to do with the\nbutton. Holding shift always yields the browser menu, matching how the\nsame modifier bypasses mouse reporting for selection.\n\nCtrl+W and its ne\n[…]\n leaving. Both are\nsettings.\n\nAdds scripts/grapheme-check.sh, which prints the 45-case corpus padded to\nthe widths measured from ghostty-vt, so a width disagreement shows up as\na marker out of column.",
          "is_bot": false,
          "headline": "feat(client): suppress the context menu and capture reserved keys in …",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-19T06:09:51Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6263c0e5bb5d474d27252a6f41291f3e62a074d5",
          "body": "…eir sources\n\nThe corpus grows from 24 clusters to 45 and gains the categories it was\nmissing, chiefly zero-width characters, along with conjoining Hangul jamo, an\nSMP ideograph, a second keycap form, Thai and Hebrew marks, and box and block\nglyphs.\n\nThe new expectations are measured rather than ass\n[…]\ner that\ndrifts fails instead of redefining correct. Seams are sampled between rows and\nbetween columns, over blocks and over box-drawing rules, and a block-heavy\nfixture is written out for eyeballing.",
          "is_bot": false,
          "headline": "test(client): measure the grapheme corpus and cell metrics against th…",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-19T05:39:21Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "bcedd6c083aa48409306b488954d425562f7933d",
          "body": "Deletes the suites whose subject no longer exists: viewport_reads, vtgl_source,\nvtgl_renderer and geometry drove ghostty-web and vtgl internals, and chord_leak\npinned a bug in a key handler that has been removed. clipboard.test.mjs tested\nthe deleted OSC 52 scanner module; the OSC 52 path is now cov\n[…]\ntored overlay, selection and\nUTF-8 OSC 52 work, OSC 52 read queries are refused, and a column through four\nstacked block rows contains no background pixel, which is the seam that\nmotivated the revert.",
          "is_bot": false,
          "headline": "test(client): retarget the browser suites at the xterm.js client",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-19T05:25:47Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "124c01a10552511cd7ef932bf4c317dba267af16",
          "body": "Selecting WebTransport explicitly left the page dead when the handshake\nfailed: connect() returned after setting a 'WebTransport failed' status and\nnever tried the socket. Chromium refuses QUIC to a loopback origin with a\nself-signed cert hash where Firefox accepts it, so the same preference is\nhonoured on one machine and unreachable on the next.\n\nFall back in both cases and name the transport that actually carried the\nsession in the status line, so the fallback is visible rather than silent.",
          "is_bot": false,
          "headline": "fix(client): fall back to WebSocket when a forced WebTransport fails",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-19T05:25:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4ccd3806f893857491421f4b6218b1bb8d595ab9",
          "body": "Rewrites the renderer, grapheme, kitty graphics and browser-coverage sections\naround what the client actually is now, and corrects the --renderer help text,\nwhich still advertised vtgl.\n\nKeeps the hard-won notes that still apply: transport is a test dimension and a\nsuite that silently accepts a fall\n[…]\nge. The kitty transcoder comments were describing a wasm\ndecoder limitation that no longer applies; the overlay decodes PNG through\ncreateImageBitmap, which is why the transcoder stays off by default.",
          "is_bot": false,
          "headline": "docs: describe the xterm.js client instead of the ghostty-web one",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-19T05:17:29Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6a3c33c97b55b05c7b0e92f6507b9aaf25c9d84e",
          "body": "Replaces the ghostty-web module client with the xterm.js one, reconciled\nagainst the server as it stands now rather than as it stood before the\nmigration.\n\nRestored: the FontFace preload before Terminal construction, lineHeight 1.0\nagainst the font's own line box, the webgl/canvas/dom renderer ladde\n[…]\neft alone rather than suppressed.\n\nPaste sanitisation is not ported: xterm normalizes newlines to CR and\nreplaces ESC with a symbol under bracketed paste, so a payload cannot close\nthe bracket itself.",
          "is_bot": false,
          "headline": "feat(client): restore the xterm.js terminal client",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-19T04:58:05Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ec3b44400b2a8f5c6b368e946ad109f2cac1e513",
          "body": "Brings back xterm.js, the fit, webgl, canvas, web-links and image addons,\nxterm.css and the kitty graphics overlay from the last tree that carried\nthem. Adds @xterm/addon-unicode-graphemes 0.4.0 as a vendored UMD build so\nthe bundle's charProperties API gets a UAX 29 provider instead of the\nwcwidth-\n[…]\neV6 default.\n\nDeletes static/ghostty-web, static/sip-client and static/vtgl: the wasm VT,\nits client module graph and the glyph-atlas renderer are all unused once\nrendering and input go back to xterm.",
          "is_bot": false,
          "headline": "chore(client): restore the vendored xterm.js bundle and drop ghostty-web",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-19T04:52:22Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "bb02ad191b4317edb14d5ff20a7628b7fcd3dfbf",
          "body": "A blinking cursor is a permanent animation, so an otherwise idle terminal\nnever stops repainting. Off by default, with a settings toggle that applies\nlive and persists.",
          "is_bot": false,
          "headline": "feat(client): stop blinking the cursor by default and make it a setting",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-19T04:17:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f99fa0b1eadb919c141927f90d8b63c624a3cdf3",
          "body": "Assets are embedded in the binary, so they change on every rebuild while\ntheir URLs stay the same. The previous one year max-age pinned browsers to\na stale client, and an ES module graph is not reliably revalidated by a\nhard reload, so the stale copy survived one. Every asset now carries a\ncontent ETag and no-cache, so an unchanged asset costs a 304 and a changed\none is picked up immediately.",
          "is_bot": false,
          "headline": "fix(server): revalidate static assets instead of caching them for a year",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-19T04:16:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3eed9c4950000c10cb6e8c9407241e7e8ce96642",
          "body": "The suite has now been caught blind to a configuration twice: first it\nwas Chromium-only, then WebSocket-only. The second time a 27/27 green\nchord matrix was cited as proof that a WebTransport input bug could not\nexist. Every one of those 27 cases had run over WebSocket, because\nWebTransport had nev\n[…]\nas\nthe only coverage of that path.\n\nCoverage: 28 cases on chromium/websocket, 28 on firefox/websocket, 28 on\nfirefox/webtransport, and 28 skipped on chromium/webtransport after\nverifying the fallback.",
          "is_bot": false,
          "headline": "test(client): run the chord matrix over both transports",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T16:37:01Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0c391d47036cb9b33e18690004879dd937a74ecf",
          "body": "Two blind spots cost a full debugging session, and neither was a bug in\nthe code being hunted.\n\ngo:embed bakes static/ into the binary, so a running server keeps serving\nthe bundle it was compiled with regardless of the working tree. A\nkeyboard fix was confirmed present in the file on disk while the\n[…]\ning swallowed entirely. SIP_DEBUG_INPUT=1\nlogs every inbound frame's type, length and hex payload for both\ntransports, which separates them at a glance. Off by default, since\nkeystrokes are sensitive.",
          "is_bot": false,
          "headline": "feat(server): surface a stale embedded bundle and log inbound frames",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T16:36:47Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "7424af5588ceb5eedce8aa006e7ad24ae13d5401",
          "body": "The previous fix stopped chords leaking as their bare character, but it\nturned one failure into another for part of the same environment. An IME\ncan deliver a chord with the physical event.code stripped, empty or\n\"Unidentified\", while event.key still names the letter. That hit the\nunmapped-code path\n[…]\nelease leaves the application believing the key is still held.\n\nThe spec now drives every shape an IME can produce and requires the\ncontrol byte to arrive, not merely that the bare character does not.",
          "is_bot": false,
          "headline": "fix(ghostty-web): recover a chord whose code an IME stripped",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T16:36:34Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6cb1895a11f29585ee903766f8ff0692ad01ecec",
          "body": "The memo caches the cell pool, and the pool holds resolved per-cell RGB\nrather than palette indices. A palette or default-colour change therefore\nrestyles every cell without writing to the grid, so the four existing\ninvalidation points never fired and the pool served the old colours until\nthe next w\n[…]\neplace the two per-frame JSON.stringify calls used to compare the\nhovered link range with a field comparison. Constant cost rather than a\nhot one, but a serializer has no business in a per-frame path.",
          "is_bot": false,
          "headline": "fix(ghostty-web): invalidate the viewport memo on palette changes",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T16:10:31Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2366d8bfb13cfc6fd3d957847b8d9f500cc068fa",
          "body": "handleKeyDown had three paths that returned without calling preventDefault:\nthe two IME guards (isComposing, and keyCode 229) and an unmapped\nevent.code. The browser then carried on to its default action, fired\nbeforeinput with inputType insertText, and handleBeforeInput sent the plain\ncharacter. Ct\n[…]\nt.\n\nMeasured in Firefox before the fix: keyCode 229, isComposing and unmapped\ncode all sent 0x6c for Ctrl+L. After: 0x0c or nothing, never 0x6c, and the\nfull chord matrix passes 27/27 on both engines.",
          "is_bot": false,
          "headline": "fix(ghostty-web): stop modifier chords leaking as their bare character",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T16:10:17Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "08bd17c226fbefeff47aa207bbb2b8f0cbea6033",
          "body": "getLine(row) walks the entire viewport and slices one row out of it, and\nthe render loop calls getLine once per damaged row. A frame was therefore\nO(rows^2 * cols) wasm crossings at roughly eight crossings per cell. This\nis invisible at the 80x24 and 120x40 sizes the benchmarks used and\ncrippling at\n[…]\nle's reads and then reading again\nthrough SipVtSource.\n\nMeasured in chromium at 193x56 (10808 cells), per rendered frame while\ntyping: canvas2d 30.0ms to 6.0ms in getViewport, webgl 187.0ms to 11.6ms.",
          "is_bot": false,
          "headline": "perf(ghostty-web): memoize the viewport walk per frame",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T15:24:31Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "267cc21847eacfa1bdb489068a7d72a59820011f",
          "body": "The HTTP listener and the WebTransport listener sit on different ports\n(7681 and 7682 by default), so a page served from http://localhost:7681\nsends that Origin to the WT endpoint whose Host is localhost:7682. The\nsame-origin default compares host including port, so it never matched and\nWebTransport\n[…]\nd.\n\nRejections now log the origin, the request host, the HTTP port and the\nallowlist rather than surfacing only as an opaque upgrade error, and the\nclient warns on fallback instead of logging at info.",
          "is_bot": false,
          "headline": "fix: accept the server's own HTTP origin on the WebTransport check",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T15:24:22Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2c42bd7fab01b4d3d6478d118663e9c1a695228e",
          "body": "Rows rendered visibly cramped, worse under the webgl renderer. Two separate\nmeasurement bugs, both of which guessed rather than asking the font.\n\nThe bundle measured the ink box of \"M\". M has no descender, so the result\ndescribed a capital letter rather than a line of text, and a +2 fudge stood\nin f\n[…]\n at dpr 1: cell height 15 -> 18, both baselines 14, the\ncoercion factor lands at exactly 1.0, and the grid corrects from 53 rows to\n44.\n\nVendored vtgl is rebuilt at bb814de for the shared measurement.",
          "is_bot": false,
          "headline": "fix(client): size the terminal cell from the font's real line box",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T10:10:02Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "cddcedfd05b86866f064ff6017d950c7a53c67de",
          "body": "Reported as \"ctrl+C ctrl+D nothing working\". Reading the key path could not\nsettle it, because what the encoder emits depends on the kitty keyboard flags\nthe VT negotiates at runtime, which only exist in a real page. So this\nasserts the bytes actually framed as MsgInput: 0x01..0x1a for Ctrl+A..Ctrl+\n[…]\nrl+M are excluded: the ghostty encoder disambiguates them from\nTab and Enter by emitting CSI u, and it did so before this branch too, so\nthat is upstream behaviour rather than something sip regressed.",
          "is_bot": false,
          "headline": "test(client): assert the wire bytes for every control chord",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T10:09:50Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8d2fb5eeeda2af5dede4ed61efbe164d9a52555a",
          "body": "vtgl's own tests drive a fake source, so they can only prove the renderer\nhonours the cell widths it is handed. This closes the loop: each of the 24\nclusters is written straight into the ghostty-vt parser and read back through\nSipVtSource, the same VtSource interface vtgl consumes, so the widths and\n[…]\ner than a wide head, which the first version of the\nmeasurement miscounted. Both are corrected upstream.\n\nAlso re-vendors the vtgl bundle so the provenance banner matches the source\nit was built from.",
          "is_bot": false,
          "headline": "test: check the grapheme torture corpus against the real ghostty-vt",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T09:19:08Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "cb32d67e9e81b30237c041cc170ca278f0afc7a2",
          "body": "Records the layering, the three-line bundle hook, which parts of the\nbundle still own what, and the gaps in this mode: no link underlines, no\nselection foreground recoloring, and no kitty virtual placeholder cells.",
          "is_bot": false,
          "headline": "docs: document the optional vtgl renderer and its seam",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T08:36:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ffe459c4bdd5a73922c2c5597aace1abb1e52e8d",
          "body": "Node tests pin the source adapter's coordinate translation and default\ncolor substitution, the two things that fail silently.\n\nPlaywright tests drive a real sip server under the system chromium:\ngolden scenarios (ascii, CJK, ZWJ emoji) land on the WebGL canvas at the\nright display widths, wide cells\n[…]\nk; without that every pixel reads as ink\nand the assertions pass vacuously, which is what the first version did.\nAnd headless GL here is SwiftShader, so draw-call counts are asserted but\nno timing is.",
          "is_bot": false,
          "headline": "test: cover the vtgl renderer path end to end",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T08:35:57Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d6866e85fd52043653bc9d3daba00aa7431f29ab",
          "body": "--renderer webgl, a Renderer config field, a settings-panel select and a\n?renderer= query param, resolved most-specific-first. The default stays\nthe canvas 2D path until the WebGL renderer has had burn-in.\n\nSwitching renderers reloads rather than reconnecting, because the renderer\nis chosen when the terminal is opened. The settings panel reports which\none actually won, since an unavailable WebGL2 falls back silently.",
          "is_bot": false,
          "headline": "feat: expose the renderer choice via flag, config and settings panel",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T08:35:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b089e031982efea4c985b0f2201e641f2800366f",
          "body": "…ebgl\n\nvtgl_source.js adapts the wasm buffer to vtgl's read-only VtSource. Two\ntranslations matter and both fail silently if wrong: the bundle addresses\nscreen rows plus a separate scrollback provider where vtgl addresses rows\nabsolutely, and the wasm buffer reports rgb(0,0,0) to mean \"the terminal\n\n[…]\nion painting lived inside the per-cell background pass this mode\nbypasses.\n\nThe vendored bundle is imported lazily and every failure path falls back\nto the 2D renderer with the terminal fully working.",
          "is_bot": false,
          "headline": "feat(client): drive vtgl from the ghostty-vt buffer behind renderer=w…",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T08:35:45Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5a0197e3d604284e5a0c6be1b751091f4bc00ee5",
          "body": "Three surgical lines, in the same style as the existing __sip* patch\npoints, so that an external renderer can own the text grid while the\nbundle keeps drawing everything else.\n\nWhen renderer.__sipRenderHook is set:\n\n- renderLine() clears its row and returns instead of painting it. Guarding\n  renderL\n[…]\nds underneath them.\n- resize() clears rather than filling the background, keeping the canvas\n  transparent.\n\nWith no hook set the bundle behaves exactly as before, so the default 2D\npath is untouched.",
          "is_bot": false,
          "headline": "feat(ghostty-web): add a render-bypass hook for an external renderer",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T08:35:34Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "476b7c80bbda9527e1c15945722b445b3ca78761",
          "body": "Built artifact from the vtgl package (MIT), following the same\nvendored-bundle pattern as static/ghostty-web: sip has no npm pipeline, so\nthe browser imports the built ESM module directly. The banner on line one\nrecords the upstream version and revision, and the README next to it says\nhow to refresh the copy.\n\nvtgl contains no VT. ghostty-vt.wasm remains the terminal emulator; this\nis only a renderer.",
          "is_bot": false,
          "headline": "chore(vtgl): vendor the vtgl glyph-atlas renderer",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T08:35:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "38a53155a258d39b340c83b259eedc80f741967d",
          "body": "The selection text extractor emitted a space for every cell whose\ncodepoint is 0. That set includes the trailing spacer cell of a\nwide character (CJK, wide emoji, flags, ZWJ families), whose width\nis 0. As a result, selecting and copying wide text inserted a\nspurious space after each wide glyph: 中文 \n[…]\nblank cells (width >= 1) should map to a space; a\nwidth-0 spacer is the tail of the preceding wide cell and carries no\ntext of its own, so skip it. Internal ASCII spaces (codepoint 32)\nare unaffected.",
          "is_bot": false,
          "headline": "fix(ghostty-web): drop spacer cells when copying wide-char selections",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T07:16:25Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "83d7300928175fbc6914585fe5d468ba88c048b0",
          "body": "renderCellText called ctx.fillText for every non-zero-width cell,\nincluding plain blanks (codepoint 0 or 32 with no grapheme). Blank\ncells have no visible glyph — the background pass already paints them —\nso the fillText is pure overhead. Skip it when the cell is a bare space,\nwhich drops the per-fr\n[…]\ny screens (a\nscroll storm of short lines padded to full width fell from ~4800 to\n~1500 fillText calls per frame). Underline and strikethrough on blank\ncells still draw; only the glyph fill is skipped.",
          "is_bot": false,
          "headline": "perf(ghostty-web): skip glyph fill for blank cells",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T07:14:38Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a5be98b718601a64be892e3b3480b298d718df1d",
          "body": "Explain the native selection path (works with no config, including the\nShift+drag bypass and copy-on-select), and the OSC 52 path: tmux needs\nset-clipboard on to emit, insecure origins fall back to a gesture-bound\ncopy while https gets instant writes, and read queries are never answered.",
          "is_bot": false,
          "headline": "docs: document the clipboard paths and their requirements",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T06:19:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "97d4644900e6e07378df7a057b62ab04138f52f1",
          "body": "Server side (package sip): assert the spawned child sees\nTERM=xterm-256color, the terminfo entry that carries the Ms capability\ntmux needs to emit OSC 52, and that an OSC 52 a child writes is forwarded\nthrough the output reader byte-for-byte (the default server wires no gate).\n\nGate: add a large-pay\n[…]\n-test suite that loads clipboard.js and exercises the\nOSC 52 parser: basic decode, multibyte UTF-8, ST terminator, split reads,\nquery-read denial, clear form, disabled mode, non-52 OSC, large payload.",
          "is_bot": false,
          "headline": "test(clipboard): cover the OSC 52 copy chain on both sides",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T06:18:39Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "524d52a435582b4711d55561398a33f5a7057033",
          "body": "When an app holds mouse tracking, Shift+drag bypasses mouse reporting and\nproduces a native browser selection over the VT screen that the terminal's\nown selection manager does not own, so it is not auto-copied. Add a\ncopy-on-select setting (default off) that copies that native selection on\nmouseup via the layered clipboard write, plus a settings-panel checkbox to\ntoggle it. copyText on SipTerminal exposes the scanner's write path.",
          "is_bot": false,
          "headline": "feat(clipboard): add opt-in copy-on-select for native Shift+drag",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T06:16:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "238ff0c1e4314d3a1064be595ef3449c87eeeb40",
          "body": "navigator.clipboard is undefined outside secure contexts (LAN IP, or an\nhttp reverse proxy without TLS), and the OSC 52 handler stopped there:\nit stashed the text in this.pending but never bound a gesture flush and\nhad no execCommand fallback, so the copy failed silently forever.\n\nRoute writes throu\n[…]\n blocks a programmatic write. Also handle the OSC 52 clear form\n(empty data) by writing an empty string, and document that query reads\nare intentionally never answered to avoid clipboard exfiltration.",
          "is_bot": false,
          "headline": "fix(clipboard): fall back to execCommand for OSC 52 on insecure origins",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T06:15:11Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2d4c5f29cef32b8b5a40cf9c38f531861b3a5941",
          "body": "Writes to the client had no deadline, so a stalled-but-alive client\n(stopped reading, socket send buffer full) pinned the output goroutine\nand its connection slot indefinitely — flaky clients could walk the\nserver to its connection cap. Add a configurable WriteTimeout (default\n30s, negative disables) and apply it per write on both the WebSocket\n(per-write timeout context) and WebTransport (SetWriteDeadline) output\npaths, so a stalled write fails and tears the session down.",
          "is_bot": false,
          "headline": "fix(transport): bound output writes with a deadline",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T05:53:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3fa1ab9254a532f4fb8ab257c0c43a9884e114a9",
          "body": "WebTransport never connected and silently fell back to WebSocket:\n\n- server bound the QUIC listener to 127.0.0.1 regardless of Config.Host\n  and advertised a hardcoded loopback wtUrl, so any hostname-based or\n  non-loopback deployment was unreachable. Bind to Config.Host and derive\n  the advertised \n[…]\nhe transport that actually connected via an onTransport\n  callback so a WT->WS fallback updates the status line instead of leaving\n  the pre-connect guess showing, and log the fallback to the console.",
          "is_bot": false,
          "headline": "fix(transport): make WebTransport reachable end to end",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T05:51:07Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e4d63a6a716d20c88ff5052a713d56781797223f",
          "body": "The WebTransport input loop deferred smallBufPool.Put inside the read\nloop, so every inbound message pinned a 256-byte buffer and a defer\nrecord for the connection's lifetime, permanently starving the pool.\nprocessInput consumes the message synchronously, so return the buffer\nright after it runs (and on the ReadFull error path).",
          "is_bot": false,
          "headline": "fix(transport): return pooled WT input buffer per message",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T05:48:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d0a7430093d274324425cfcddd343bf01ff4cce3",
          "body": "…he render loop\n\ndecodeKittyImageToCanvas copied the wasm pixel view straight into a fixed\nwidth*height*4 buffer. An over-long payload threw RangeError and took down\nthe whole rAF render loop; a short one (the symptom the old client padded\naround) is now absorbed by the pre-zeroed destination. Clamp the copy to the\ndestination length.",
          "is_bot": false,
          "headline": "fix(kitty): bound the RGBA copy so a mismatched payload can't crash t…",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T05:44:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1ec79a5014780930afd38e2dd56695e5de0c630e",
          "body": "…ort and drop stale frames\n\nrenderKittyImages drew direct placements at active-screen rows, ignoring\nthe JS viewport scroll, so images stayed pinned while the text under them\nscrolled; offset each placement by the viewport row count and skip any that\nfall outside the viewport. renderPlaceholderCell \n[…]\nheck and the\nper-frame damage signature. The canvas cache was never evicted (unbounded\nleak under image-id churn): prune it against live placements each precompute\npass and clear it on renderer reset.",
          "is_bot": false,
          "headline": "fix(kitty): keep the graphics overlay aligned with the scrolled viewp…",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T05:44:34Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8e5272efde10abe576b8f8c4d84c77eb4c598ed0",
          "body": "The ghostty-web bundle's DECODE_PNG callback is wired to a JS PNG decoder\nand verified end to end: raw APC f=100 sequences (single- and multi-chunk)\nwritten to the wasm VT decode to RGBA and are retrievable via\ngetKittyImagePixels. Forward the raw APC stream to the client by default\nso PNG payloads \n[…]\nressed end to end, instead of inflating them 5-20x\nthrough the server transcoder. Rename DisableKittyTranscoder to\nEnableKittyTranscoder (off by default), keeping the transcoder as an\nopt-in fallback.",
          "is_bot": false,
          "headline": "feat(kitty): decode PNG graphics client-side by default",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T05:43:03Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "db3b696fc46df17ea75abd82f8acfdc8998252b5",
          "body": "…e transcoder\n\nA multi-chunk kitty PNG transfer that never sends its m=0 chunk left the\ntranscoder in the loading state forever, silently swallowing every image\nthat followed. Detect a new command arriving mid-transfer (a chunk carrying\nkeys other than m/q), flush the abandoned bytes, and process the new command\nfresh. Drop the stored m flag on passthrough so a leftover m=1 can't leave\nthe client parser waiting, and cap accumulated chunk bytes.",
          "is_bot": false,
          "headline": "fix(kitty): stop a never-terminating chunked transfer from wedging th…",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T05:42:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a769bec59ec55de313fa8630f61fba6d328bdedd",
          "body": "setKittyFlags had no callers while the VT negotiated kitty flags, so\nenhanced-keyboard apps (nvim, helix, Bubble Tea v2) got legacy bytes. Read\nthe terminal's kitty flags per key event, feed them to the encoder, and skip\nthe legacy printable/special fast paths when flags are active, adding keyup\nREL\n[…]\n(config toggle: altIsMeta) so Alt/Option works as\nmeta for readline navigation, and pass any single BMP key as the utf8 hint\nwithout lowercasing so non-ASCII Option characters are no longer swallowed.",
          "is_bot": false,
          "headline": "feat(ghostty-web): wire kitty keyboard flags and Alt-as-meta default",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T05:26:28Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "67f4a48314659228f5fe595843160ae5be823b28",
          "body": "…ion code\n\nWhile a mouse-tracking app is active, holding Shift now suppresses mouse\nreporting on down/move/up so the native selection can be made and copied out\nof the app, matching the universal terminal convention. Also encode\nbuttonless (mode 1003) hover motion as button 35 instead of 32, which apps\nread as a phantom left-drag.",
          "is_bot": false,
          "headline": "fix(ghostty-web): shift bypass for local selection and buttonless mot…",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T05:21:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b712057db5ae71c2ecdcba1c538feed03d90d2b0",
          "body": "emitPasteData wrapped clipboard text verbatim, so an embedded \\x1b[201~\ncould close bracketed paste and inject the rest as commands, and LF was not\nnormalized to CR on the non-bracketed path. Strip C0 controls (including\nESC) and normalize line endings to CR centrally, covering both the paste and\nbeforeinput paths.",
          "is_bot": false,
          "headline": "fix(ghostty-web): sanitize pasted text before bracketed-paste wrapping",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T05:20:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "62d0eb7175180fc0bfe394cdf57cdea50b4e58d1",
          "body": "…nsert\n\nPlain Ctrl+V was swallowed, so apps never received 0x16 (readline\nliteral-next, vim visual-block), and the guard also matched AltGr+V on\nWindows, making that character untypable. Only intercept Cmd+V (native paste\nevent) and, with an explicit clipboard read, Ctrl+Shift+V and Shift+Insert;\nall guarded on !altKey. Bind Ctrl+Shift+C to copy-if-selection so it no\nlonger leaks to the app.",
          "is_bot": false,
          "headline": "fix(ghostty-web): let apps see Ctrl+V and add Ctrl+Shift+C/V, Shift+I…",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T05:19:48Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b258674563c8e02d321426151a265bd595b8daa3",
          "body": "The unconditional contextmenu preventDefault killed the ghostty-web\nSelectionManager's native right-click copy/paste flow. Let the browser menu\nthrough so right-click copy/paste works.",
          "is_bot": false,
          "headline": "fix(terminal): stop suppressing the context menu",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T05:18:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5c267ba50725d16ff3a7578823105155d2a2cf06",
          "body": "…ession\n\nA single oversized input frame (a large paste) exceeded the server read\nlimit and tore down the connection along with all program state. Split\nclient writes into bounded MsgInput frames with backpressure on both the\nWebSocket and WebTransport adapters, and have the server drop an\nover-MaxPasteBytes message with a warning instead of closing the session.",
          "is_bot": false,
          "headline": "fix: chunk large pastes and drop oversize input without killing the s…",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T05:18:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b1aa6a19444646ab139284158fcbd92f21f748e6",
          "body": "Operate on raw output bytes with a state machine instead of decoding each\nchunk to a string and running atob on the result, which garbled every\nnon-ASCII copy and corrupted sequences split across reads. Only the OSC 52\npayload is buffered and it is capped, so an unrelated OSC (a shell title on\nevery\n[…]\nt) can no longer pin memory. Honor whichever of BEL or ST\nterminates first, ignore read queries instead of feeding '?' to atob, and\nretry a clipboard write that was blocked for want of a user gesture.",
          "is_bot": false,
          "headline": "fix(clipboard): decode OSC 52 as UTF-8 and bound the scanner",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T05:16:32Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e2e0a83714b40d06d88fd34146435ba3fede1d08",
          "body": "The output goroutine blocks in a PTY master Read that ctx cancellation\ncannot interrupt, and closeFunc was gated behind wg.Wait. A client\ndisconnect or child exit therefore deadlocked teardown and orphaned the\nPTY, child process, goroutines, sessions-map entry, and a MaxConnections\nslot.\n\nAdd a per-\n[…]\nCmd.Wait concurrently, and Close returns only once the child is\nreaped.\n\nCovers the disconnect-while-blocked-read, short-lived-command cleanup, and\nconcurrent Wait/Close paths with tests (race-clean).",
          "is_bot": false,
          "headline": "fix: unblock session teardown and single-own the child reap",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T05:11:11Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e06c4b20827a425930b8035f7d33ba0a4220b33c",
          "body": "gatedSession.OutputReader() built a fresh scanner on every call, and the\nhandlers invoke it inside their per-iteration read loop. Any byte-level\nparse state buffered mid-escape was discarded between reads, corrupting\nsequences split at a chunk boundary and letting ModeDeny fail open on an\nOSC 52 write spanning two reads.\n\nCache one scanner per session via sync.Once so its state persists for the\nsession lifetime.",
          "is_bot": false,
          "headline": "fix(osc52gate): persist the scanner across OutputReader calls",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T05:06:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "52425983dd173c646fe8edd63cd799a8d7565517",
          "body": "originPatterns() injected [\"*\"] when no origins were configured, which\ncoder/websocket treats as any-origin, contradicting the documented\nsame-origin default. The WebTransport handshake hardcoded CheckOrigin to\nalways true and /cert-hash served Access-Control-Allow-Origin: *, so any\nweb page could o\n[…]\n add a\ncheckOrigin method mirroring the WS policy for the WT handshake, and drop\nthe wildcard CORS header from /cert-hash. Any-origin now requires an\nexplicit \"*\" entry in AllowOrigins/OriginPatterns.",
          "is_bot": false,
          "headline": "fix: default to same-origin policy on both transports",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T05:05:56Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "1656518021cf36c4cf1d679be7dd9a6f12342671",
          "body": "Snapshot of in-progress migration from vendored xterm.js to the\nghostty-web client, plus new middleware, wasm build, and kitty\ngraphics overlay work. Committed as-is before hardening work.",
          "is_bot": false,
          "headline": "wip: checkpoint ghostty-web client migration",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-07-18T04:59:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "58d8e2bd4106641089c1272f5b1fcdfb2a15da14",
          "body": "Two fixes for kitty overlay:\n\n1. When broadcast drops cause short RGBA data, render only complete\n   rows (floor(bytes / bytesPerRow)) instead of padding with zeros.\n   Padding shifted all subsequent rows creating a distorted image.\n   Now the image shows correctly with potentially fewer rows at the\n   bottom.\n\n2. Clamp canvas dimensions to the terminal viewport. When the window\n   is resized smaller than the image, the canvas no longer overflows\n   past the window boundaries.",
          "is_bot": false,
          "headline": "fix: render complete rows only for short data, clamp images to viewport",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-04-08T16:52:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1b3315716c59374df9ff45778b13e7f8c4e667f7",
          "body": "…t payloads\n\nThe daemon-to-client broadcast channel can drop chunks under high\nthroughput, causing kitty image data to arrive slightly short. The\nImageData constructor requires RGBA data to be exactly width*height*4\nbytes. Pad with zeros (transparent black) instead of crashing with\nInvalidStateError.",
          "is_bot": false,
          "headline": "fix: pad RGBA data to expected length when broadcast drops cause shor…",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-04-08T16:52:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "35b6b9e683b6ffded691a194562e683f188456cb",
          "body": null,
          "is_bot": false,
          "headline": "debug: log kitty overlay actions to console for chafa troubleshooting",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-04-08T16:52:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "09a15158d8caa9df03ca323b9e73728be79cabb6",
          "body": "createImageBitmap is asynchronous, so any a=p place command that arrives\non the parser thread between the transmit's final chunk and the bitmap\npromise resolving was silently dropped because the image id was not yet\nin the storage map. tuios emits a=t and a=p back-to-back in the same\nrender cycle, w\n[…]\nyed by image id, and\ndrain the queue as soon as decodeAndStore resolves. Queue entries are\nde-duplicated by placement id so a burst of refresh-driven places\ncollapses to only the most recent position.",
          "is_bot": false,
          "headline": "fix(kitty-overlay): defer place commands while decode is in-flight",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-04-08T16:52:37Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ecbe8914b57ec707d971f8cfbe194401392ca4d6",
          "body": "Two fixes to the custom kitty overlay.\n\n1. Store placements in viewport-relative cell coordinates instead of\n   absolute buffer rows. The previous model tracked xterm.js scrollback\n   so images moved with history on user scroll, but that is wrong for\n   compositor TUIs like tuios: when the guest app\n[…]\ne-sends\n   bytes), close the old bitmap and re-render every live placement\n   that references that id. Without this the canvases kept displaying\n   the first frame while the storage silently advanced.",
          "is_bot": false,
          "headline": "fix(kitty-overlay): viewport-relative rows and retransmit refresh",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-04-08T16:52:37Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "117a536b7041f89bb2411717cfcb8971bfd55197",
          "body": "xterm-addon-image's kitty graphics implementation renders images inline\ninto the terminal cell buffer at cursor position. Once painted, a\nplacement cannot be moved, source-clipped, or deleted individually (d=i\nwipes the bytes, there is no d=p), which makes it unusable as a backing\nfor a window-manag\n[…]\nBA), f=100 (PNG), and o=z zlib via the\n    DecompressionStream API.\n\nxterm-addon-image stays loaded for sixel support with kittySupport:false\nso the two paths don't collide on the same APC identifier.",
          "is_bot": false,
          "headline": "feat: custom kitty graphics overlay with DOM canvas placements",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-04-08T16:52:37Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9a5e2975e6f65359975be3a63912b12109dea59f",
          "body": "Terminal.registerOscHandler does not exist on the public API. Use\nterm.parser.registerOscHandler(ident, handler), which is the documented\nIParser method for OSC handlers.",
          "is_bot": false,
          "headline": "fix: OSC 52 registration uses term.parser, not term",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-04-08T16:52:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c7690930ef30024853627c4612e229cea09e9b96",
          "body": "xterm.js does not register an OSC 52 handler by default, so applications\nthat emit \\e]52;c;<base64>\\a to write to the system clipboard (tmux, vim,\nbubbletea's tea.SetClipboard, etc.) were silently ignored. Register a\nhandler on the terminal that decodes the payload and calls\nnavigator.clipboard.writeText(), with a document.execCommand fallback for\ninsecure contexts. Read requests (payload = '?') are intentionally not\nhonoured to avoid leaking arbitrary clipboard contents back to the page.",
          "is_bot": false,
          "headline": "feat: register OSC 52 handler for system clipboard",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-04-08T16:52:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0cec3a34f8519f97c7c05e1175e701fb4e8d6d3e",
          "body": "Vendor @xterm/addon-image 0.10.0-beta.196 with kittySupport and\nsixelSupport enabled. Update all xterm.js addons to matching beta\nversions. This enables kitty image protocol rendering in the browser\nfor tuios-web. Will switch to stable 7.0.0 when released.",
          "is_bot": false,
          "headline": "feat: upgrade xterm.js to 6.1.0-beta.196 with kitty graphics support",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2026-04-08T16:52:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "876bd410a3055d6b26e7b3e4d6eca9db1f8f8da1",
          "body": "Updated import paths and improved error handling in the main function for the readme example.",
          "is_bot": false,
          "headline": "chore: Refactor imports and add error handling",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2025-12-30T05:29:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "753e1fd75d450810af6d497dd3c776a1ec4fb640",
          "body": "- Update imports from github.com/charmbracelet/* to charm.land/*\n- Use bubbletea v2.0.0-rc.2\n- Use lipgloss v2.0.0-beta.3\n- Update indirect dependencies to compatible versions",
          "is_bot": false,
          "headline": "feat: migrate to charm.land bubbletea/v2 and lipgloss/v2",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2025-12-23T08:23:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b87c43e3a12452493dc08b730baf16bdddf1dd53",
          "body": null,
          "is_bot": false,
          "headline": "Merge pull request #1 from ShalokShalom/main",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2025-12-04T16:19:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e439927a92ab03f885bb4fc4b71d7bff2fe3059b",
          "body": "Added a demonstration video :)",
          "is_bot": false,
          "headline": "Add demonstration video to README",
          "author_name": "ShalokShalom",
          "author_login": "ShalokShalom",
          "committed_at": "2025-12-03T18:48:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c38de00d5026268e7b3c89185750e36ee19a1902",
          "body": "Concurrent send() calls (input, resize, ping) shared pre-allocated\nbuffers, causing frame corruption when calls overlapped. The server\nwould misinterpret terminal escape bytes as length prefixes, triggering\n\"message too large\" disconnections.\n\nAlways allocate fresh buffers for WebTransport sends to prevent races.",
          "is_bot": false,
          "headline": "fix: race condition in WebTransport message framing",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2025-12-03T15:27:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8dc331c6e2ac4f0da28e4eb15246c7e1215a5f4b",
          "body": null,
          "is_bot": false,
          "headline": "fix: remove sip as a folder from gitignore",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2025-12-03T06:40:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f218a1e1bab2731fe4fb307ff0cf70e091e9334b",
          "body": "- Replace flag package with Cobra + Fang (matches tuios pattern)\n- Add short flags: -H host, -p port, -d dir, -v version\n- Include shell completion support via `sip completion`\n\nFix Ctrl+C not exiting cleanly:\n- Use fresh context with 5s timeout for Shutdown() instead of cancelled ctx\n- Close all active sessions (cmd and web) before server shutdown\n- Suppress expected \"Server closed\" warning from WebTransport",
          "is_bot": false,
          "headline": "refactor: migrate CLI to Cobra + Fang and fix graceful shutdown",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2025-12-03T04:48:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b940b1ec07ea550c59edbe248d873e85bb2968fa",
          "body": null,
          "is_bot": false,
          "headline": "fix: force TrueColor profile and filter TERM/COLORTERM from env",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2025-12-02T21:02:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "80a2fe27f33a4bfe27d710d546620fbebdcca26d",
          "body": null,
          "is_bot": false,
          "headline": "fix: add colorprofile for proper color support",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2025-12-02T21:00:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "704d05e273c32dbac5bef2701aabe2f43d19dc62",
          "body": "The Session wrapper interface was preventing Bubble Tea from setting\nraw mode on the terminal, causing input echo (mouse escape sequences\nappearing as visible text like ^[[<35;94;31M).\n\nBubble Tea needs the actual *os.File to:\n- Call term.IsTerminal(fd) to detect TTY\n- Set raw mode via termios to disable echo\n\nAdded PtySlave() method to Session interface and changed MakeOptions\nto use the real file instead of the wrapper.",
          "is_bot": false,
          "headline": "fix: pass ptySlave directly to Bubble Tea for proper raw mode",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2025-12-02T20:58:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8c21afc1416893f3816ba456c097ee4647c2f867",
          "body": "Bubble Tea needs Fd() to detect if input/output are TTYs and enable\nproper raw mode handling. Without Fd(), escape sequences for mouse\nand keyboard events were being echoed as visible text.\n\n💘 Generated with Crush\n\nAssisted-by: Claude Opus 4.5 via Crush <crush@charm.land>",
          "is_bot": false,
          "headline": "fix: add Fd() method to Session for TTY detection",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2025-12-02T20:53:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "74d6fdfbd2edab238b36c2657fe5999d9b19af64",
          "body": "The charmbracelet/log logger outputs ANSI color codes by default which\ncould potentially leak into the terminal output. Disabled colors to\nensure clean logging.\n\n💘 Generated with Crush\n\nAssisted-by: Claude Opus 4.5 via Crush <crush@charm.land>",
          "is_bot": false,
          "headline": "fix: disable ANSI colors in logger to prevent escape sequence leaking",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2025-12-02T20:48:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d6b01a5f52b742a318dd28e2af2cd790836bfa2e",
          "body": "Updated lipgloss version to match tuios requirements which uses\nlipgloss.Layer for rendering composition.\n\n💘 Generated with Crush\n\nAssisted-by: Claude Opus 4.5 via Crush <crush@charm.land>",
          "is_bot": false,
          "headline": "fix: use lipgloss v2.0.0-beta.3 for Layer type compatibility",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2025-12-02T20:43:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0db10faeee667ab8fc510077116e522bdac5dfed",
          "body": "Changed webtransport.Stream function parameters to pointer type\nto work with webtransport-go v0.9.0 where Read/Write have pointer receivers.\n\n💘 Generated with Crush\n\nAssisted-by: Claude Opus 4.5 via Crush <crush@charm.land>",
          "is_bot": false,
          "headline": "fix: update webtransport to v0.9.0 for Go dependency compatibility",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2025-12-02T20:41:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "60769e14a280db99948cffcbddeafeced0046798",
          "body": "Sip serves Bubble Tea applications through a web browser with full terminal\nemulation, mouse support, and hardware-accelerated rendering via xterm.js.\n\nFeatures:\n- Wish-like Handler API for easy integration\n- WebTransport (HTTP/3) with WebSocket fallback\n- Embedded static assets (HTML, CSS, JS, fonts)\n- JetBrains Mono Nerd Font bundled\n- Session management with isolated PTY per user\n- Pure Go, no CGO dependencies\n\n💘 Generated with Crush\n\nAssisted-by: Claude Opus 4.5 via Crush <crush@charm.land>",
          "is_bot": false,
          "headline": "feat: initial release of sip library (v0.1.0)",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2025-12-02T20:38:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "459f1454ff5ed03dafb158cf692592c111395a94",
          "body": "Documented the vision and roadmap for Sip, a library for serving Bubble Tea\napplications through a web browser.\n\nStatus: Planning phase\nImplementation: Will be extracted from tuios-web in future releases\n\nFeatures planned:\n- WebGL rendering via xterm.js\n- WebTransport/WebSocket dual protocol\n- Embed\n[…]\nusers\n- Pure Go, no CGO dependencies\n\nThe web terminal functionality currently lives in tuios-web and uses\nthe internal/web package. Once the API is stabilized, it will be\nextracted into this library.",
          "is_bot": false,
          "headline": "docs: sip library planning and vision (v0.1.0)",
          "author_name": "Gaurav Gosain",
          "author_login": "Gaurav-Gosain",
          "committed_at": "2025-12-02T19:12:01Z",
          "body_truncated": true,
          "is_coding_agent": false
        }
      ],
      "releases_count": 9,
      "commits_last_year": 92,
      "latest_release_at": "2026-07-21T10:45:46Z",
      "latest_release_tag": "v0.4.0",
      "releases_from_tags": false,
      "days_since_last_push": 2,
      "active_weeks_last_year": 8,
      "days_since_latest_release": 7,
      "mean_days_between_releases": 26.3
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": false,
      "health_percentage": 42,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "github.com/Gaurav-Gosain/sip",
          "exists": true,
          "license": null,
          "keywords": [],
          "ecosystem": "go",
          "matches_repo": true,
          "registry_url": "https://pkg.go.dev/github.com/Gaurav-Gosain/sip",
          "is_deprecated": false,
          "latest_version": "v0.5.0",
          "repository_url": "https://github.com/Gaurav-Gosain/sip",
          "versions_count": 24,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": null,
          "first_published_at": null,
          "latest_published_at": "2026-07-26T14:27:27Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 2
        }
      ]
    },
    "popularity": {
      "forks": 3,
      "stars": 25,
      "watchers": 0,
      "fork_history": {
        "days": [
          {
            "date": "2025-12-03",
            "count": 1
          },
          {
            "date": "2025-12-06",
            "count": 1
          },
          {
            "date": "2026-01-25",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 3,
        "total_forks": 3
      },
      "star_history": null,
      "open_issues_and_prs": 0
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [
        "examples"
      ],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": false,
      "bootstrap_files": [],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [
        "go.mod"
      ],
      "largest_source_bytes": 1810323,
      "source_files_sampled": 46,
      "oversized_source_files": 1,
      "agent_instruction_files": [
        "AGENTS.md"
      ],
      "agent_instruction_max_bytes": 32096
    },
    "dependencies": {
      "manifests": [
        "clienttests/package.json",
        "go.mod"
      ],
      "advisories": {
        "error": null,
        "scope": null,
        "source": null,
        "findings": [],
        "collected": false,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 0,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "go",
        "npm"
      ],
      "dependencies": [
        {
          "name": "charm.land/bubbletea/v2",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v2.0.0-rc.2"
        },
        {
          "name": "charm.land/lipgloss/v2",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v2.0.0-beta.3.0.20251114160003-3248589b24c9"
        },
        {
          "name": "github.com/charmbracelet/colorprofile",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.3.3"
        },
        {
          "name": "github.com/charmbracelet/fang",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.4.4"
        },
        {
          "name": "github.com/charmbracelet/log",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.4.2"
        },
        {
          "name": "github.com/charmbracelet/x/xpty",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.1.3"
        },
        {
          "name": "github.com/coder/websocket",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.8.14"
        },
        {
          "name": "github.com/quic-go/quic-go",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.57.1"
        },
        {
          "name": "github.com/quic-go/webtransport-go",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.9.0"
        },
        {
          "name": "github.com/spf13/cobra",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.10.1"
        }
      ],
      "all_dependencies": {
        "error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
        "source": null,
        "packages": [],
        "collected": false,
        "truncated": false,
        "total_count": null,
        "direct_count": null,
        "indirect_count": null
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 2,
        "open_issues": 0,
        "closed_ratio": null,
        "closed_issues": 0,
        "closed_unmerged_prs": 0
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "Gaurav-Gosain",
          "commits": 91,
          "avatar_url": "https://avatars.githubusercontent.com/u/55647468?v=4"
        },
        {
          "type": "User",
          "login": "ShalokShalom",
          "commits": 1,
          "avatar_url": "https://avatars.githubusercontent.com/u/6344099?v=4"
        }
      ],
      "contributors_sampled": 2,
      "top_contributor_share": 0.989
    },
    "quality_signals": {
      "has_ci": false,
      "has_tests": true,
      "ci_workflows": [],
      "has_docs_dir": true,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": false,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [
        "go.sum",
        "package-lock.json"
      ],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 10,
            "reason": "no binaries found in the repo",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 0,
            "reason": "branch protection not enabled on development/release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 0,
            "reason": "0 out of 1 merged PRs checked by a CI test -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
          },
          {
            "name": "CII-Best-Practices",
            "score": 0,
            "reason": "no effort to earn an OpenSSF best practices badge detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
          },
          {
            "name": "Code-Review",
            "score": 0,
            "reason": "Found 0/10 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 6,
            "reason": "project has 2 contributing companies or organizations -- score normalized to 6",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": null,
            "reason": "no workflows found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 0,
            "reason": "no update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 10,
            "reason": "license file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 10,
            "reason": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": null,
            "reason": "packaging workflow not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": null,
            "reason": "no dependencies found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "SAST tool is not run on all commits -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 0,
            "reason": "security policy file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": null,
            "reason": "no releases found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": null,
            "reason": "No tokens found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 0,
            "reason": "32 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "5a2ffb3f56651f9c53cbecaa5ae9758c6ad6087c",
        "ran_at": "2026-07-29T00:14:36Z",
        "aggregate_score": 2.7,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-07-26T15:21:30Z",
      "oldest_open_prs": [],
      "last_merged_pr_at": "2026-07-19T12:17:23Z",
      "ci_last_conclusion": null,
      "oldest_open_issues": []
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/Gaurav-Gosain/sip",
    "host": "github.com",
    "name": "sip",
    "owner": "Gaurav-Gosain"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": "The weighted overall 52 is calibrated to 53 on the published index scale (record calibration 2026-08-02).",
      "notes": [
        {
          "code": "overall_calibration",
          "params": {
            "raw": 52,
            "calibrated": 53,
            "calibration": "2026-08-02"
          }
        }
      ],
      "value": 53,
      "inputs": {
        "security": 27,
        "vitality": 81,
        "community": 37,
        "governance": 58,
        "calibration": "2026-08-02",
        "engineering": 44,
        "ai_readiness": 60,
        "weighted_overall_raw": 52
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "excellent",
        "name": "Vitality",
        "value": 81,
        "weight": 0.21,
        "metrics": [
          {
            "key": "development_activity",
            "band": "good",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 69,
            "inputs": {
              "commits_last_year": 92,
              "human_commit_share": 1,
              "days_since_last_push": 2,
              "active_weeks_last_year": 8
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 2 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 2
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "8/52 weeks with commits",
                "points": 5.5,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 8
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "92 commits in the last year",
                "points": 17.7,
                "status": "partial",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 92
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "exceptional",
            "name": "Release discipline",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "releases_count": 9,
              "latest_release_tag": "v0.4.0",
              "releases_from_tags": false,
              "days_since_latest_release": 7,
              "mean_days_between_releases": 26.3
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "9 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 9
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 7 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 7
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~26.3 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 26.3
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "exceptional",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "maintained",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": null,
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": 9,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "last human commit 9 days ago",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_maintained",
                    "params": {
                      "days": 9
                    }
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "weak",
        "name": "Community & Adoption",
        "value": 37,
        "weight": 0.17,
        "metrics": [
          {
            "key": "popularity",
            "band": "at_risk",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 25,
            "inputs": {
              "forks": 3,
              "stars": 25,
              "watchers": 0,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "25 stars",
                "points": 22.4,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 25
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "3 forks",
                "points": 2.5,
                "status": "partial",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 3
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "0 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "moderate",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "readme_badges": null,
              "has_contributing": false,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "readme_badge_services": [],
              "has_pull_request_template": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "recognized license (MIT)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "MIT"
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "code_of_conduct",
                "name": "Code of conduct",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 13.5
              },
              {
                "key": "issue_template",
                "name": "Issue template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.2
              },
              {
                "key": "pr_template",
                "name": "PR template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.3
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "moderate",
        "name": "Sustainability & Governance",
        "value": 58,
        "weight": 0.23,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 18,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 2,
              "top_contributor_share": 0.989
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "1 contributor(s) cover half of all commits",
                "points": 9,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 99% of commits",
                "points": 0.2,
                "status": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 99
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "2 contributors",
                "points": 2.7,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 2 contributing companies or organizations -- score normalized to 6",
                "points": 6,
                "status": "partial",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "good",
            "name": "Issue & PR responsiveness",
            "note": "Excluded from scoring (no data or not applicable): Issue resolution, Newcomer PR acceptance. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "issue_resolution",
                    "newcomer_pr_acceptance"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 67,
            "inputs": {
              "merged_prs": 2,
              "open_issues": 0,
              "closed_issues": 0,
              "prs_merged_7d": null,
              "prs_decided_7d": null,
              "prs_merged_30d": null,
              "prs_decided_30d": null,
              "issue_closed_ratio": null,
              "closed_unmerged_prs": 0,
              "first_time_authors_30d": null,
              "first_time_prs_merged_30d": null,
              "first_time_prs_decided_30d": null
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "no issues or no data",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_issues_or_data",
                    "params": {}
                  }
                ],
                "max_points": 42
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "2/2 decided PRs merged",
                "points": 30,
                "status": "met",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 2,
                      "decided": 2
                    }
                  }
                ],
                "max_points": 30
              },
              {
                "key": "newcomer_pr_acceptance",
                "name": "Newcomer PR acceptance",
                "detail": "no first-time contributor's PR decided in 30d",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_newcomer_prs",
                    "params": {
                      "days": 30
                    }
                  }
                ],
                "max_points": 13
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/10 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "moderate",
            "name": "Ownership & stewardship",
            "note": "Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "verified_domain"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 63,
            "inputs": {
              "followers": 154,
              "owner_type": "User",
              "is_verified": null,
              "owner_login": "Gaurav-Gosain",
              "public_repos": 120,
              "account_age_days": 2501
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "personal (user) account",
                "points": 10,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_personal",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": "not applicable to user accounts",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_applicable_to_user_accounts",
                    "params": {}
                  }
                ],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "154 followers of Gaurav-Gosain",
                "points": 15.7,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 154,
                      "login": "Gaurav-Gosain"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "120 public repos, account ~6 yr old",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 120
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 6
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "exceptional",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "github.com/Gaurav-Gosain/sip"
              ],
              "ecosystems": "go",
              "any_deprecated": false,
              "min_days_since_publish": 2
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "1 package(s) on go",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 1,
                      "ecosystems": "go"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 2 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 2
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "24 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 24
                    }
                  }
                ],
                "max_points": 20
              },
              {
                "key": "not_deprecated",
                "name": "Not deprecated",
                "detail": "active, not deprecated or yanked",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "package_not_deprecated",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "weak",
        "name": "Engineering Quality",
        "value": 44,
        "weight": 0.19,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "at_risk",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 24,
            "inputs": {
              "has_ci": false,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 24,
                "status": "met",
                "details": [],
                "max_points": 24
              },
              {
                "key": "linter_config",
                "name": "Linter config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 9.6
              },
              {
                "key": "editorconfig",
                "name": ".editorconfig",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "0 out of 1 merged PRs checked by a CI test -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "good",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 75,
            "inputs": {
              "topics": [],
              "has_wiki": true,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": true,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 25,
                "status": "met",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "at_risk",
        "name": "Security",
        "value": 27,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "at_risk",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): Dangerous-Workflow, Packaging, Pinned-Dependencies, Signed-Releases, Token-Permissions. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "dangerous_workflow",
                    "packaging",
                    "pinned_dependencies",
                    "signed_releases",
                    "token_permissions"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 27,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 13,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 5,
              "scorecard_aggregate": 2.7
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection not enabled on development/release branches",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "0 out of 1 merged PRs checked by a CI test -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "cii_best_practices",
                "name": "CII-Best-Practices",
                "detail": "no effort to earn an OpenSSF best practices badge detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "code_review",
                "name": "Code-Review",
                "detail": "Found 0/10 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 2 contributing companies or organizations -- score normalized to 6",
                "points": 1.5,
                "status": "partial",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no workflows found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "no update tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file detected",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow not detected",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "no dependencies found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "SAST tool is not run on all commits -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "No tokens found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "32 existing vulnerabilities detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "exceptional",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "commit_weight_rule": {
                "min_commits": 50,
                "min_commit_share": 0.1
              },
              "review_only_matches": 0,
              "below_threshold_exposures": [],
              "assessed_self_published_locations": 4
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "moderate",
        "name": "AI Readiness",
        "value": 60,
        "weight": 0.04,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "excellent",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 85,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 0.978,
              "agent_instruction_files": [
                "AGENTS.md"
              ],
              "agent_instruction_max_bytes": 32096
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "AGENTS.md",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "AGENTS.md"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "90 of 92 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 90,
                      "sampled": 92
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "moderate",
            "name": "Verify loop (build / test / typecheck)",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Pinned-Dependencies. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_pinned_dependencies"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 50,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "go.sum",
                "package-lock.json"
              ],
              "has_dockerfile": false,
              "typed_language": false,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [],
              "agent_commit_share": 0,
              "toolchain_manifests": [
                "go.mod"
              ],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": "go.mod (toolchain convention, no task runner)",
                "points": 12.6,
                "status": "partial",
                "details": [
                  {
                    "code": "toolchain_convention",
                    "params": {
                      "files": "go.mod"
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": "lockfile",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "lockfile"
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "no agent-authored commits among the last 92",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_authored_commits",
                    "params": {
                      "sampled": 92
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "no automated dependency updates observed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_dependency_automation",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "no dependencies found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "moderate",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 54,
            "inputs": {
              "primary_language": "JavaScript",
              "largest_source_bytes": 1810323,
              "source_files_sampled": 46,
              "oversized_source_files": 1
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "JavaScript without a type-check config",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_typecheck_config_language",
                    "params": {
                      "language": "JavaScript"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "1/46 source files over 60KB",
                "points": 53.8,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 46,
                      "oversized": 1
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          },
          {
            "key": "ai_interfaces",
            "band": "weak",
            "name": "Machine-readable interfaces",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "example_dirs": [
                "examples"
              ],
              "has_mcp_signal": false,
              "api_schema_files": []
            },
            "components": [
              {
                "key": "api_schema_openapi_graphql_proto",
                "name": "API schema (OpenAPI/GraphQL/proto)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 40
              },
              {
                "key": "mcp_server",
                "name": "MCP server",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              },
              {
                "key": "runnable_examples",
                "name": "Runnable examples",
                "detail": "examples",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "examples"
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? Carries a deliberately small weight: agent tooling is a real maintenance signal, but its absence must never gate the top of the scale (calibration saturates at raw 91, so 100/100 remains reachable with AI Readiness at zero)."
      }
    ],
    "classification": {
      "labels": [
        "cli"
      ],
      "scores": {
        "cli": 4,
        "library": 3
      },
      "primary": "cli",
      "evidence": [
        {
          "tier": "dependencies",
          "label": "cli",
          "source": "dep:github.com/spf13/cobra",
          "weight": 4
        },
        {
          "tier": "distribution",
          "label": "library",
          "source": "registry:go",
          "weight": 3
        }
      ],
      "artifacts": [],
      "confidence": "low",
      "host_extension": false,
      "runs_as_process": true,
      "consumed_by_code": false
    },
    "metrics_version": "2.3.2"
  },
  "warnings": [
    "Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-29T00:14:48.771679Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/g/Gaurav-Gosain/sip.svg",
  "full_name": "Gaurav-Gosain/sip",
  "license_state": "standard",
  "license_spdx": "MIT"
}

Оцінки — це сигнали, а не гарантії. Вони відображають публічно видимі практики на GitHub — це не аудит коду й не гарантія безпеки.

Відсутні дані виключаються, а ваги перенормовуються — нуль за відсутність ніколи не ставиться. Методологія версіонована й відкрита: метрики v2.3.2, схема v0.27.0 — повна методологія · вікі метрик.

Як окремий результат виглядає на тлі всього реєстру: сукупна статистикаGo.