JSON-Rohbericht maschinenlesbar
{
"data": {
"repo": {
"topics": [
"lightweight",
"performance",
"typescript",
"virtual-list",
"virtual-scroll",
"virtualization",
"zero-dependencies"
],
"is_fork": false,
"size_kb": 3906,
"has_wiki": true,
"homepage": "https://vlist.io",
"languages": {
"CSS": 56059,
"JavaScript": 56,
"TypeScript": 3091655
},
"pushed_at": "2026-07-15T05:45:55Z",
"created_at": "2026-02-01T18:09:39Z",
"owner_type": "User",
"updated_at": "2026-07-23T03:37:11Z",
"description": "Accessible, batteries-included ultra efficient virtual list for every framework. Zero deps, 9.7 KB",
"is_archived": false,
"is_disabled": false,
"license_spdx": "MIT",
"default_branch": "main",
"license_spdx_raw": "MIT",
"primary_language": "TypeScript",
"significant_languages": [
"TypeScript"
]
},
"owner": {
"blog": "https://floor.io",
"name": "Floor",
"type": "User",
"login": "floor",
"company": "Floor IO",
"location": "Switzerland",
"followers": 53,
"avatar_url": "https://avatars.githubusercontent.com/u/187733?v=4",
"created_at": "2010-01-22T15:09:44Z",
"is_verified": null,
"public_repos": 30,
"account_age_days": 6027
},
"license": {
"state": "standard",
"spdx_id": "MIT",
"raw_spdx": "MIT",
"file_present": true,
"scorecard_found": true,
"profile_has_license": true
},
"activity": {
"releases": [
{
"tag": "v2.6.1",
"kind": "patch",
"published_at": "2026-07-15T05:46:50Z"
},
{
"tag": "v2.6.0",
"kind": "minor",
"published_at": "2026-07-08T02:55:03Z"
},
{
"tag": "v2.5.1",
"kind": "patch",
"published_at": "2026-06-13T10:48:29Z"
},
{
"tag": "v2.5.0",
"kind": "minor",
"published_at": "2026-06-09T09:41:57Z"
},
{
"tag": "v2.4.2",
"kind": "patch",
"published_at": "2026-06-09T06:02:35Z"
},
{
"tag": "v2.4.1",
"kind": "patch",
"published_at": "2026-06-07T19:52:14Z"
},
{
"tag": "v2.4.0",
"kind": "minor",
"published_at": "2026-06-07T18:29:39Z"
},
{
"tag": "v2.3.0",
"kind": "minor",
"published_at": "2026-06-05T14:40:26Z"
},
{
"tag": "v2.2.0",
"kind": "minor",
"published_at": "2026-06-02T11:04:02Z"
},
{
"tag": "v2.1.2",
"kind": "patch",
"published_at": "2026-06-01T23:28:56Z"
},
{
"tag": "v2.1.1",
"kind": "patch",
"published_at": "2026-06-01T14:08:32Z"
},
{
"tag": "v2.1.0",
"kind": "minor",
"published_at": "2026-05-30T11:15:13Z"
},
{
"tag": "v2.0.5",
"kind": "patch",
"published_at": "2026-05-29T16:31:01Z"
},
{
"tag": "v2.0.4",
"kind": "patch",
"published_at": "2026-05-28T15:30:37Z"
},
{
"tag": "v2.0.3",
"kind": "patch",
"published_at": "2026-05-28T09:27:58Z"
},
{
"tag": "v2.0.2",
"kind": "patch",
"published_at": "2026-05-28T07:48:58Z"
},
{
"tag": "v2.0.1",
"kind": "patch",
"published_at": "2026-05-27T10:06:58Z"
},
{
"tag": "v2.0.0",
"kind": "major",
"published_at": "2026-05-27T09:41:57Z"
},
{
"tag": "v1.9.1",
"kind": "patch",
"published_at": "2026-05-21T11:14:17Z"
},
{
"tag": "v1.9.0",
"kind": "minor",
"published_at": "2026-05-17T19:13:11Z"
},
{
"tag": "v1.8.3",
"kind": "patch",
"published_at": "2026-05-13T22:48:48Z"
},
{
"tag": "v1.8.2",
"kind": "patch",
"published_at": "2026-05-13T12:34:14Z"
},
{
"tag": "v1.8.1",
"kind": "patch",
"published_at": "2026-05-13T09:33:37Z"
},
{
"tag": "v1.8.0",
"kind": "minor",
"published_at": "2026-05-13T06:30:00Z"
},
{
"tag": "v1.7.9",
"kind": "patch",
"published_at": "2026-05-13T06:02:50Z"
},
{
"tag": "v1.7.8",
"kind": "patch",
"published_at": "2026-05-12T20:16:50Z"
},
{
"tag": "v1.7.7",
"kind": "patch",
"published_at": "2026-05-11T08:21:15Z"
},
{
"tag": "v1.7.6",
"kind": "patch",
"published_at": "2026-05-10T14:44:29Z"
},
{
"tag": "v1.7.5",
"kind": "patch",
"published_at": "2026-05-08T07:08:58Z"
},
{
"tag": "v1.7.4",
"kind": "patch",
"published_at": "2026-05-02T13:41:55Z"
},
{
"tag": "v1.7.3",
"kind": "patch",
"published_at": "2026-05-01T07:36:39Z"
},
{
"tag": "v1.7.2",
"kind": "patch",
"published_at": "2026-05-01T00:22:53Z"
},
{
"tag": "v1.7.1",
"kind": "patch",
"published_at": "2026-04-30T10:14:56Z"
},
{
"tag": "v1.7.0",
"kind": "minor",
"published_at": "2026-04-29T10:05:15Z"
}
],
"recent_commits": [
{
"oid": "7c39284b964a4d4e7b67821d17a622cf599eaed8",
"body": "chore(release): v2.6.1",
"is_bot": false,
"headline": "Merge pull request #121 from floor/staging",
"author_name": "Floor",
"author_login": "floor",
"committed_at": "2026-07-15T05:45:44Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c6c29caeb6aa5897545574de541bfdbac783a920",
"body": null,
"is_bot": false,
"headline": "chore(release): v2.6.1",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-07-15T05:44:23Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "e22e42dd074b3b570f26f2b7dfc15d2b5f5908cc",
"body": "CHANGELOG [2.6.1] entry + README/npm-readme version summary. Base size\nunchanged (9.7 KB gzipped); no size-table impact.",
"is_bot": false,
"headline": "docs: prepare v2.6.1 release notes (#60)",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-07-15T05:16:49Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b6c1cf18d339e5b29b9e0a581967c2336d8dfb28",
"body": "Grid PageUp/PageDown column preservation (#60).",
"is_bot": false,
"headline": "Merge branch 'fix/60-grid-page-nav' into staging",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-07-15T05:08:29Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "dd09a86d96cb2c022b88cf3e365bdd5a887eacd1",
"body": "In grid mode, PageUp from an item in the first row (and PageDown from the last\nrow) clamped the target to the absolute first/last item, snapping focus to the\ncorner — i.e. Home/End behaviour — instead of staying in the same column.\n\nAdd a shared `clampPageTarget` helper that, in grid mode (`columns \n[…]\no both the selection and a11y keyboard handlers\n(including the layout↔data-index path). Linear lists (`columns <= 1`) keep the\nplain `[0, total-1]` clamp.\n\nAdds test/utils/grid-nav.test.ts (10 cases).",
"is_bot": false,
"headline": "fix(a11y): PageUp/PageDown preserve column at grid boundaries (#60)",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-07-09T16:33:18Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "1d1a469e2d8f191e77dbdc0dd13563f871959abe",
"body": "chore(release): v2.6.0",
"is_bot": false,
"headline": "Merge pull request #120 from floor/staging",
"author_name": "Floor",
"author_login": "floor",
"committed_at": "2026-07-08T02:53:57Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b1142f80fcbf3c8c440b09c7bd8c9459e008f803",
"body": null,
"is_bot": false,
"headline": "chore(release): v2.6.0",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-07-08T02:48:45Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ef7b3998ed44601ee864429280acbfda19556043",
"body": "Add CHANGELOG [2.6.0] entry and update the version summary in README.md and\nnpm-readme.md. Plugin size table verified against `bun run size` (unchanged;\nbase stays 9.7 KB gzipped).",
"is_bot": false,
"headline": "docs: prepare v2.6.0 release notes (changelog + readme)",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-07-08T02:43:52Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "72f593c72ffe266c403402f66e60674893458b7d",
"body": "Shared vlist/config resolver for framework adapters (fixes #119).",
"is_bot": false,
"headline": "Merge branch 'fix/119-adapter-config-resolver' into staging",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-07-08T02:42:03Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "203ebfcff8d21acb602af297158c2f9a2d3a260b",
"body": "Introduce a `vlist/config` subpath export owning the high-level `VListConfig`\ntype and the config→plugins translation (`resolvePlugins`,\n`createVListFromConfig`), previously duplicated across the four framework\nadapter repos.\n\nRoot-cause fix for #119: `CreateVListConfig` re-declared inline `item`/`s\n[…]\nse bundle stays 9.7 KB gzipped (tree-shaking\nintact). Adds test/config/resolve.test.ts (25 tests incl. #119 + native\nscrollbar regressions).\n\nFixes #119\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(config): add shared vlist/config resolver for framework adapters",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-07-08T02:41:56Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "02f859ab822bb4339c30e14aa3812616275d5d10",
"body": "Release v2.5.1",
"is_bot": false,
"headline": "Merge pull request #118 from floor/staging",
"author_name": "Floor",
"author_login": "floor",
"committed_at": "2026-06-13T10:47:21Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "9d4ae6accd45f5511b3a9525094333aad487944f",
"body": "Carousel snap refinements + fixes (groups bounded scroll, carousel snapEasing,\nstatic-variant reposition, async idle reconcile, grouped-table data indices).\nCorrect carousel size in both READMEs (+3.4 KB; npm-readme was stale at +2.3).",
"is_bot": false,
"headline": "chore(release): v2.5.1",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-13T10:42:14Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "e2ba4b04e7e80009d60295b2206b3a51edabca40",
"body": "The groups plugin was the one layout plugin never migrated to the bounded\nscroll model, so enabling scroll: { mode: 'bounded' } broke grouped lists:\n\n1. buildTransform positioned items at their raw absolute offset instead of\n offset - baseOffset, rendering them millions of px off-screen (blank lis\n[…]\nll three are no-ops in native mode (baseOffset is 0). Adds groups-bounded\nintegration tests (list deep-scroll, list gradual-scroll no-overlap, grid\ndeep-scroll), each verified to fail without its fix.",
"is_bot": false,
"headline": "fix(groups): make the groups plugin bounded-scroll aware (RFC-012)",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-13T07:22:42Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "8934709b2c5f2c983da42d4003eebdd67c4a5cc4",
"body": "…ument\n\nThe call passed (target, duration, undefined, snapEasing), parking snapEasing\nin the onComplete slot of the current\nsmoothScrollTo(target, duration, easing?, onComplete?) signature. A configured\nsnapEasing was silently ignored (snaps used the default easing) and it tripped\nthe type checker. Pass it as the easing argument.",
"is_bot": false,
"headline": "fix(carousel): forward snapEasing to smoothScrollTo as the easing arg…",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-12T23:52:17Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "bc093e218cd3aa8413d63ae10c3030b24543ad26",
"body": "…ange\n\nloadPendingRange bailed out when pendingRange was null. During a momentum\nscroll the final onAfterScroll can land in the slow path, which calls\nresetDeceleration() (clearing pendingRange) without re-ensuring the settled\nchunk — so onIdle loaded nothing and the viewport stayed on placeholders.\n\nAlways ensure the currently-visible range on idle. ensure() dedupes against\nloaded/in-flight chunks, so it is a no-op when the range is already loaded.",
"is_bot": false,
"headline": "fix(data): reconcile the visible range on idle regardless of pendingR…",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-12T23:52:17Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a9b1668bb2df80edf604abc0d05dc5f190c847cb",
"body": "In grouped table mode the engine runs in layout-index space (header\npseudo-rows interleaved with data rows), but the table render published raw\nlayout indices as engineState.startIndex/visibleCount. The async data plugin\nreads those as data indices, so it requested a range shifted by the header\ncoun\n[…]\nrender's entry.dataIndex fill); plain tables keep\nthe 1:1 path. Resolve the lookup once, and drop the per-row visible* array\nwrites that only the default render pipeline reads (the table replaces it).",
"is_bot": false,
"headline": "fix(table): publish data indices to the loader in grouped tables",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-12T23:52:04Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "f69186d8bd17a5af8905aa2768980ebcfb2ce162",
"body": "…ap for full variant\n\n- Add `snapDirection` option (default true) — snaps in the user's scroll\n direction instead of always to nearest item\n- Add `snapEasing` option — custom easing function for snap animation\n- Force snap on for `full` variant regardless of `snap: false`\n- Capture last scroll dire\n[…]\ne resets it to 0\n\nAlso:\n- Simplify rebuild utility — pass snapshot directly via `restore` instead\n of sessionStorage round-trip\n- Fix snapshots plugin — `restore` now takes precedence over `autoSave`",
"is_bot": false,
"headline": "feat(carousel): direction-aware snap, configurable easing, enforce sn…",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-09T17:35:10Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "3a6a4ec38ab649c7b1001187170a117289e5a489",
"body": "fix(carousel): static variant smooth scroll + concurrent test fixes",
"is_bot": false,
"headline": "Merge pull request #112 from floor/staging",
"author_name": "Floor",
"author_login": "floor",
"committed_at": "2026-06-09T10:32:40Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "dd446ffe9158e2b61a645b9d22e5881916a27375",
"body": "Use local container/list variables with try/finally cleanup in async tests\nthat previously shared file-level state, preventing races under\nbun test --concurrent. Resize test additionally flushes the ResizeObserver\ninstall synchronously to avoid leaking the global mock across yields.",
"is_bot": false,
"headline": "fix(test): isolate shared state for concurrent test stability",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-09T10:30:20Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "76218fb20cb17fc9b6f6e3cd3fd50de88dea4b58",
"body": "… scroll\n\nThe updateItemLayout() early return guard prevented DOM transform updates\nfor static carousels (no layout engine). Relax the guard to only bail when\nrealTotal <= 1, so the else branch computes absOffset - baseOffset each\nframe during smooth scroll animations.",
"is_bot": false,
"headline": "fix(carousel): allow static variant to reposition items during smooth…",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-09T10:30:14Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f9b59acc3b479a4ee5d18770025eadb0a0ccffed",
"body": "v2.5.0 — Carousel stylesheet, selectAll async fix",
"is_bot": false,
"headline": "Merge pull request #111 from floor/staging",
"author_name": "Floor",
"author_login": "floor",
"committed_at": "2026-06-09T09:39:31Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4b596b43bea538f6dfa26fbd4d2c52a772d02f7f",
"body": null,
"is_bot": false,
"headline": "chore(release): v2.5.0",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-09T09:36:33Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "79c2eba7b8955f75ebd1575ebb1af08c72a84407",
"body": "…l-focal-width\n\nLibrary-shipped structural styles for carousel slides: media stabilization\n(no image breathing during transitions), overlay visibility driven by\nrole-weight, and text truncation. Focal-width CSS variable locks media to\nthe focal slot size with centered absolute positioning for parallax pan.",
"is_bot": false,
"headline": "feat(carousel): add vlist-carousel.css stylesheet and --vlist-carouse…",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-09T09:08:23Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f35cff2915fe97ff9d596f6ffe6e3e6055377daa",
"body": "… unloaded\n\ndoSelectAll/doSelectRange now add placeholder IDs for items not yet fetched\nby the data plugin. The existing claimPlaceholderSelection mechanism swaps\nthem for real IDs when data loads. Also resolves loadedItemFn before the\nselectAll loop, marks placeholder DOM elements as selected in itemStateFn,\nand guards _seedSelection against restoring multi-selection into single mode.",
"is_bot": false,
"headline": "fix(selection): selectAll with async data selects all items including…",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-09T09:08:17Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f4392732f58b5a74973f9f8eac3cf79bc3409f34",
"body": "Maps role-weight to the item's rendered size relative to the focal\nslot — text fades out as items shrink at the edges and fades in as\nthey grow.",
"is_bot": false,
"headline": "feat(carousel): add \"size\" textFade mode, use it for uncontained",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-09T07:39:47Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "2e9dca856d52035c6235792e37a40c0becde4171",
"body": "…ewport offset\n\nroundedOffset is relative to native scrollTop=0, not the visible viewport.\nSubtracting the native scroll position gives correct viewport-relative\ncoordinates for the visibility ratio.",
"is_bot": false,
"headline": "fix(carousel): viewport role-weight used content offset instead of vi…",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-09T07:28:04Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b3352c0ba2785629a6bd87f7375554177e4267c3",
"body": "Add textFade (\"role\" | \"viewport\") to SlotConfig and new NoEngineConfig\ntype for presets without a layout engine. PresetResult union lets any\nresolver control overlay behavior. --vlist-carousel-role-weight variable\ndrives text overlay visibility per-frame: \"role\" mode fades by slot\nprogress, \"viewport\" mode fades by container-edge visibility.",
"is_bot": false,
"headline": "feat(carousel): textFade preset option and role-weight CSS variable",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-09T07:18:52Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "8f23fbc6f82db70a7d71b43a9a043b00903f5043",
"body": "v2.4.2",
"is_bot": false,
"headline": "Merge pull request #110 from floor/staging",
"author_name": "Floor",
"author_login": "floor",
"committed_at": "2026-06-09T06:01:33Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a574c707fc3cbd4da64448b0061e8c85405c93cb",
"body": "…ncItemCount",
"is_bot": false,
"headline": "test(carousel): cover SlotConfig object variant and variable-width sy…",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-09T05:49:39Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3efa1a1f4ce3f3446ae60ace9bbab46d271f2a89",
"body": null,
"is_bot": false,
"headline": "chore(release): v2.4.2",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-09T05:47:26Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "79620a5dcb425bdb0260286f51fa1827792bac3b",
"body": "Replace hardcoded switch in resolvePreset with a Map-based registry.\nPresets are SlotConfigResolver functions registered by name — users\ncan add or override presets via registerPreset(). The variant config\nnow accepts a string, SlotConfig, or SlotConfigResolver function.",
"is_bot": false,
"headline": "feat(carousel): modular preset registry",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-09T05:24:08Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1adbe6ad1b7a173cb9e2883d95b41095ac188555",
"body": "MD3's \"Uncontained multi-aspect ratio\" variant positions the focal item\nat the left viewport edge with neighbors peeking from the right — not\ncentered. Remove centerShift from the no-layout-engine path.",
"is_bot": false,
"headline": "fix(carousel): left-align multi-aspect items per MD3 uncontained spec",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-09T04:20:57Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c8964a83698b91227531ee8c80ce75e0afb50a84",
"body": "The no-layout-engine path (used by multi-aspect variant) positioned items\nfrom the left edge, making the focal item appear off-center. Compute\ncenterShift from the interpolated focal item size and apply it to all\nitem offsets so the active item stays centered in the viewport.",
"is_bot": false,
"headline": "feat(carousel): focal centering for multi-aspect variable-width items",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-09T04:17:08Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "50fa46f6ad2b4943cb5aa5db7dd26f2f8644019b",
"body": "…iant\n\nReplace scalar stepSize with stepSizes[] array and stepOffsets[] prefix\nsums. Binary search for variable widths, fast division for uniform —\none pipeline handles both. Adds multi-aspect variant that renders items\nat their natural widths without a slot engine.",
"is_bot": false,
"headline": "feat(carousel): support per-item variable widths for multi-aspect var…",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-09T03:03:09Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "426081247a87eff338b5ea9d30aa8712845e481e",
"body": "…cal boundary\n\nItems shrinking to 0 at the focal-boundary flip kept a full gap until\nthe instant they disappeared, injecting a gap-sized jump into cumulative\noffsets. Fade the gap proportionally with the item size so the offset\nstays continuous through the flip.",
"is_bot": false,
"headline": "fix(carousel): fade gap with item size to eliminate offset jump at fo…",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-09T03:03:01Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b745e91ad7fedb7eb280a05f6fcb6a7a21c45528",
"body": "v2.4.1",
"is_bot": false,
"headline": "Merge pull request #109 from floor/staging",
"author_name": "Floor",
"author_login": "floor",
"committed_at": "2026-06-07T19:51:08Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "e182f3ac9ef27621ff8c42db29ec43128f740567",
"body": "The custom scrollbar's max position was computed from engineState.totalSize\nalone, which excludes padding. This made the thumb stop short by\nmainAxisPadding pixels when dragged to the bottom — the End key and\nscrollToIndex worked because they route through the bounded handler's\nsetLogical which uses\n[…]\ned to updateBounds, and route\nthe scroll callback through ctx.scrollTo (which reaches setLogical\ndirectly) instead of ctx.scroll.setPixelEquivalent (which clamps via the\nadapter's sizeCache-only max).",
"is_bot": false,
"headline": "fix(scrollbar): include main-axis padding in max scroll bounds",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-07T19:49:34Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "5bbd1a26986337a6896f80a5c85bb252c1c0fcc5",
"body": null,
"is_bot": false,
"headline": "chore(release): v2.4.1",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-07T19:35:46Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "866031085734c2feef3cb9c125c8b87e4754f399",
"body": "… nav\n\nThe keyboard handler skipped scrollFocusIntoView when nav.navigate was\nset, assuming the custom navigate handles scrolling. Masonry provides\nnavigate for lane-aware 2D movement but relies on _scrollItemIntoView\nfor scrolling. Now scrollFocusIntoView runs when sivFn is registered\n(masonry) or when there is no custom navigate (grid/standard lists).",
"is_bot": false,
"headline": "fix(selection): scroll focused item into view during masonry keyboard…",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-07T19:32:36Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "fa2c512fcfb6e741edfe6c063d3ccc315f2457ac",
"body": "The bounded scroll handler ignored deltaX-dominant wheel events for\nhorizontal lists, falling through to native scroll. Native scroll is\nlimited by the bounded runway (~900px), causing missing items during\nfast macOS trackpad two-finger swipes. In wrap mode (carousel), these\nevents are now intercepted and processed synthetically like deltaY.",
"is_bot": false,
"headline": "fix(core): intercept trackpad horizontal swipe in carousel wrap mode",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-07T19:21:32Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "9240c53de869b6dd7b6f06742863eacc96345884",
"body": "Track the intended virtual index target so rapid button clicks chain\ncorrectly instead of computing from the mid-animation scroll position.\nClear the target on idle so manual scroll/drag still works.",
"is_bot": false,
"headline": "fix(carousel): rapid next/prev clicks no longer skip or stutter",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-07T18:56:36Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f7b4f77c8cd635f5c1e64d976ceefe7e83f587e6",
"body": "v2.4.0 — Bounded logical scroll model (RFC-012)",
"is_bot": false,
"headline": "Merge pull request #107 from floor/staging",
"author_name": "Floor",
"author_login": "floor",
"committed_at": "2026-06-07T18:28:34Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "2c0ca81fe4fd602c837e9f793020e40e8818fcbe",
"body": null,
"is_bot": false,
"headline": "docs: mention carousel plugin in 2.4.0 tagline, sync npm-readme sizes",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-07T18:26:22Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "77c99a24a9ac5392fdc16d72745baeb065136822",
"body": "…cItemCount",
"is_bot": false,
"headline": "test(carousel): cover presets, keyboard handler, snap, navConfig, syn…",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-07T18:25:39Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1c6b2eee6a828b593d8ec9b66e109be6c036aa3b",
"body": null,
"is_bot": false,
"headline": "docs(changelog): fix base size claim in 2.4.0 entry",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-07T18:14:59Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3e371c4d78d0beb3ce112a04f921042204d51c81",
"body": null,
"is_bot": false,
"headline": "chore(release): v2.4.0",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-07T18:12:18Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "5ff6755d9bc9de36e18b6f560d04f03092c23801",
"body": null,
"is_bot": false,
"headline": "Merge logical-scroll-model (RFC-012 + Phase A)",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-07T18:09:26Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "441698c0f42dfc70857f999be18b1cf903f5a2ab",
"body": "RFC-013 Phase A: grid/table/masonry route through bounded scroll.\nScale deprecation stub. File renames (runway.ts, adapter.ts).",
"is_bot": false,
"headline": "Merge rfc-013-renderer-routing into logical-scroll-model",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-07T18:07:12Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "122a4f8b83c3b220c4a8eb10e2ebbf6e7d808792",
"body": "scale() returns a no-op plugin with a one-time console.warn pointing\nusers to scroll: { mode: \"bounded\" }. Preserves the import so existing\ncode doesn't break on a minor bump. Removed entirely in 3.0.",
"is_bot": false,
"headline": "feat(scale): deprecation stub for 2.4.0 → 3.0 migration",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-07T18:06:26Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ed5c28ed3362b8af0ceec5f3486f224f401538a4",
"body": "One-word filenames to match the directory convention (scroll, state,\nsizes, pool, etc.). Coverage tests for runway.ts added: 67.8% → 99.4%\nline coverage — wheel handler, idle detection, smooth scroll, cancel.",
"is_bot": false,
"headline": "refactor(core): rename bounded-scroll → runway, scroll-model → adapter",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-07T18:06:19Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "802f7a172a9cd9e8d206f87044e68621dfe925a9",
"body": null,
"is_bot": false,
"headline": "chore: add .agents/ and .env.agents to gitignore",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-07T18:05:26Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "54fb8f0e1732d111d398883eee50358c214b52cc",
"body": "These renderers install setRenderFn, so core skips syncContentSize and they\nown content sizing. They wrote the full physical size and absolute transforms,\nreintroducing the browser ~16.7M px element limit in bounded mode.\n\n- subtract engineState.baseOffset from item transforms (no-op in native mode)\n[…]\nontentSize so the bounded handler\n caps it to the runway, guarded by lastContentTotalSize\n- masonry re-syncs content size on the first render since the bounded handler\n is created after plugin setup",
"is_bot": false,
"headline": "fix(render): route grid/table/masonry through bounded scroll (RFC-013)",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-07T17:17:58Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "283b2d5d42725cec361a9574ae61fa7c89bb5f36",
"body": "Two RFC-012 review fixes:\n\n- The ResizeObserver updated containerSize and re-rendered but never called\n boundedHandler.refresh(), so the runway and max-logical bounds stayed sized\n to the old viewport. Refresh the handler before rendering on resize.\n\n- page() installs window-based scroll fns; the \n[…]\nt handler, silently breaking both. Throw an\n explicit error when page() is combined with scroll: { mode: \"bounded\" } or\n the carousel plugin (bounded wrap). Bounded page-mode is not implemented yet.",
"is_bot": false,
"headline": "fix(core): refresh bounded runway on resize; guard page() + bounded",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-07T16:08:30Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "d67ff7282e8cebc73584f07878946e3361e381e3",
"body": "… Phase 4)\n\nThe carousel previously managed its own silent rebasing, smooth-scroll\nanimation, and raw scrollTop writes over a content element sized to the\nfull virtual window. That duplicated the bounded handler's job and assumed\nscrollTop == logical position.\n\nIt now requests a wrap-capable bounded\n[…]\n value.\n\nThe mock PluginContext scroll writes now mutate scrollPosition to match the\nreal adapter; this corrected an autosize test that was asserting a mock\nartifact (anchor compensation accumulates).",
"is_bot": false,
"headline": "refactor(carousel): route infinite loop through bounded wrap (RFC-012…",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-07T15:59:04Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "2f212b1053c3463c46ace18cefc071440507d2c1",
"body": "Remove the legacy rendering/compression domain that src/core/ already\nsuperseded. These modules were reachable only via vlist/internals, never on\nthe runtime path, so the main bundle is unaffected (base stays 9.4 KB).\n\n- delete src/rendering/{renderer,viewport,scale,scroll,measured}.ts and\n src/plu\n[…]\nomments\n- delete the dead compression tests; de-compress the grid/table renderer\n tests; update the size-overflow assertion\n\nbun run typecheck clean, bun test 3326 pass / 0 fail, bun run build green.",
"is_bot": false,
"headline": "refactor(core): delete dead compression internals (RFC-012 Phase 3b)",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-07T15:17:10Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "7b4d282bf639d118dcec545ba8ede37ffa369430",
"body": "Base 8.1 → 9.4 KB (bounded scroll now in core), drop the scale() row,\nrefresh every plugin delta against `bun run size`, add carousel(), and\npurge stale scale references. Remove scale from scripts/size.ts.",
"is_bot": false,
"headline": "docs: update bundle sizes after scale plugin removal",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-07T15:03:30Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "5a90a36aedfc2edd50452d0ffb2be73ec8e4d118",
"body": "Bounded logical scroll supersedes scroll compression. Remove the scale\nplugin, its public export and build entry, and the now-dead compression\nbranches across core (state, wheel handler) and the scrollbar, snapshots,\ngroups, grid, table, and tree plugins.\n\nLegacy src/rendering/* and internals compression references are left for\na follow-up pass; they are not on the live engine path.",
"is_bot": false,
"headline": "refactor(core): remove scale plugin and compression path (RFC-012)",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-07T13:58:51Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "78f7e3edfbd32142bd431ca228b8902c049a076a",
"body": "Add an opt-in `scroll: { mode: \"bounded\" }` model that sizes the content\nelement to a viewport-multiple runway instead of the full virtual size,\navoiding the browser's ~16.7M px element limit without the scale plugin's\ncompression. The public scroll position is an absolute logical pixel;\nnative scro\n[…]\n autosize derives end-detection from the size cache, not scrollHeight.\n- Runway defaults to 2x viewport (configurable via scroll.runway,\n clamped up to a 1.5x floor for native scroll/touch momentum).",
"is_bot": false,
"headline": "feat(core): bounded logical scroll model (RFC-012)",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-07T01:50:07Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "f2d475fa86ea40c613c8a15019d3c8ac0b683e16",
"body": "Carousel plugin (RFC-011): infinite-loop scrolling with configurable\nlayout engine. 70 tests, +2.2 KB gzipped.\n\n- Layout engine (engine.ts) with slot-based model\n- Presets: full, hero, hero-center, multi, uncontained, static\n- Dynamic item sizing on every scroll frame\n- Built-in keyboard navigation \n[…]\non sync (preserves logical index on item changes)\n- Smooth animation layout sync (forceRender on completion)\n- carousel:change event, CSS variables per element\n- 3815 total tests pass, typecheck clean",
"is_bot": false,
"headline": "Merge feat/carousel-plugin into staging",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-06T19:33:37Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "10bbe680449536d45fab9324450a11b6a3d2f8fc",
"body": "Truly circular: rebaseIfNeeded() now runs on every onAfterScroll frame,\nnot just when snapEnabled is true. Without this, free scroll (no snap)\nwould hit the edge of the 101-cycle virtual window and stop.",
"is_bot": false,
"headline": "fix(carousel): rebase fires on every scroll, not just when snap enabled",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-06T19:32:44Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "759ae7efb70df0dff04e5c86dc01499c66ae5eb1",
"body": "…malization\n\n8 new tests (62 → 70):\n- Keyboard: registers keydown handler, sets tabindex=0\n- carousel:change: emitted by next() with correct logical index,\n prev() wraps correctly\n- Index mapping: _layoutToDataIndex maps virtual→logical via modulo\n- Mutation sync: getItems().length reflects additions\n- Normalized scroll: getCarouselState().scrollPosition within one lap",
"is_bot": false,
"headline": "test(carousel): keyboard, events, index mapping, mutation, scroll nor…",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-06T18:37:27Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "0323dedb09f4a80bb3137bfeada2699cd71742f7",
"body": "Keyboard navigation:\n- Carousel registers keydown handler via ctx.registerKeydownHandler\n- Sets tabindex=0 on content element for focusability\n- Arrow keys use next()/prev() with smooth scrolling (same as buttons)\n- Home/End use goTo() with smooth scrolling\n- setNavConfig({ navigate, total }) for se\n[…]\nMutation sync:\n- syncItemCount rebases scroll to preserve logical index\n- Scroll setter updates engineState immediately\n- next()/prev() emit carousel:change directly\n\n3815 tests pass, typecheck clean.",
"is_bot": false,
"headline": "fix(carousel): built-in keyboard nav, smooth animation layout sync",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-06T18:32:53Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "e9da69e0ae889a103e1ce3ed78fc7ca18817f054",
"body": "P1 fix from cadex review: virtual scroll indices (e.g. 247 for a 5-item\nlist) leaked into data-index, aria-posinset, aria-setsize, templates,\nclick events, and element IDs.\n\nCore changes:\n- Add setIndexMapFn to PluginContext — plugins can register a render→logical\n index mapper that the pipeline us\n[…]\n.ts (engine.ts is now pure math)\n\nAlso fixes:\n- groups-table-data flaky tests: scoped ensureDimensions() helper\n- renderer.test.ts: instance-level clientWidth/Height override\n\n3815 tests pass, 0 fail.",
"is_bot": false,
"headline": "fix(carousel): virtual indices no longer leak into public API",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-06T16:34:21Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "243d62ffe7e742411be4d4bc0fb28f076451b32d",
"body": "- Add gap parameter to LayoutConfig — engine subtracts gap from slot widths\n and adds spacing in offset accumulation. Both axes, all variants.\n- Center-aligned hero: getAnchorOffset() shifts viewport anchor for pre-focal\n slots so the focal item is visually centered.\n- Full preset now uses the engine (slots: [1.0]) — no special case.\n- Default gap: 0 (library convention). Example sets gap: 8 (MD3 spec).\n- 62 tests: 3 gap tests (hero/full/vertical), 1 center centering test.",
"is_bot": false,
"headline": "feat(carousel): gap support, center preset, all variants through engine",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-06T15:04:43Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "9f9789e8a3662d9e3b36098813e543528a5a636f",
"body": "Slot-based layout model: each variant is a configuration of slot\nratios (e.g., hero [0.80, 0.20], center [0.15, 0.70, 0.15]).\nThe engine computes per-item sizes, offsets, and CSS variables\nfrom the scroll fraction — all variants use the same code path.\n\n- engine.ts: createLayoutEngine(), resolveVari\n[…]\n MD3 transition model: outgoing shrinks to 0, incoming grows, next peek fades in\n- Snap-on-idle via setTimeout in onAfterScroll\n- next()/prev() always target snap positions\n- 58 tests, +2.1 KB gzipped",
"is_bot": false,
"headline": "refactor(carousel): extract layout engine into engine.ts",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-06T14:19:28Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "0e74188a28503ce3e4eba725dd3e47650647fca0",
"body": "…riables\n\nPhase 2 implementation:\n- Compute step size per variant (full=container, hero=container-peek, hero-center=container-2*peek)\n- Resolve peek from number (px), percentage string, or \"auto\" (56dp, clamped 40-56)\n- Set --vlist-carousel-progress, --vlist-carousel-offset, --vlist-carousel-role per element on scroll\n- 56 tests covering step size, peek config, CSS variables, hero cycling and infinite loop",
"is_bot": false,
"headline": "feat(carousel): hero/hero-center variants with peek sizing and CSS va…",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-06T12:24:46Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "032f8f9e53b2d3c4a24cf6ad236e6288bc09240c",
"body": "The onAfterScroll hook now emits a carousel:change event with the\nlogical index when the focused card changes from user scrolling.\nConsumers can listen to update dots, panels, or other UI.",
"is_bot": false,
"headline": "feat(carousel): emit carousel:change event on scroll index change",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-06T11:18:21Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "e3bb7ac8648b3e4602df16220882f140753739b7",
"body": "The first render happened at scrollPosition=0 (items at indices 0-5).\nThe onCommit hook then set scrollTop to 384,000 but the DOM still\nshowed the stale items. Now forces a re-render after setting the\ninitial scroll position.\n\nAlso removed the sizeCache.rebuild hook that was corrupting realTotal\nwhen the engine called rebuild(virtualTotal) internally.\n\nPublic API (list.total) returns realTotal via virtualTotalFn.\nengineState.totalItems is virtualTotal for the render pipeline.",
"is_bot": false,
"headline": "fix(carousel): render items at correct virtual positions",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-06T11:11:48Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "e851c97e97f77c8282b896a0a0f18c034ce4d713",
"body": "The virtual scroll window is now entirely internal to the sizeCache\nhooks — getTotalSize, getOffset, getSize, indexAtOffset, and getTotal\nall report virtual dimensions, but engineState.totalItems stays at\nthe real item count.\n\nThis means ARIA, selection, click events, and list.total all see the\nlogical 16 items, not the inflated 1616 virtual slots. Matches the\nRFC-011 spec: \"Public totals stay logical.\"",
"is_bot": false,
"headline": "fix(carousel): keep totalItems at real count, hook sizeCache internally",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-06T10:56:09Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a5b8681df34363446656319bb063979b2e48423f",
"body": "…integration\n\n- sizeCache rebuilt with virtualTotal for proper content height\n- Initial scroll to middle cycle deferred to onCommit hook\n- next()/prev() scroll forward/backward from current position\n- goTo() uses shortest-path in virtual space\n- scrollToIndex override for wrap-aware navigation\n- Plugin-wizard example updated to use carousel() plugin\n- Verified in browser: forward wrap from last→first works\n- 26 tests, +1.0 KB gzipped, 18 size scenarios clean",
"is_bot": false,
"headline": "feat(carousel): virtual scroll window with deferred init and browser …",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-06T10:47:30Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "32d60ebca4e0411e120a9f857af26f8a68a961a4",
"body": "- 101-cycle virtual window: items mapped via modulo, start in middle cycle\n- Silent rebasing when approaching edge cycles (threshold: 10 cycles)\n- next()/prev() always scroll in the user's direction (no rewind)\n- goTo() with direction: auto takes shortest path, forward/backward forced\n- Smooth scroll with easeInOutQuad animation\n- scrollToIndex override for wrap-aware navigation\n- onAfterScroll hook updates currentIndex from scroll position\n- +1.0 KB gzipped (within 2.0 KB budget)",
"is_bot": false,
"headline": "feat(carousel): virtual scroll window with silent rebasing",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-06T10:28:04Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "9141a5bd61f3b384850d3d54688608e0f45eee56",
"body": "…tests\n\n- Export carousel from src/index.ts\n- Add to build.ts ALL_PLUGINS and wrapper\n- Add size scenario: +0.4 KB gzipped (18 scenarios clean)\n- Add tests: virtual item mapping (modulo wrap), next/prev cycling\n across boundaries, initialIndex with wrapping\n- 26 tests passing",
"is_bot": false,
"headline": "feat(carousel): export, build entry, size tracking, and virtual item …",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-06T10:17:34Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3f9d8caa0d5f250706b7d0239e096dbee09dc0aa",
"body": "Carousel plugin stub with 21 passing tests covering:\n- Factory (name, priority, variants, scale conflict)\n- Registered methods (next, prev, goTo, getCarouselState)\n- Infinite loop (wrap forward/backward, step with wrap)\n- Logical totals (real item count, index always 0..total-1)\n- Edge cases (empty list, single item)\n- Snap config, variant: full, goTo direction, destroy\n\nImplementation uses modulo index resolution and shortest-path\nnavigation. Silent rebasing and CSS variable effects are next.",
"is_bot": false,
"headline": "feat(carousel): scaffold plugin with tests-first (RFC-011)",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-06T10:08:44Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "261a5f26ff1efbf815f0fa59d7167d218efd2e33",
"body": "…clamp\n\nscrollToIndex clamped indices to 0..total-1, ignoring the scroll.wrap\nconfig. Index 16 with 16 items was clamped to 15 — no scroll happened.\nNow uses modulo when wrap is enabled, matching the JSDoc contract.",
"is_bot": false,
"headline": "fix(core): scrollToIndex respects scroll.wrap with modulo instead of …",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-06T09:05:16Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ded39a4b2d6645dc83743e300782e6064f22bc03",
"body": "chore(release): v2.3.0",
"is_bot": false,
"headline": "Merge pull request #104 from floor/staging",
"author_name": "Floor",
"author_login": "floor",
"committed_at": "2026-06-05T14:38:38Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "57c840a9b6135e51f8699b6cc50d05cb886fd15d",
"body": "Add tests for keyboard handler (open/close/navigate), cancel timeout,\nand type-ahead invisible mode (position: \"none\"). Coverage goes from\n81.1% to 87.2% line coverage.",
"is_bot": false,
"headline": "test(search): raise coverage above 85% threshold",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-05T14:17:03Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b7d983f46ab58ed3e9a2c6d60fae57bcd8794e9d",
"body": null,
"is_bot": false,
"headline": "chore(release): v2.3.0",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-05T13:55:02Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1be82f946365a9b06f2f7f9b31d4037e433d24d3",
"body": null,
"is_bot": false,
"headline": "docs(release): prepare v2.3.0 notes, README/npm-readme sizes and version",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-05T13:54:01Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a6a16ef2d2657168a82765cfe50908bf020ed212",
"body": "The groups plugin's rebuild hook was destroyed when the table plugin\ncalled setSizeConfig (Object.assign overwrites all sizeCache methods).\nThe previous fix used queueMicrotask to re-hook, which only worked\nfor autoLoad:true due to timing.\n\nThe hook now self-heals: on each call, it checks if sizeCache.rebuild\nstill points to itself. If not (setSizeConfig overwrote it), it\nre-captures the new base and re-installs — same pattern as the grid\nplugin's installRebuildHook guard.\n\nResolves issue 022.",
"is_bot": false,
"headline": "fix(groups): self-healing sizeCache.rebuild hook survives setSizeConfig",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-05T13:40:49Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "0071b1cd643199a74cf6002ba8aa1f40471d68cc",
"body": "…tive\n\nWhen primary axis is X and a sticky header exists, inline group headers\nwere still rendered and visible alongside the sticky header. Now sets\ndisplay:none on inline headers in this case — the sticky header alone\nhandles group labeling in horizontal scrolling mode.",
"is_bot": false,
"headline": "fix(groups): hide inline headers in horizontal mode when sticky is ac…",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-05T12:49:51Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "08fcf7ddd8162bbf6a93881cadb040d616fa6410",
"body": "… mode\n\nlaneYCenters was populated with zeros when groups was active because\nthe groups layout positions aren't in cachedPlacements. The groups\nplugin now exposes _getItemY and _getItemH methods, and masonry uses\nthem to compute accurate Y-center values for bsNearest cross-lane\nnavigation.",
"is_bot": false,
"headline": "fix(masonry,groups): ArrowRight/Left finds nearest Y-center in groups…",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-05T12:36:31Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "26b8b26618ba3c85871da6dcb504b1be049060fe",
"body": "…o-view\n\nThe groups plugin's _scrollItemIntoView used sizeCache.getSize()\nwhich returns fallback heights in masonry mode, not the computed\nmasonry item height. Now reads pos.h from gridItemPositions.\n\nAlso accounts for startPadding in the scroll-up detection so the\nfocused item doesn't touch the viewport top edge.",
"is_bot": false,
"headline": "fix(groups): use actual item height and padding in masonry scroll-int…",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-05T12:17:10Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d04e8d8f7eed5d1914f4cad62b36530bbbff6135",
"body": "The masonry navigate() function receives layout indices from the\nselection plugin, but cachedPlacements uses data indices. When groups\nis active, these differ because group headers are interleaved.\n\nAdded toData/toLayout helpers that resolve _layoutToDataIndex and\n_dataToLayoutIndex from the groups \n[…]\noutToDataIndex\n(the groups plugin's masonry integration path skips it), so the\nconversion is identity for now. The framework is in place for when\ngroups properly exposes index mapping in masonry mode.",
"is_bot": false,
"headline": "fix(masonry): add layout↔data index conversion for groups compatibility",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-05T12:03:45Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "e88e6b8c128d55e45b331902f54d16d875e54ce2",
"body": "selection and scale referenced \"getGridLayout\" (a public grid method)\nto read the row gap, causing the size checker to flag grid code as\nleaked into their bundles.\n\nGrid now registers a private _getRowGap method. Selection and scale\nread it via ctx.getMethod(\"_getRowGap\") — no grid-specific string\nin their source, clean tree-shaking.",
"is_bot": false,
"headline": "fix(grid,scale,selection): use _getRowGap to avoid tree-shaking leak",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-05T11:07:13Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "82097c73b9e6a5cbbc28ed67ebeb78c8297372f9",
"body": "Use startPadding/endPadding individually instead of mainAxisPadding.\nThe compressed path computes a delta from the item's actual rendered\nposition (via calculateCompressedItemPosition) relative to the\nviewport, then adjusts the virtual scroll by delta * ratio.\n\nNon-compressed paths in both selection and scale now include\nstartPadding in the scroll-down target so the bottom gap matches\nendPadding exactly.",
"is_bot": false,
"headline": "fix(scale,selection): pixel-perfect scroll-into-view with padding",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-05T10:59:15Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "78f0458f0e4ddb49ede691f24d8a9b0ba87119aa",
"body": "The compressed path compared virtual item positions against the\nviewport size (an actual-pixel measurement), mixing coordinate\nspaces. ArrowDown from the top at 500K+ never triggered scrolling\nbecause the virtual positions were far smaller than containerSize.\n\nNow uses calculateCompressedItemPosition to get the item's rendered\noffset relative to the viewport, then compares against containerSize\ndirectly — same logic as the non-compressed path.",
"is_bot": false,
"headline": "fix(scale): use actual item position for scroll-into-view detection",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-05T10:11:21Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "edfd39a0ecab6e7eae829aa847461e87dc1d19d6",
"body": "scrollFocusIntoView and _scrollItemIntoView positioned the last item\nflush against the viewport edge, ignoring mainAxisPadding. The bottom\npadding was invisible when pressing End or ArrowDown to the last item.\n\nSelection plugin now checks `offset + size > sp + cs - pad` and\nscrolls to `offset + size + pad - cs`.\n\nScale plugin adds `mainAxisPadding * ratio` to getMaxScroll so the\ncompressed scroll range includes the scaled padding. The non-compressed\npath mirrors the selection plugin's formula.",
"is_bot": false,
"headline": "fix(scale,selection): account for padding in scroll-into-view",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-05T09:56:33Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a5108a4b0d19ccf300519ff1509a6fb264724687",
"body": "Grid: verify updateGrid survives rapid column/gap changes without\nstack overflow, and that the rebuild hook uses the mutable column\ncount (not the stale initial config).\n\nScale: _scrollItemIntoView and scrollToIndexFn tests were added in\nthe prior commit (a9ddd53).",
"is_bot": false,
"headline": "test(grid,scale): add tests for rebuild hook and scroll-into-view",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-05T08:45:43Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "0683af3557060ee2ec14d183f9ce686e470bb970",
"body": "installRebuildHook captured sizeCache.rebuild which was already the\nhooked version when called without a preceding setSizeConfig — the\nhook called rebuildAsRows which called the hook again.\n\nNow tracks the current hook reference and skips re-installation if\nsizeCache.rebuild is already hooked.",
"is_bot": false,
"headline": "fix(grid): prevent infinite recursion in sizeCache.rebuild hook",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-05T08:41:07Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a9ddd536f58c98079f7e64982d9cbe26536dddc4",
"body": "The selection plugin's scrollFocusIntoView compared uncompressed\nsizeCache offsets against the compressed virtual scroll position —\ndifferent coordinate spaces. This caused ArrowUp from the bottom\nof a scaled list to leave the focused item pinned at the viewport\nbottom instead of scrolling up.\n\nThe scale plugin now registers _scrollItemIntoView which uses\ncalculateCompressedScrollToIndex to compute the correct virtual\nposition for both \"item above viewport\" and \"item below viewport\"\ncases.",
"is_bot": false,
"headline": "fix(scale): register _scrollItemIntoView for keyboard navigation",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-05T08:18:23Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "55c4589911d78835dc81c771599f59fa2bfcd488",
"body": "The data plugin calls sizeCache.rebuild(itemCount) when data loads.\nWithout the hook, this overwrites the grid's row-based total with the\nraw item count, breaking the scale plugin's compression ratio and\nscrollbar range.\n\nThe hook converts item count → row count (ceil(n / columns)) before\ndelegating\n[…]\nevery\nsetSizeConfig call (which Object.assigns a new cache and destroys\nhooks).\n\nAlso adds onContentKeydown input guard in create.ts to skip keydown\nfor embedded form controls (input/textarea/select).",
"is_bot": false,
"headline": "fix(grid): hook sizeCache.rebuild to convert item count to row count",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-05T03:44:23Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "dbf2f318b11b17f18f1e13feda50c1f567228c0e",
"body": "…pping\n\nresolveClickedItem maps layout index → data index via _layoutToDataIndex\nwhen groups are active. Previously it passed the data index to getItemFn,\nwhich in table+groups mode is already layout-aware (set by the groups\nplugin via setGetItemFn) — causing a double mapping that returned the\nwrong\n[…]\nfor the\ntable-mode ordering requirement (groups must be pushed after table in\nthe plugin array since both are priority 10).\n\nTests: item:click offset correctness with groups, header click suppression.",
"is_bot": false,
"headline": "fix(core): resolveClickedItem uses _getItem to avoid double layout ma…",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-04T10:41:58Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "20a359523abc9345fa666ae6c2a23c78ff425361",
"body": "Search plugin (RFC-008 Phase 1), scoped highlighting, tree+selection\nclick fixes, and stale-mark highlight fix.",
"is_bot": false,
"headline": "Merge feat/search-plugin into staging",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-04T08:19:04Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "9969ac699004001ac3025ffbdb7618f26494ce78",
"body": "forceRender() reuses pooled elements without re-rendering templates\nwhen the same item stays at the same index (pipeline.ts:306). This\nleft <mark> tags from the previous query in the DOM; the TreeWalker\nthen skipped text inside those marks, producing partial highlights.\n\nhighlightElement now calls clearHighlights first to unwrap existing\nmarks and restore original text nodes before applying the new query.",
"is_bot": false,
"headline": "fix(search): clear stale marks before re-highlighting on each keystroke",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-04T04:27:10Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1e1f752320047145d5c7ad5ce841480a75473772",
"body": "The `highlight` option now accepts `{ within: \".selector\" }` to\nrestrict `<mark>` wrapping to matching descendants instead of the\nwhole row. Prevents false highlights when the query appears in\nunrelated fields.\n\nAlso adds border-bottom to MD3 search bar variant.",
"is_bot": false,
"headline": "feat(search): scoped highlighting via highlight.within selector",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-04T03:59:12Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d47456fcbe02b5e04dc9a586adaacf49c984dbce",
"body": "Selection click handler used doToggle() in single mode, causing\nre-clicks to deselect. Now uses doSelect() so single-mode clicks\nalways select.\n\n_focusById now sets focusVisible = focusOnClick so the --focused\nCSS class appears when the tree plugin delegates focus.\n\nTree plugin registers _getLoadedI\n[…]\neyond root-level indices.\n\nAlso improves groups-table-data test resilience under --concurrent\nby documenting the Bun shared-heap prototype race and re-installing\noverrides at the snapshot-restore gap.",
"is_bot": false,
"headline": "fix(selection,tree): consistent click selection in tree views",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-04T03:59:06Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "15e6db0f35bdafe50bad673cbef3dd2cb0a84c1f",
"body": "selection/a11y: add keyboard?: boolean (default true). When false, the\nkeydown handler is skipped — click-selection, focus, and the full\nselection model stay active, letting an outer system own keyboard\nnavigation (e.g. a global, focus-independent hotkey layer).\n\ncore: resolveClickedItem maps layout\n[…]\nre (was falling back to the empty static\nitems array, always returning -1).\n\nNOTE: programmatic selectNext/selectPrevious scroll-into-view at the\nviewport edge is a known open issue (see desk issues).",
"is_bot": false,
"headline": "feat(selection): add keyboard option, fix getIndexById for async data",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-03T00:01:28Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "efa604f8510236fd4b34a8d2c0e3a1d435c41557",
"body": null,
"is_bot": false,
"headline": "docs(contributing): add no-inline-text standard (RFC-010)",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-02T18:44:14Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "77b6fae6bf758ebf3ff23a7c3d231dfc887ac613",
"body": "…010)\n\nRestructure the search bar to a modular BEM DOM (.vlist-search__container /\n__leading-icon / __input / __counter / __nav-prev|next / __clear-button) and\nrewrite the styles to BEM with theme tokens (reuse base --vlist-* vars; only\nmatch-highlight + MD3 surface/state are search-specific).\n\nExte\n[…]\nd the former top-level\nplaceholder option into text.placeholder.\n\nAdds RFC-010 test coverage (decorative magnifier, unnamed/named landmark,\nconsumer labels + counter formatters). 32 search tests pass.",
"is_bot": false,
"headline": "refactor(search): modular BEM search bar + externalized UI text (RFC-…",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-02T18:44:14Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "cdd1388b02c96dc9f5ac99da0d9b9e5c6acd5776",
"body": null,
"is_bot": false,
"headline": "docs(search): list search() in README + npm-readme plugin tables",
"author_name": "DrJones",
"author_login": "drjonze",
"committed_at": "2026-06-02T15:19:16Z",
"body_truncated": false,
"is_coding_agent": false
}
],
"releases_count": 34,
"commits_last_year": 1864,
"latest_release_at": "2026-07-15T05:46:50Z",
"latest_release_tag": "v2.6.1",
"releases_from_tags": false,
"days_since_last_push": 9,
"active_weeks_last_year": 22,
"days_since_latest_release": 9,
"mean_days_between_releases": 4.8
},
"community": {
"has_readme": true,
"has_license": true,
"has_description": true,
"has_contributing": true,
"health_percentage": 57,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"ecosystem": {
"packages": [
{
"name": "vlist",
"exists": true,
"license": "MIT",
"keywords": [
"virtual-list",
"virtual-scroll",
"virtualized-list",
"infinite-scroll",
"windowing",
"list-virtualization",
"dom-recycling",
"large-list",
"performance",
"typescript",
"zero-dependencies"
],
"ecosystem": "npm",
"matches_repo": true,
"registry_url": "https://www.npmjs.com/package/vlist",
"is_deprecated": false,
"latest_version": "2.6.1",
"repository_url": "https://github.com/floor/vlist",
"versions_count": 47,
"total_downloads": null,
"dependents_count": null,
"deprecation_note": null,
"maintainers_count": 1,
"monthly_downloads": 1016,
"first_published_at": "2017-07-07T07:59:07.048000Z",
"latest_published_at": "2026-07-15T05:46:47.346000Z",
"latest_version_yanked": null,
"days_since_latest_publish": 9
},
{
"name": "@floor/vlist",
"exists": true,
"license": "MIT",
"keywords": [],
"ecosystem": "npm",
"matches_repo": true,
"registry_url": "https://www.npmjs.com/package/@floor/vlist",
"is_deprecated": true,
"latest_version": "1.5.6",
"repository_url": "https://github.com/floor/vlist",
"versions_count": 68,
"total_downloads": null,
"dependents_count": null,
"deprecation_note": "This package has moved to 'vlist'. Install with: npm install vlist",
"maintainers_count": 2,
"monthly_downloads": 209,
"first_published_at": "2026-02-16T11:04:41.688000Z",
"latest_published_at": "2026-04-15T16:22:52.852000Z",
"latest_version_yanked": null,
"days_since_latest_publish": 99
}
]
},
"popularity": {
"forks": 1,
"stars": 12,
"watchers": 1,
"fork_history": {
"days": [
{
"date": "2026-04-11",
"count": 1
}
],
"complete": true,
"collected": 1,
"total_forks": 1
},
"star_history": null,
"open_issues_and_prs": 11
},
"ai_readiness": {
"has_nix": false,
"example_dirs": [],
"has_llms_txt": false,
"has_dockerfile": false,
"has_mcp_signal": false,
"bootstrap_files": [],
"api_schema_files": [],
"has_devcontainer": false,
"typecheck_configs": [
"tsconfig.json"
],
"toolchain_manifests": [],
"largest_source_bytes": 80649,
"source_files_sampled": 201,
"oversized_source_files": 7,
"agent_instruction_files": [
".claude/CLAUDE.md"
],
"agent_instruction_max_bytes": 12228
},
"dependencies": {
"manifests": [
"package.json",
"shim/package.json"
],
"advisories": {
"error": "No resolved dependencies carried a version and a supported ecosystem",
"scope": "repository_graph",
"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": 7,
"direct_affected_count": 0
},
"ecosystems": [
"npm"
],
"dependencies": [
{
"name": "vlist",
"manifest": "shim/package.json",
"ecosystem": "npm",
"version_constraint": "^1.5.5"
}
],
"all_dependencies": {
"error": null,
"source": "github-sbom",
"packages": [
{
"name": "vlist",
"direct": true,
"version": "^1.5.5",
"ecosystem": "npm"
},
{
"name": "@happy-dom/global-registrator",
"direct": false,
"version": "^20.9.0",
"ecosystem": "npm"
},
{
"name": "@types/bun",
"direct": false,
"version": "^1.0.0",
"ecosystem": "npm"
},
{
"name": "@types/jsdom",
"direct": false,
"version": "^27.0.0",
"ecosystem": "npm"
},
{
"name": "happy-dom",
"direct": false,
"version": "^20.9.0",
"ecosystem": "npm"
},
{
"name": "jsdom",
"direct": false,
"version": "^28.0.0",
"ecosystem": "npm"
},
{
"name": "typescript",
"direct": false,
"version": "^5.0.0",
"ecosystem": "npm"
}
],
"collected": true,
"truncated": false,
"total_count": 7,
"direct_count": 1,
"indirect_count": 6
}
},
"maintainership": {
"issues": {
"open_prs": 0,
"merged_prs": 48,
"open_issues": 11,
"closed_ratio": 0.8,
"closed_issues": 44,
"closed_unmerged_prs": 1
},
"bus_factor": 1,
"bot_contributors": 0,
"top_contributors": [
{
"type": "User",
"login": "drjonze",
"commits": 1798,
"avatar_url": "https://avatars.githubusercontent.com/u/150515870?v=4"
},
{
"type": "User",
"login": "floor",
"commits": 66,
"avatar_url": "https://avatars.githubusercontent.com/u/187733?v=4"
}
],
"contributors_sampled": 2,
"top_contributor_share": 0.965
},
"quality_signals": {
"has_ci": true,
"has_tests": true,
"ci_workflows": [
"ai-committee.yml",
"ci.yml",
"notify-staging.yml",
"publish.yml"
],
"has_docs_dir": false,
"linter_configs": [],
"has_editorconfig": false,
"has_linter_config": false,
"has_precommit_config": false
},
"security_signals": {
"lockfiles": [],
"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": null,
"reason": "internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
},
{
"name": "CI-Tests",
"score": 10,
"reason": "6 out of 6 merged PRs checked by a CI test -- score normalized to 10",
"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/6 approved changesets -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
},
{
"name": "Contributors",
"score": 3,
"reason": "project has 1 contributing companies or organizations -- score normalized to 3",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
},
{
"name": "Dangerous-Workflow",
"score": 10,
"reason": "no dangerous workflow patterns detected",
"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 30 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": "internal error: Client.Actions.ListWorkflowRunsByFileName: internal error: ListWorkflowRunsByFileName: GET https://api.github.com/repos/floor/vlist/actions/workflows/publish.yml/runs?status=success: 502 Server Error []",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
},
{
"name": "Pinned-Dependencies",
"score": 0,
"reason": "dependency not pinned by hash detected -- score normalized to 0",
"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": 0,
"reason": "detected GitHub workflow tokens with excessive permissions",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
},
{
"name": "Vulnerabilities",
"score": 0,
"reason": "12 existing vulnerabilities detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
}
],
"commit": "7c39284b964a4d4e7b67821d17a622cf599eaed8",
"ran_at": "2026-07-24T16:12:47Z",
"aggregate_score": 3.6,
"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-18T12:58:12Z",
"oldest_open_prs": [],
"last_merged_pr_at": "2026-07-15T05:45:44Z",
"ci_last_conclusion": "SKIPPED",
"oldest_open_issues": [
{
"number": 20,
"created_at": "2026-04-14T06:26:09Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 25,
"created_at": "2026-04-14T09:41:28Z",
"last_comment_at": "2026-06-10T06:50:16Z",
"last_comment_author": "AzzaAzza69"
},
{
"number": 31,
"created_at": "2026-04-20T06:55:49Z",
"last_comment_at": "2026-06-02T07:28:40Z",
"last_comment_author": "AzzaAzza69"
},
{
"number": 47,
"created_at": "2026-05-01T08:36:44Z",
"last_comment_at": "2026-05-29T09:29:57Z",
"last_comment_author": "AzzaAzza69"
},
{
"number": 60,
"created_at": "2026-05-13T14:12:23Z",
"last_comment_at": "2026-06-06T11:00:10Z",
"last_comment_author": "AzzaAzza69"
},
{
"number": 101,
"created_at": "2026-06-02T07:22:57Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 106,
"created_at": "2026-06-06T11:02:01Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 113,
"created_at": "2026-06-10T06:38:31Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 114,
"created_at": "2026-06-10T06:41:19Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 115,
"created_at": "2026-06-10T06:42:29Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 116,
"created_at": "2026-06-10T07:14:16Z",
"last_comment_at": null,
"last_comment_author": null
}
]
}
},
"config": {
"disabled_metrics": [],
"disabled_categories": [],
"disabled_components": {}
},
"source": {
"url": "https://github.com/floor/vlist",
"host": "github.com",
"name": "vlist",
"owner": "floor"
},
"metrics": {
"overall": {
"key": "overall",
"band": "moderate",
"name": "Overall health",
"note": null,
"notes": [],
"value": 59,
"inputs": {
"security": 36,
"vitality": 83,
"community": 44,
"governance": 54,
"engineering": 71
},
"components": []
},
"categories": [
{
"key": "vitality",
"band": "good",
"name": "Vitality",
"value": 83,
"weight": 0.22,
"metrics": [
{
"key": "development_activity",
"band": "good",
"name": "Development activity",
"note": null,
"notes": [],
"value": 72,
"inputs": {
"commits_last_year": 1864,
"human_commit_share": 1,
"days_since_last_push": 9,
"active_weeks_last_year": 22
},
"components": [
{
"key": "push_recency",
"name": "Push recency",
"detail": "last push 9 days ago",
"points": 28.8,
"status": "partial",
"details": [
{
"code": "push_recency",
"params": {
"days": 9
}
}
],
"max_points": 36
},
{
"key": "commit_cadence",
"name": "Commit cadence",
"detail": "22/52 weeks with commits",
"points": 15.2,
"status": "partial",
"details": [
{
"code": "commit_cadence_weeks",
"params": {
"weeks": 22
}
}
],
"max_points": 36
},
{
"key": "commit_volume",
"name": "Commit volume",
"detail": "1864 commits in the last year",
"points": 18,
"status": "met",
"details": [
{
"code": "commits_last_year",
"params": {
"count": 1864
}
}
],
"max_points": 18
},
{
"key": "openssf_scorecard_maintained",
"name": "OpenSSF Scorecard: Maintained",
"detail": "30 commit(s) and 30 issue activity found in the last 90 days -- score normalized to 10",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
},
{
"key": "release_discipline",
"band": "excellent",
"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": 34,
"latest_release_tag": "v2.6.1",
"releases_from_tags": false,
"days_since_latest_release": 9,
"mean_days_between_releases": 4.8
},
"components": [
{
"key": "ships_releases",
"name": "Ships releases",
"detail": "34 releases published",
"points": 27,
"status": "met",
"details": [
{
"code": "releases_published",
"params": {
"count": 34
}
}
],
"max_points": 27
},
{
"key": "release_recency",
"name": "Release recency",
"detail": "latest release 9 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "release_recency",
"params": {
"days": 9
}
}
],
"max_points": 36
},
{
"key": "release_cadence",
"name": "Release cadence",
"detail": "a release every ~4.8 days",
"points": 27,
"status": "met",
"details": [
{
"code": "release_cadence",
"params": {
"gap": 4.8
}
}
],
"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": "excellent",
"name": "Abandonment",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"cap": null,
"state": "unverified",
"guards": [],
"signals": [],
"red_flag": false,
"multiplier_pct": 100,
"declared_reason": null,
"unverified_reason": "repository_too_young",
"unanswered_open_prs": null,
"unanswered_open_issues": null,
"days_since_last_merged_pr": null,
"days_since_last_human_commit": null,
"days_since_last_human_commit_is_floor": false
},
"components": [
{
"key": "project_is_still_maintained",
"name": "Project is still maintained",
"detail": "maintenance record not established from the collected data",
"points": 100,
"status": "met",
"details": [
{
"code": "abandonment_unverified",
"params": {}
}
],
"max_points": 100
}
]
}
],
"description": "Is the project alive — is code being written and are releases shipping?"
},
{
"key": "community",
"band": "at_risk",
"name": "Community & Adoption",
"value": 44,
"weight": 0.18,
"metrics": [
{
"key": "popularity",
"band": "critical",
"name": "Popularity & adoption",
"note": null,
"notes": [],
"value": 17,
"inputs": {
"forks": 1,
"stars": 12,
"watchers": 1,
"growth_state": "unverified",
"growth_factor_pct": 100,
"growth_unverified_reason": "no_history"
},
"components": [
{
"key": "stars",
"name": "Stars",
"detail": "12 stars",
"points": 16.9,
"status": "partial",
"details": [
{
"code": "stars",
"params": {
"count": 12
}
}
],
"max_points": 60
},
{
"key": "forks",
"name": "Forks",
"detail": "1 forks",
"points": 0,
"status": "missed",
"details": [
{
"code": "forks",
"params": {
"count": 1
}
}
],
"max_points": 25
},
{
"key": "watchers",
"name": "Watchers",
"detail": "1 watchers",
"points": 0,
"status": "missed",
"details": [
{
"code": "watchers",
"params": {
"count": 1
}
}
],
"max_points": 15
}
]
},
{
"key": "community_health",
"band": "good",
"name": "Community health",
"note": null,
"notes": [],
"value": 70,
"inputs": {
"has_readme": true,
"has_license": true,
"has_contributing": true,
"has_issue_template": false,
"has_code_of_conduct": false,
"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": 18,
"status": "met",
"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
}
]
},
{
"key": "ecosystem_adoption",
"band": "moderate",
"name": "Ecosystem adoption (downloads)",
"note": "Excluded from scoring (no data or not applicable): Registry dependents. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"registry_dependents"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 52,
"inputs": {
"packages": [
"vlist",
"@floor/vlist"
],
"dependents": null,
"ecosystems": "npm",
"total_downloads": null,
"monthly_downloads": 1225
},
"components": [
{
"key": "monthly_downloads",
"name": "Monthly downloads",
"detail": "1,225 downloads/month across npm",
"points": 41.2,
"status": "partial",
"details": [
{
"code": "downloads_monthly",
"params": {
"count": 1225,
"ecosystems": "npm"
}
}
],
"max_points": 80
},
{
"key": "registry_dependents",
"name": "Registry dependents",
"detail": "not reported by this ecosystem",
"points": 0,
"status": "excluded",
"details": [
{
"code": "not_reported_by_this_ecosystem",
"params": {}
}
],
"max_points": 20
}
]
}
],
"description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
},
{
"key": "governance",
"band": "moderate",
"name": "Sustainability & Governance",
"value": 54,
"weight": 0.24,
"metrics": [
{
"key": "maintainer_resilience",
"band": "critical",
"name": "Maintainer resilience (bus factor)",
"note": null,
"notes": [],
"value": 16,
"inputs": {
"bus_factor": 1,
"contributors_sampled": 2,
"top_contributor_share": 0.965
},
"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 96% of commits",
"points": 0.8,
"status": "partial",
"details": [
{
"code": "top_contributor_share",
"params": {
"share": 96
}
}
],
"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 1 contributing companies or organizations -- score normalized to 3",
"points": 3,
"status": "partial",
"details": [],
"max_points": 10
}
]
},
{
"key": "responsiveness",
"band": "good",
"name": "Issue & PR responsiveness",
"note": null,
"notes": [],
"value": 75,
"inputs": {
"merged_prs": 48,
"open_issues": 11,
"closed_issues": 44,
"issue_closed_ratio": 0.8,
"closed_unmerged_prs": 1
},
"components": [
{
"key": "issue_resolution",
"name": "Issue resolution",
"detail": "80% of issues closed",
"points": 37.4,
"status": "partial",
"details": [
{
"code": "issues_closed_share",
"params": {
"share": 80
}
}
],
"max_points": 46.75
},
{
"key": "pr_acceptance",
"name": "PR acceptance",
"detail": "48/49 decided PRs merged",
"points": 37.5,
"status": "partial",
"details": [
{
"code": "decided_prs_merged",
"params": {
"merged": 48,
"decided": 49
}
}
],
"max_points": 38.25
},
{
"key": "openssf_scorecard_code_review",
"name": "OpenSSF Scorecard: Code-Review",
"detail": "Found 0/6 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": 57,
"inputs": {
"followers": 53,
"owner_type": "User",
"is_verified": null,
"owner_login": "floor",
"public_repos": 30,
"account_age_days": 6027
},
"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": "53 followers of floor",
"points": 12.5,
"status": "partial",
"details": [
{
"code": "owner_followers",
"params": {
"count": 53,
"login": "floor"
}
}
],
"max_points": 25
},
{
"key": "track_record",
"name": "Track record",
"detail": "30 public repos, account ~16 yr old",
"points": 22.9,
"status": "partial",
"details": [
{
"code": "public_repos",
"params": {
"count": 30
}
},
{
"code": "account_age_years",
"params": {
"years": 16
}
}
],
"max_points": 25
}
]
},
{
"key": "package_maintenance",
"band": "good",
"name": "Package maintenance",
"note": null,
"notes": [],
"value": 80,
"inputs": {
"packages": [
"vlist",
"@floor/vlist"
],
"ecosystems": "npm",
"any_deprecated": true,
"min_days_since_publish": 9
},
"components": [
{
"key": "published_resolvable",
"name": "Published & resolvable",
"detail": "2 package(s) on npm",
"points": 25,
"status": "met",
"details": [
{
"code": "packages_published",
"params": {
"count": 2,
"ecosystems": "npm"
}
}
],
"max_points": 25
},
{
"key": "publish_recency",
"name": "Publish recency",
"detail": "latest publish 9 days ago",
"points": 35,
"status": "met",
"details": [
{
"code": "publish_recency",
"params": {
"days": 9
}
}
],
"max_points": 35
},
{
"key": "version_history",
"name": "Version history",
"detail": "68 published versions",
"points": 20,
"status": "met",
"details": [
{
"code": "published_versions",
"params": {
"count": 68
}
}
],
"max_points": 20
},
{
"key": "not_deprecated",
"name": "Not deprecated",
"detail": "@floor/vlist: This package has moved to 'vlist'. Install with: npm install vlist",
"points": 0,
"status": "missed",
"details": [],
"max_points": 20
}
]
}
],
"description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
},
{
"key": "engineering",
"band": "good",
"name": "Engineering Quality",
"value": 71,
"weight": 0.2,
"metrics": [
{
"key": "engineering_practices",
"band": "moderate",
"name": "Engineering practices",
"note": null,
"notes": [],
"value": 68,
"inputs": {
"has_ci": true,
"has_tests": true,
"has_editorconfig": false,
"has_linter_config": false,
"has_precommit_config": false
},
"components": [
{
"key": "ci_workflows",
"name": "CI workflows",
"detail": "4 workflow(s)",
"points": 24,
"status": "met",
"details": [
{
"code": "ci_workflows",
"params": {
"count": 4
}
}
],
"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": "6 out of 6 merged PRs checked by a CI test -- score normalized to 10",
"points": 20,
"status": "met",
"details": [],
"max_points": 20
}
]
},
{
"key": "documentation",
"band": "good",
"name": "Documentation",
"note": null,
"notes": [],
"value": 75,
"inputs": {
"topics": [
"lightweight",
"performance",
"typescript",
"virtual-list",
"virtual-scroll",
"virtualization",
"zero-dependencies"
],
"has_wiki": true,
"homepage": "https://vlist.io",
"has_readme": true,
"has_docs_dir": false,
"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": 0,
"status": "missed",
"details": [],
"max_points": 25
},
{
"key": "documentation_homepage_site",
"name": "Documentation / homepage site",
"detail": "https://vlist.io",
"points": 15,
"status": "met",
"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": "7 topics",
"points": 10,
"status": "met",
"details": [
{
"code": "topics_count",
"params": {
"count": 7
}
}
],
"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": 36,
"weight": 0.16,
"metrics": [
{
"key": "security_posture",
"band": "at_risk",
"name": "Security posture",
"note": "Excluded from scoring (no data or not applicable): Branch-Protection, Packaging, Signed-Releases. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"branch_protection",
"packaging",
"signed_releases"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 36,
"inputs": {
"source": "openssf_scorecard",
"checks_evaluated": 15,
"scorecard_version": "v5.5.0",
"checks_inconclusive": 3,
"scorecard_aggregate": 3.6
},
"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": "internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 7.5
},
{
"key": "ci_tests",
"name": "CI-Tests",
"detail": "6 out of 6 merged PRs checked by a CI test -- score normalized to 10",
"points": 2.5,
"status": "met",
"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/6 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "contributors",
"name": "Contributors",
"detail": "project has 1 contributing companies or organizations -- score normalized to 3",
"points": 0.8,
"status": "partial",
"details": [],
"max_points": 2.5
},
{
"key": "dangerous_workflow",
"name": "Dangerous-Workflow",
"detail": "no dangerous workflow patterns detected",
"points": 10,
"status": "met",
"details": [],
"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 30 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": "internal error: Client.Actions.ListWorkflowRunsByFileName: internal error: ListWorkflowRunsByFileName: GET https://api.github.com/repos/floor/vlist/actions/workflows/publish.yml/runs?status=success: 502 Server Error []",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 5
},
{
"key": "pinned_dependencies",
"name": "Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"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": "detected GitHub workflow tokens with excessive permissions",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "vulnerabilities",
"name": "Vulnerabilities",
"detail": "12 existing vulnerabilities detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
}
]
},
{
"key": "high_risk_jurisdiction_exposure",
"band": "excellent",
"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"
],
"review_only_matches": 0,
"assessed_self_published_locations": 2
},
"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": 64,
"weight": 0,
"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.97,
"agent_instruction_files": [
".claude/CLAUDE.md"
],
"agent_instruction_max_bytes": 12228
},
"components": [
{
"key": "agent_instructions",
"name": "Agent instructions",
"detail": ".claude/CLAUDE.md",
"points": 45,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": ".claude/CLAUDE.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": "97 of 100 human commits state their intent (structured subject or explanatory body)",
"points": 40,
"status": "met",
"details": [
{
"code": "legible_history",
"params": {
"legible": 97,
"sampled": 100
}
}
],
"max_points": 40
}
]
},
{
"key": "ai_verify_loop",
"band": "at_risk",
"name": "Verify loop (build / test / typecheck)",
"note": null,
"notes": [],
"value": 35,
"inputs": {
"has_nix": false,
"has_tests": true,
"lockfiles": [],
"has_dockerfile": false,
"typed_language": true,
"bootstrap_files": [],
"has_devcontainer": false,
"has_linter_config": false,
"typecheck_configs": [
"tsconfig.json"
],
"agent_commit_share": 0.01,
"toolchain_manifests": [],
"dependency_bot_commit_share": 0
},
"components": [
{
"key": "one_command_bootstrap",
"name": "One-command bootstrap",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"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": "tsconfig.json",
"points": 11,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "tsconfig.json"
}
}
],
"max_points": 11
},
{
"key": "reproducible_environment",
"name": "Reproducible environment",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
},
{
"key": "demonstrated_agent_practice",
"name": "Demonstrated agent practice",
"detail": "1 of the last 100 commits agent-authored or agent-credited",
"points": 2,
"status": "partial",
"details": [
{
"code": "agent_authored_commits",
"params": {
"count": 1,
"sampled": 100
}
}
],
"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": "dependency not pinned by hash detected -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "ai_code_legibility",
"band": "excellent",
"name": "Code legibility for models",
"note": null,
"notes": [],
"value": 98,
"inputs": {
"primary_language": "TypeScript",
"largest_source_bytes": 80649,
"source_files_sampled": 201,
"oversized_source_files": 7
},
"components": [
{
"key": "type_checkable_code",
"name": "Type-checkable code",
"detail": "TypeScript (statically typed)",
"points": 45,
"status": "met",
"details": [
{
"code": "statically_typed_language",
"params": {
"language": "TypeScript"
}
}
],
"max_points": 45
},
{
"key": "manageable_file_sizes",
"name": "Manageable file sizes",
"detail": "7/201 source files over 60KB",
"points": 53.1,
"status": "partial",
"details": [
{
"code": "oversized_source_files",
"params": {
"kb": 60,
"sampled": 201,
"oversized": 7
}
}
],
"max_points": 55
}
]
}
],
"description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
}
],
"metrics_version": "1.13.0"
},
"warnings": [
"Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
"No resolved dependencies carried a version and a supported ecosystem"
],
"report_type": "repository",
"generated_at": "2026-07-24T16:13:13.749583Z",
"schema_version": "0.27.0",
"badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/f/floor/vlist.svg",
"full_name": "floor/vlist",
"license_state": "standard",
"license_spdx": "MIT"
}