公开记录
软件健康报告模式 0.27.0 · 指标 1.13.0 · 2026-07-27 17:41 UTC

AxonWatch / axon-charts

A fast, lightweight candlestick chart library optimized for AI-driven applications and LLM integration

TypeScript · HTMLApache-2.0★ 1 星标⑂ 0 复刻始于 2026年5月在 GitHub 上查看 ↗

AxonWatch/axon-charts 的健康指数为 100 分中的 47 分,处于「存在风险」区间。 其得分最高的类别是Vitality(71/100),最低的是Sustainability & Governance(32/100)。 最近一次更新在 1 天前。 近期的大部分工作由 1 位贡献者完成。

47
总分 / 100
存在风险

软件健康指数

指标归入加权类别,统一采用 1–100 量表。总体分先取类别加权平均;当公开证据触发高风险司法辖区政策时,评级会按政策调整,并设置 49(有风险)的上限。AI 就绪度不计入总体分。

47
优秀85-100堪称典范;基本满足所有检验标准
良好70-84健康;仅有轻微不足
中等50-69可接受,但存在明显不足;建议进行审查
存在风险30-49存在重大薄弱环节;采用时应保持审慎
危急1-29问题严重(项目被弃置、仅有单一维护者、缺乏基本工程规范)
活力社区与采用可持续性与治理工程质量安全AI 就绪度

评分画像

每条轴代表一个类别。形状比平均值更重要——健康的对象会填满整个图形,而“一峰一谷”式画像意味着某一维度的优势正掩盖另一维度的风险。

所有权

AxonWatch组织
0 关注者1 个公开仓库始于 2026年5月

该仓库由组织支持——共同承担、可问责的托管责任,可延续于任何单一维护者之后。

软件包生态系统

注册表软件包版本月下载量版本数最近发布标签
npmaxon-charts1.5.91,477181 天前candlestickchartfinancialtradingcanvasllmaiaxonfintechchartingcandlestick-chartfinancial-charttrading-chartrealtime

按类别列示的指标

活力

项目是否仍有生命——是否仍在编写代码,是否仍在发布版本?

71良好 · 占总体的 22%
评分方式
36/36推送新近度 — 最近一次推送于 1 天前
6.2/36提交节奏 — 52 周中有 9 周有提交
18/18提交量 — 最近一年 196 次提交
0/10OpenSSF Scorecard:Maintained — project was created within the last 90 days. Please review its contents carefully
所用输入
commits_last_year196
human_commit_share1
days_since_last_push1
active_weeks_last_year9

发布纪律

88优秀
评分方式
16.2/27有发布版本 — 24 个版本标签(无 GitHub 发布版本)
36/36发布时效 — 最近一次发布版本于 6 天前
27/27发布节奏 — 约每 0.2 天发布一次
0/10OpenSSF Scorecard:Signed-Releases — 无数据
所用输入
releases_count24
latest_release_tagv1.5.8
releases_from_tags
days_since_latest_release6
mean_days_between_releases0.2
已排除计分(无数据或不适用):OpenSSF Scorecard:Signed-Releases。 其余权重已重新归一化。

社区与采用

项目是否拥有用户、下载量与关注度,并具备欢迎贡献者参与的配置?

38存在风险 · 占总体的 18%
评分方式
0/60星标 — 1 个星标
0/25复刻 — 0 个复刻
0/15关注者 — 0 位关注者
所用输入
forks0
stars1
watchers0
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history

社区健康

70良好
评分方式
22.5/22.5README
22.5/22.5许可证 — 可识别的许可证(Apache-2.0)
18/18CONTRIBUTING 指南
0/13.5行为准则
0/7.2议题模板
0/6.3PR 模板
所用输入
has_readme
has_license
has_contributing
has_issue_template
has_code_of_conduct
has_pull_request_template
评分方式
42.3/80月度下载量 — npm 合计每月 1,477 次下载
0/20注册表被依赖数 — 该生态系统不报告此项
所用输入
packagesaxon-charts
dependents
ecosystemsnpm
total_downloads
monthly_downloads1,477
已排除计分(无数据或不适用):注册表被依赖数。 其余权重已重新归一化。

可持续性与治理

项目能否在其成员之外延续——巴士系数、响应能力、由谁支持,以及软件包的维护状况?

32存在风险 · 占总体的 24%
评分方式
9/54巴士系数 — 1 位贡献者贡献了半数提交
0/22.5提交分布 — 头号贡献者编写了 100% 的提交
1.4/13.5贡献者广度 — 1 位贡献者
0/10OpenSSF Scorecard:Contributors — project has 0 contributing companies or organizations -- score normalized to 0
所用输入
bus_factor1
contributors_sampled1
top_contributor_share1
评分方式
0/46.8议题解决 — 没有议题或无数据
0/38.3PR 接受 — 没有已裁定的拉取请求或无数据
0/15OpenSSF Scorecard:Code-Review — Found 0/30 approved changesets -- score normalized to 0
所用输入
merged_prs0
open_issues0
closed_issues0
issue_closed_ratio
closed_unmerged_prs0
已排除计分(无数据或不适用):议题解决, PR 接受。 其余权重已重新归一化。
评分方式
30/30所有权背书 — 组织持有
0/20已验证域名
0/25所有者影响力 — AxonWatch 有 0 位关注者
2.6/25既往记录 — 1 个公开仓库,账户约 0 年
所用输入
followers0
owner_typeOrganization
is_verified
owner_loginAxonWatch
public_repos1
account_age_days83
评分方式
25/25已发布且可解析 — npm 上有 1 个软件包
35/35发布时效 — 最近一次发布于 1 天前
20/20版本历史 — 18 个已发布版本
20/20未被弃用 — 活跃,未被弃用或撤回
所用输入
packagesaxon-charts
ecosystemsnpm
any_deprecated
min_days_since_publish1

工程质量

基础的工程与文档实践是否到位?

54中等 · 占总体的 20%

工程实践

30存在风险
评分方式
24/24CI 工作流 — 1 个工作流
0/24存在测试
0/16Linter 配置
0/9.6Pre-commit 钩子
0/6.4.editorconfig
0/20OpenSSF Scorecard:CI-Tests — 无数据
所用输入
has_ci
has_tests
has_editorconfig
has_linter_config
has_precommit_config
已排除计分(无数据或不适用):OpenSSF Scorecard:CI-Tests。 其余权重已重新归一化。

文档

90优秀
评分方式
30/30README
25/25文档目录
15/15文档 / 主页站点 — https://axonwatch.github.io/axon-charts/
10/10仓库描述
0/10主题标签
10/10Wiki
所用输入
topics
has_wiki
homepagehttps://axonwatch.github.io/axon-charts/
has_readme
has_docs_dir
has_description

安全

可见的安全与供应链实践是否稳固,且不存在未解决的高风险司法辖区暴露?

38存在风险 · 占总体的 16%

安全态势

38存在风险
评分方式
7.5/7.5Binary-Artifacts — no binaries found in the repo
0/7.5Branch-Protection — branch protection not enabled on development/release branches
0/2.5CI-Tests — 无数据
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 0/30 approved changesets -- score normalized to 0
0/2.5Contributors — project has 0 contributing companies or organizations -- score normalized to 0
10/10Dangerous-Workflow — no dangerous workflow patterns detected
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5许可证 — license file detected
0/7.5Maintained — project was created within the last 90 days. Please review its contents carefully
0/5Packaging — 无数据
0/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
0/5SAST — no SAST tool detected
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — 无数据
7.5/7.5Token-Permissions — GitHub workflow tokens follow principle of least privilege
6.8/7.5Vulnerabilities — 1 existing vulnerabilities detected
所用输入
sourceopenssf_scorecard
checks_evaluated15
scorecard_versionv5.5.0
checks_inconclusive3
scorecard_aggregate3.8
已排除计分(无数据或不适用):ci_tests, packaging, signed_releases。 其余权重已重新归一化。

AI 就绪度

该仓库在多大程度上具备与 AI 编码代理协同开发与维护的条件?这是一枚独立的实验性徽章——权重为 0.0,因此单独呈现,不影响总体健康评分。

41存在风险 · 占总体的 0%
评分方式
0/45代理指令 — 没有 CLAUDE.md / AGENTS.md / 编辑器规则
0/15机器可读文档(llms.txt)
40/40可读的提交历史 — 100 次人类提交中有 100 次说明了意图(结构化标题或解释性正文)
所用输入
has_llms_txt
legible_history_share1
agent_instruction_files
agent_instruction_max_bytes
评分方式
0/18一条命令的引导启动
0/22自动化测试
0/11Lint / 格式化配置
11/11静态类型检查 — tsconfig.json
10/10可复现环境 — lockfile
0/10已体现的代理实践 — 最近 100 次提交中没有代理编写的提交
0/8自动化维护 — 未观察到自动依赖更新
0/10OpenSSF Scorecard:Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
所用输入
has_nix
has_tests
lockfilespackage-lock.json
has_dockerfile
typed_language
bootstrap_files
has_devcontainer
has_linter_config
typecheck_configstsconfig.json
agent_commit_share0
toolchain_manifests
dependency_bot_commit_share0
评分方式
45/45可类型检查的代码 — TypeScript(静态类型)
54.2/55可控的文件大小 — 采样的 68 个源文件中有 1 个超过 60KB
所用输入
primary_languageTypeScript
largest_source_bytes61,125
source_files_sampled68
oversized_source_files1

关键数据

1GitHub 星标
1贡献者
196最近 12 个月提交数
1距最近推送天数
24发布版本数
1巴士系数(bus factor)
0开放议题
npm软件包生态系统数

数据采集警告

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

更多细节

OpenSSF Scorecard 3.8 / 10
3.8综合

来自开源项目 OpenSSF Scorecard 的独立、工具无关的安全评估。每项检查奖励的是安全实践本身,而非特定供应商的工具。Scorecard 无法判定的检查项标记为 不适用,并从安全评分中剔除(绝不按零分计)。Scorecard v5.5.0 · 2026-07-27 17:41 UTC

10Binary-Artifactsno binaries found in the repo
0Branch-Protectionbranch protection not enabled on development/release branches
不适用CI-Testsno pull request found
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/30 approved changesets -- score normalized to 0
0Contributorsproject has 0 contributing companies or organizations -- score normalized to 0
10Dangerous-Workflowno dangerous workflow patterns detected
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
0Maintainedproject was created within the last 90 days. Please review its contents carefully
不适用Packagingpackaging workflow not detected
0Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 0
0SASTno SAST tool detected
0Security-Policysecurity policy file not detected
不适用Signed-Releasesno releases found
10Token-PermissionsGitHub workflow tokens follow principle of least privilege
9Vulnerabilities1 existing vulnerabilities detected
全部依赖 未采集

本报告未能采集到解析后的依赖集合:GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

原始 JSON 报告 机器可读
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 1773,
      "has_wiki": true,
      "homepage": "https://axonwatch.github.io/axon-charts/",
      "languages": {
        "HTML": 216840,
        "JavaScript": 1332,
        "TypeScript": 477182
      },
      "pushed_at": "2026-07-26T01:07:55Z",
      "created_at": "2026-05-22T14:37:00Z",
      "owner_type": "Organization",
      "updated_at": "2026-07-26T01:07:59Z",
      "description": "A fast, lightweight candlestick chart library optimized for AI-driven applications and LLM integration",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "Apache-2.0",
      "default_branch": "main",
      "license_spdx_raw": "Apache-2.0",
      "primary_language": "TypeScript",
      "significant_languages": [
        "TypeScript",
        "HTML"
      ]
    },
    "owner": {
      "blog": null,
      "name": null,
      "type": "Organization",
      "login": "AxonWatch",
      "company": null,
      "location": null,
      "followers": 0,
      "avatar_url": "https://avatars.githubusercontent.com/u/281991794?v=4",
      "created_at": "2026-05-05T15:52:58Z",
      "is_verified": null,
      "public_repos": 1,
      "account_age_days": 83
    },
    "license": {
      "state": "standard",
      "spdx_id": "Apache-2.0",
      "raw_spdx": "Apache-2.0",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v1.5.8",
          "kind": "patch",
          "published_at": "2026-07-21T17:40:09Z"
        },
        {
          "tag": "v1.5.7",
          "kind": "patch",
          "published_at": "2026-07-21T14:15:47Z"
        },
        {
          "tag": "v1.5.6",
          "kind": "patch",
          "published_at": "2026-07-21T12:33:51Z"
        },
        {
          "tag": "v1.5.5",
          "kind": "patch",
          "published_at": "2026-07-21T06:51:12Z"
        },
        {
          "tag": "v1.5.4",
          "kind": "patch",
          "published_at": "2026-07-20T19:49:20Z"
        },
        {
          "tag": "v1.5.3",
          "kind": "patch",
          "published_at": "2026-07-20T17:11:53Z"
        },
        {
          "tag": "v1.5.2",
          "kind": "patch",
          "published_at": "2026-07-20T16:31:06Z"
        },
        {
          "tag": "v1.5.1",
          "kind": "patch",
          "published_at": "2026-07-20T15:53:41Z"
        },
        {
          "tag": "v1.5.0",
          "kind": "minor",
          "published_at": "2026-07-20T11:08:32Z"
        },
        {
          "tag": "v1.4.1",
          "kind": "patch",
          "published_at": "2026-07-20T00:12:06Z"
        },
        {
          "tag": "v1.4.0",
          "kind": "minor",
          "published_at": "2026-07-19T23:27:22Z"
        },
        {
          "tag": "v1.3.0",
          "kind": "minor",
          "published_at": "2026-07-19T18:34:19Z"
        },
        {
          "tag": "v1.2.8",
          "kind": "patch",
          "published_at": "2026-06-24T17:32:10Z"
        },
        {
          "tag": "v1.2.7",
          "kind": "patch",
          "published_at": "2026-06-24T17:15:16Z"
        },
        {
          "tag": "v1.2.6",
          "kind": "patch",
          "published_at": "2026-06-24T14:36:41Z"
        },
        {
          "tag": "v1.2.5",
          "kind": "patch",
          "published_at": "2026-06-24T00:03:36Z"
        },
        {
          "tag": "v1.2.4",
          "kind": "patch",
          "published_at": "2026-06-23T11:15:52Z"
        },
        {
          "tag": "v1.2.3",
          "kind": "patch",
          "published_at": "2026-06-23T10:18:42Z"
        },
        {
          "tag": "v1.2.2",
          "kind": "patch",
          "published_at": "2026-05-25T18:46:28Z"
        },
        {
          "tag": "v1.2.1",
          "kind": "patch",
          "published_at": "2026-05-23T21:50:20Z"
        },
        {
          "tag": "v1.2.0",
          "kind": "minor",
          "published_at": "2026-05-19T23:51:49Z"
        },
        {
          "tag": "v1.1.1",
          "kind": "patch",
          "published_at": "2026-05-16T04:56:26Z"
        },
        {
          "tag": "v1.1.0",
          "kind": "minor",
          "published_at": "2026-05-14T21:49:22Z"
        },
        {
          "tag": "v1.0.0",
          "kind": "major",
          "published_at": "2026-05-05T05:54:47Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "69c285e3e4b08922717d5c0c97c29ac4e69a407f",
          "body": "- Version 1.5.8 → 1.5.9 in all md/html files\n- Banner reads 'Axon Charts v1.5.9'\n\nVerification:\n  - npm run build: clean (banner reads 'Axon Charts v1.5.9')\n  - npx tsc --noEmit: 0 errors",
          "is_bot": false,
          "headline": "release: v1.5.9 — version reference updates",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-26T01:00:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ec6a1885608fd0e1e8642c22883ee9e679a0b8ed",
          "body": "…warmup, tooltip perf, Ichimoku projection\n\nPatch release with 5 indicator fixes:\n\n  fix(indicators): Ichimoku cloud color respects A/B crossovers (Kumo twist)\n  fix(indicators): VWAP daily reset respects configured timezone\n  fix(indicators): Stochastic slow-%K no longer contaminated by NaN warmup\n\n[…]\ntip lookups\n  fix(indicators): Ichimoku leading cloud projects into right gap\n\nBundle: 41566 -> 41712 bytes gzipped (+146 bytes).\n\nVerification:\n  - npm run build: clean\n  - npx tsc --noEmit: 0 errors",
          "is_bot": false,
          "headline": "release: v1.5.9 — Ichimoku cloud coloring, VWAP timezone, Stochastic …",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-26T00:59:34Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "51a31ac0f3789f68b6f426890b358cd0e463b304",
          "body": "Senkou Span A and B are shifted forward by the displacement (default\n26 bars) — this is the defining feature of Ichimoku: the cloud (Kumo)\nextends into the future to show projected support/resistance. But the\nforward-shifted values were dropped when shiftedIdx >= data.length:\n\n  const shiftedIdx = i\n[…]\nno shiftedIdx < len check)\n    - render(): add cloudEndIdx from senkouA.length; use it for the cloud\n      segmentation loop and the Span A/B line drawing\n\nVerification:\n  - npx tsc --noEmit: 0 errors",
          "is_bot": false,
          "headline": "fix(indicators): Ichimoku leading cloud projects into right gap",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-26T00:58:25Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "490d1536a4fa83e745ae8686c105d943e869da47",
          "body": "All 8 indicator sub-panes (RSI, MACD, Stochastic, Williams %R, CCI,\nMFI, ATR, ADX) used Array.indexOf(bar) inside getTooltipValue() to\nfind the bar's index into the computed-values array. This method is\ncalled on every render via getHoveredValue() (which updates the\nsub-pane's current-value label) a\n[…]\nndex ?? indexOf(bar)\n  src/subpanes/ADXSubPane.ts:     barIndex ?? indexOf(bar)\n  src/subpanes/VolumeSubPane.ts:  signature conformance (_barIndex unused)\n\nVerification:\n  - npx tsc --noEmit: 0 errors",
          "is_bot": false,
          "headline": "fix(subpanes): eliminate O(n) indexOf in crosshair tooltip lookups",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-26T00:56:28Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ba43ad6701eec868f72030f1bbd8790adf3d7cef",
          "body": "The slow stochastic smoothing (smoothK > 1) replaced NaN raw-%K values\nwith 0 before passing them to sma():\n\n  const k = smoothK > 1\n    ? sma(rawK.map(v => isNaN(v) ? 0 : v), smoothK)\n        .map((v, i) => isNaN(rawK[i]) ? NaN : v)\n    : rawK;\n\nThe re-mask only hid the output at index i where rawK\n[…]\ny sum when all smoothK values are\nnon-NaN.\n\nFiles:\n  src/utils/indicators.ts:\n    - stochastic(): replace sma(zero-padded) with explicit valid-window loop\n\nVerification:\n  - npx tsc --noEmit: 0 errors",
          "is_bot": false,
          "headline": "fix(indicators): Stochastic slow-%K no longer contaminated by NaN warmup",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-26T00:53:39Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "71d592bae1bb66e0f4bdda02632a3894068cd34b",
          "body": "VWAP's daily reset was hardcoded to UTC midnight:\n\n  const day = Math.floor(bar.time / 86400000);\n\nThis split non-UTC trading sessions mid-session. A US equities trader\n(charting in EST/EDT) would see the VWAP line reset at 7-8 PM EST\ninstead of at the session boundary, invalidating all volume-weigh\n[…]\n/overlays/VWAPOverlay.ts:\n    - import PriceFormatter\n    - replace lastDay/UTC-floor with lastBarTime + isDifferentDay\n    - read tz once before the loop\n\nVerification:\n  - npx tsc --noEmit: 0 errors",
          "is_bot": false,
          "headline": "fix(indicators): VWAP daily reset respects configured timezone",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-26T00:53:01Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c0060b5a509a66acc95b370e79835f3dfa9b5144",
          "body": "…wist)\n\nThe entire visible cloud was tinted green or red based on a single\nmidpoint sample of Senkou Span A vs. Span B. When the two spans crossed\nwithin the visible range (a \"Kumo twist\"), the whole cloud flipped\ncolor abruptly instead of showing the transition.\n\nRoot cause: render() built one canv\n[…]\ns:\n  src/overlays/IchimokuCloudOverlay.ts:\n    - render(): replace single-path/single-color cloud with segmented fills\n    - add fillCloudSegment() helper\n\nVerification:\n  - npx tsc --noEmit: 0 errors",
          "is_bot": false,
          "headline": "fix(indicators): Ichimoku cloud color respects A/B crossovers (Kumo t…",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-26T00:52:03Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a5f248a7ad42e96bb32a730ac68eb61cf6f8ea9c",
          "body": "- Version 1.5.7 → 1.5.8 in all md/html files\n- v1.5.8 git tag created\n\nVerification:\n- npm run build: clean (banner reads 'Axon Charts v1.5.8')\n- npx tsc --noEmit: 0 errors",
          "is_bot": false,
          "headline": "release: v1.5.8 — version reference updates",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-21T17:40:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fe402b859007c05ffde57049cc4d4c1c4902cd5d",
          "body": "…l gap",
          "is_bot": false,
          "headline": "release: v1.5.8 — separator drag fix, distinct indicator colors, labe…",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-21T17:40:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5c16e43edcc37216e3a9beba20bd2561345749b4",
          "body": "…label gap\n\nFix three issues with sub-pane indicators:\n\n## 1. Separator drag resized the wrong pane (critical)\n\nWhen multiple sub-panes were stacked (e.g. RSI + Stochastic + Volume),\ndragging any separator always resized the FIRST sub-pane, not the one\nwhose separator was grabbed. Trying to resize t\n[…]\n    fallback color #f97316\nsrc/subpanes/ATRSubPane.ts:        fallback color #14b8a6\n\n## Verification\n- tsc --noEmit: 0 errors\n- npm run build: clean\n- Bundle gzipped: 41515 -> 41566 bytes (+51 bytes)",
          "is_bot": false,
          "headline": "fix(subpanes): separator drag resizes correct pane, distinct colors, …",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-21T17:40:01Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ded457652a6d1992ce8a8331d744d5e2c219991e",
          "body": "- Version 1.5.6 → 1.5.7 in all md/html files\n- Bundle size unchanged at 40.5KB (41515 bytes gzipped)\n- v1.5.7 git tag created\n\nVerification:\n- npm run build: clean (banner reads 'Axon Charts v1.5.7')\n- npx tsc --noEmit: 0 errors",
          "is_bot": false,
          "headline": "release: v1.5.7 — version reference updates",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-21T14:16:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8c0f1032a232a395747496cfe36f83123b7e346b",
          "body": "…t-side tooltip",
          "is_bot": false,
          "headline": "release: v1.5.7 — fix sub-pane labels, overlay alignment, remove righ…",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-21T14:15:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "dbd8694432c038bbd72cf024124f4cfc45f0df47",
          "body": "… + overlay alignment\n\nFix four issues with the indicator labels and tooltips:\n\n## 1. Sub-pane: remove unrequested right-side tooltip\nv1.5.6 accidentally added a right-aligned tooltip on each sub-pane.\nRemoved entirely — each sub-pane now shows only the top-left label.\n\n## 2. Sub-pane label: proper \n[…]\nwith colored value\n  - getOverlayLabel: returns structured object instead of string\n\n## Verification\n- tsc --noEmit: 0 errors\n- npm run build: clean\n- Bundle gzipped: 41313 -> 41515 bytes (+202 bytes)",
          "is_bot": false,
          "headline": "fix(indicators): remove right-side sub-pane tooltip, fix label format…",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-21T14:15:39Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "cad8b710b690c6d855530cff89eb65e494d07552",
          "body": "- Version 1.5.5 → 1.5.6 in all md/html files\n- Bundle size unchanged at 40.3KB (41313 bytes gzipped)\n- v1.5.6 git tag created\n\nVerification:\n- npm run build: clean (banner reads 'Axon Charts v1.5.6')\n- npx tsc --noEmit: 0 errors\n- Bundle: 41313 bytes gzipped (40.3KB)",
          "is_bot": false,
          "headline": "release: v1.5.6 — version reference updates",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-21T12:34:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7bde755110a04b8a989d1b946cf0b67713665777",
          "body": "…sub-pane tooltips",
          "is_bot": false,
          "headline": "release: v1.5.6 — fix overlay label names, current values in labels, …",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-21T12:33:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "22c5d69009bbcb66d9cc793d6b4668d0f1c69d28",
          "body": "…tips in own sub-pane\n\nFix three issues with indicator labels and tooltips:\n\n## 1. Overlay labels showed minified class names (V4, U4)\n\noverlay.constructor.name gets renamed by esbuild's minifier in\nproduction builds — 'SMAOverlay' becomes 'V4', 'EMAOverlay' becomes\n'U4', etc. The labels showed 'V4(\n[…]\nside its own pane (currentTop + 2)\n    instead of stacking all at the first sub-pane\n\n## Verification\n- tsc --noEmit: 0 errors\n- npm run build: clean\n- Bundle gzipped: 41226 -> 41313 bytes (+87 bytes)",
          "is_bot": false,
          "headline": "fix(indicators): proper overlay names, current values in labels, tool…",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-21T12:33:45Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "471f25165e3ab124dbbc6976fc8cdb22b9d0f867",
          "body": "- Version 1.5.4 → 1.5.5 in all md/html files\n- Bundle size 39.9KB → 40.3KB in README.md + html/index.html\n  (actual: 41226 bytes gzipped)\n- v1.5.5 git tag created\n\nVerification:\n- npm run build: clean (banner reads 'Axon Charts v1.5.5')\n- npx tsc --noEmit: 0 errors\n- Bundle: 41226 bytes gzipped (40.3KB)",
          "is_bot": false,
          "headline": "release: v1.5.5 — version reference updates",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-21T06:51:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b63f8bf1daf12075d29f3bd9aae3a5a551feb837",
          "body": "… clipping fix",
          "is_bot": false,
          "headline": "release: v1.5.5 — text wrapping/styling, label price display, drawing…",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-21T06:51:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f5fa8628986d2c1f411ffa53877f9e3a2c6bfe51",
          "body": "…drawing clipping to chart area\n\nFix two bugs and add text/label styling options:\n\n## Bug 1: Drawings visible in sub-pane area\nrenderDrawings() was not clipping to the main chart area, so\ndrawings (trendlines, boxes, text, etc.) rendered across sub-panes\n(RSI, MACD, Volume). Now clips to chartBottom\n[…]\nh the new fields\n\nCHANGELOG.md:\n  - [1.5.5] entry with Fixed/Added/Changed sections\n\n## Verification\n- tsc --noEmit: 0 errors\n- npm run build: clean\n- Bundle gzipped: 40885 -> 41226 bytes (+341 bytes)",
          "is_bot": false,
          "headline": "fix(drawings): text wrapping + styling options, label price display, …",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-21T06:51:01Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f2f6350e0a176c780958b4ea3f9a9747a1593b0f",
          "body": "Update all version references for the v1.5.4 release.\n\n- Version 1.5.3 → 1.5.4 in all md/html files\n- Bundle size 39.6KB → 39.9KB in README.md + html/index.html\n  (actual: 40885 bytes gzipped)\n- v1.5.4 git tag created\n\nVerification:\n- npm run build: clean (banner reads 'Axon Charts v1.5.4')\n- npx tsc --noEmit: 0 errors\n- Bundle: 40885 bytes gzipped (39.9KB)",
          "is_bot": false,
          "headline": "release: v1.5.4 — version reference updates",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T19:49:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "acadd62f115e3a7383554eec2202ef90c1f2eff1",
          "body": "… registry, resetState, migrateSnapshot",
          "is_bot": false,
          "headline": "release: v1.5.4 — drawings + overlays in saveState/loadState, overlay…",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T19:49:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f607c1c1d7fafaaa2b5adcddb5dd9523f1030709",
          "body": "… registry, resetState, migrateSnapshot\n\nClose four persistence gaps in the state serialization system.\nAll changes are additive — old 1.0.0 snapshots still load fine.\n\n## Request 1: Drawings in saveState/loadState\n\nsaveState() now captures this._drawings (already plain JSON objects).\nloadState() re\n[…]\n0 errors\n- npm run build: clean\n- Bundle gzipped: 40576 -> 40885 bytes (+309 bytes for the overlay\n  registry, migrateSnapshot, resetState, registerOverlayType, and\n  the extended saveState/loadState)",
          "is_bot": false,
          "headline": "fix(persistence): drawings + overlays in saveState/loadState, overlay…",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T19:49:06Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0d688c7f7ea1e634a8332a60de152da8aa061a99",
          "body": "Update all version references and CHANGELOG for the v1.5.3 release\n(indicator labels, context menu toggles, setIndicatorOptions API).\n\n- Version 1.5.2 → 1.5.3 in all md/html files\n- Bundle size 39.1KB → 39.6KB in README.md + html/index.html\n  (actual: 40576 bytes gzipped = 39.6KB)\n- CHANGELOG: new [\n[…]\nentry with Added/Changed sections\n- v1.5.3 git tag created\n\nVerification:\n- npm run build: clean (banner reads 'Axon Charts v1.5.3')\n- npx tsc --noEmit: 0 errors\n- Bundle: 40576 bytes gzipped (39.6KB)",
          "is_bot": false,
          "headline": "release: v1.5.3 — version reference updates",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T17:12:27Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d5c7f057b287f0de1d364070034e01e1d80befbd",
          "body": "…rOptions API",
          "is_bot": false,
          "headline": "release: v1.5.3 — indicator labels, context menu toggles, setIndicato…",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T17:11:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8346b87079dbaa30b5c56349b92eca73610225f9",
          "body": "…ptions API\n\nAdd three features that make indicators editable by the user and\nby the integrating app, without building a heavy settings UI that\nwould violate the library's minimal philosophy.\n\n## 1. On-chart indicator labels (canvas-rendered)\n\nEach active sub-pane now shows its name + key params in \n[…]\nys)\n\n## Verification\n- tsc --noEmit: 0 errors\n- npm run build: clean\n- Bundle gzipped: 39989 -> 40576 bytes (+587 bytes for the labels,\n  8 context menu entries, setIndicatorOptions, onIndicatorClick)",
          "is_bot": false,
          "headline": "fix(indicators): on-chart labels, context menu toggles, setIndicatorO…",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T17:11:46Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9166ce7167757df6fd0d0302cae83831ea71acef",
          "body": "Update all version references and CHANGELOG for the v1.5.2 release\n(negative-value sub-pane rendering fix for MACD, CCI, Williams %R).\n\n- Version 1.5.1 → 1.5.2 in all md/html files\n- Bundle size unchanged at 39.1KB (the fix was 6 bytes)\n- CHANGELOG: new [1.5.2] entry with the two bug descriptions\n- v1.5.2 git tag created\n\nVerification:\n- npm run build: clean (banner reads 'Axon Charts v1.5.2')\n- npx tsc --noEmit: 0 errors\n- Bundle: 39989 bytes gzipped (39.1KB)",
          "is_bot": false,
          "headline": "release: v1.5.2 — version reference updates",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T16:31:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8e7e0fd89d2f838cce62311cd82bccf097053d55",
          "body": "…illiams %R)",
          "is_bot": false,
          "headline": "release: v1.5.2 — fix negative-value sub-pane rendering (MACD, CCI, W…",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T16:31:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "286675e91d8c853768695bf5a792552f930bcdf7",
          "body": "…set)\n\nFix two bugs in the ScalePane base class that broke negative-value\nindicators (MACD, CCI, Williams %R). These were latent bugs in the\noriginal code (VolumeSubPane never triggered them because volume is\nalways positive), now exposed by the new negative-range indicators.\n\n## Bug 1 (critical): v\n[…]\nthreshold check\n\n## Verification\n- tsc --noEmit: 0 errors\n- npm run build: clean\n- Bundle gzipped: 39983 -> 39989 bytes (+6 bytes — the fix is a\n  one-character change in two places + a Math.abs call)",
          "is_bot": false,
          "headline": "fix(subpanes): negative values clipped by Math.max(getMinVisible, off…",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T16:30:55Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "36445bf993edbd150d84c4577a6b0afb85e72b21",
          "body": "Update all version references and CHANGELOG for the v1.5.1 release\n(getContext() fix exposing drawings, overlays, and sub-pane values).\n\n- Version 1.5.0 → 1.5.1 in README.md, docs/API.md, docs/SETTINGS.md,\n  docs/LLM.md, html/index.html, html/demo.html, html/docs.html\n- Bundle size 38.8KB → 39.1KB i\n[…]\nes gzipped)\n- CHANGELOG: Unreleased → [1.5.1] - 2026-07-20\n\nVerification:\n- npm run build: clean (banner reads 'Axon Charts v1.5.1')\n- npx tsc --noEmit: 0 errors\n- Bundle: 39983 bytes gzipped (39.1KB)",
          "is_bot": false,
          "headline": "release: v1.5.1 — version reference updates",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T15:54:19Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2013e6b6b986144d791542e0b0b04fc04c59d9c7",
          "body": "…etContext()",
          "is_bot": false,
          "headline": "release: v1.5.1 — expose drawings, overlays, and sub-pane values in g…",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T15:53:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c6cb47747e97bf14b0247674ab2833f3503d64fe",
          "body": "Update the documentation to reflect the three new data blocks\nexposed by getContext(): sub-pane indicator values, drawings, and\noverlays.\n\n## Changes\n\ndocs/LLM.md:\n  - Expanded the getContext() JSON example to include:\n    * subPanes with values + latestValue (RSI, MACD examples)\n    * drawings arra\n[…]\npanded the getContext() return shape to show the new fields:\n    subPanes with values/latestValue, drawings array, overlays object\n\nCHANGELOG.md:\n  - Unreleased section with the getContext() fix entry",
          "is_bot": false,
          "headline": "docs: update LLM.md + API.md for new getContext() structure",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T15:53:32Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0f30ee86d75a1196078ca890aa719e186d899ee9",
          "body": "…xt()\n\nFix three gaps in the LLM context (chart.getContext()) that meant\nAI agents couldn't see the full chart state:\n\n1. Drawings were not exposed at all — if the user drew a box,\n   trendline, or had open positions, the LLM had no way to see them.\n2. Overlays were not exposed — if the user added a\n[…]\nlooking at, not\n  the full dataset.\n\n## Verification\n- tsc --noEmit: 0 errors\n- npm run build: clean\n- Bundle gzipped: 39723 -> 39981 bytes (+258 bytes for the drawing/\n  overlay/value exposure logic)",
          "is_bot": false,
          "headline": "feat(llm): expose drawings, overlays, and sub-pane values in getConte…",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T11:17:53Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "97f28192485e1ee8c4009212ad62cb0f7ef3ad1e",
          "body": "Update all version references and CHANGELOG entry for the v1.5.0\nrelease (the actual version bump + git tag were done via\n'npm version minor' in the previous commit).\n\n## What this commit does\n\n- New [1.5.0] - 2026-07-20 entry in CHANGELOG covering all 9 commits:\n    * Indicators math utilities (13 \n[…]\nts v1.5.0')\n- npx tsc --noEmit: 0 errors\n- Bundle: 39723 bytes gzipped (38.8KB)\n- No stale 1.4.1 version references in any md/html file\n- v1.5.0 git tag created by 'npm version' in the previous commit",
          "is_bot": false,
          "headline": "release: v1.5.0 — version reference updates",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T11:09:13Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e8d7f3361594708b8c0d26eb1842ce162052387a",
          "body": "…cators math utils",
          "is_bot": false,
          "headline": "release: v1.5.0 — 8 sub-pane indicators + 4 overlay indicators + indi…",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T11:08:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "30e91e09011d29227c1f8b3f6cd01365c65a8c5c",
          "body": "Add the Ichimoku Cloud (Ichimoku Kinko Hyo) overlay indicator —\nthe most complex overlay, with 5 components and a filled cloud\nregion. This completes the overlay indicator set.\n\n## What it renders\n\nFive components on the main chart:\n  1. Tenkan-sen (Conversion Line): (9-period high + low) / 2 — blue\n[…]\nandsOverlay)\n\n## Verification\n- tsc --noEmit: 0 errors\n- npm run build: clean\n- Bundle gzipped: 39097 -> 39725 bytes (+628 bytes for the Ichimoku\n  overlay — the most complex indicator in the library)",
          "is_bot": false,
          "headline": "feat(overlays): Ichimoku Cloud overlay",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T11:08:26Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c6092fa8c190320c5d9805c3951f4baa145f2532",
          "body": "Add the VWAP (Volume Weighted Average Price) overlay indicator.\nRenders a single line on the main chart at the cumulative\nvolume-weighted average price, resetting at the start of each\ncalendar day by default.\n\n## What it renders\n\nA line at VWAP = cumulative(typicalPrice * volume) / cumulative(volume\n[…]\nack to typical price when volume is 0 (avoids division\n    by zero)\n\n## Verification\n- tsc --noEmit: 0 errors\n- npm run build: clean\n- Bundle gzipped: 38943 -> 39097 bytes (+154 bytes for VWAPOverlay)",
          "is_bot": false,
          "headline": "feat(overlays): VWAP overlay",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T11:07:40Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ca7a3427e07852e6a029a940c08b8d3ca5bcf607",
          "body": "Add the Bollinger Bands overlay indicator. Renders three lines on\nthe main chart (middle band = SMA, upper/lower = +/- numStdDev)\nplus an optional filled region between the bands.\n\n## What it renders\n\n  - Middle band: SMA(period) of the close — solid line\n  - Upper band:  middle + numStdDev * rollin\n[…]\nss as a template for custom overlays)\n\n## Verification\n- tsc --noEmit: 0 errors\n- npm run build: clean\n- Bundle gzipped: 38425 -> 38943 bytes (+518 bytes for BB overlay +\n  the rollingStdDev function)",
          "is_bot": false,
          "headline": "feat(overlays): Bollinger Bands overlay",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T11:06:54Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "133f93f1fb3bcb9bb60305443281e66202826def",
          "body": "Add the first two overlay indicators — Simple Moving Average and\nExponential Moving Average. Both draw a single line on the main\nchart on top of candles, using the main chart's price scale.\n\n## What they render\n\nA polyline connecting the indicator values for the visible bars,\nstarting at the first b\n[…]\nrs\n- npm run build: clean\n- Bundle gzipped: 38144 -> 38425 bytes (+281 bytes for LineOverlay +\n  SMAOverlay + EMAOverlay; the sma()/ema() functions were already\n  pulled in by the sub-pane indicators)",
          "is_bot": false,
          "headline": "feat(overlays): SMA + EMA overlay indicators",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T11:06:14Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "fa1d04217e072ad1253df0dec4d3ecad24120459",
          "body": "Add the Overlay plugin interface and the rendering infrastructure\nfor overlay indicators — indicators that draw on the main chart on\ntop of candles, sharing the main chart's price scale (Y-axis).\nExamples: SMA, EMA, Bollinger Bands, VWAP, Ichimoku Cloud.\n\nThis is the foundation for Phase 3 (the actu\n[…]\n Verification\n- tsc --noEmit: 0 errors\n- npm run build: clean\n- Bundle gzipped: 38004 -> 38144 bytes (+140 bytes for the Overlay\n  interface + overlay stack + renderOverlays + the 3 new Chart methods)",
          "is_bot": false,
          "headline": "feat(overlays): add overlay stack infrastructure",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T11:05:18Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a67801246f6a7c72070732604be5cf0a26d0b56d",
          "body": "Add the remaining 5 sub-pane indicators, completing the sub-pane\nindicator set. All follow the same ScalePane pattern established\nby RSI/MACD/Stochastic.\n\n## New sub-pane indicators\n\n  WilliamsRSubPane  — Williams %R oscillator (-100..0 range)\n                      Overbought -20, oversold -80 by de\n[…]\norts\n\n## Verification\n- tsc --noEmit: 0 errors\n- npm run build: clean\n- Bundle gzipped: 36941 -> 38004 bytes (+1063 bytes for the 5 new\n  sub-panes + the williamsR/cci/mfi/atr/adx functions pulled in)",
          "is_bot": false,
          "headline": "feat(indicators): Williams %R, CCI, MFI, ATR, ADX sub-panes",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T11:03:36Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "fec4bd6e9875de156300bf01b522588e810a7890",
          "body": "Add the Stochastic Oscillator sub-pane indicator. Renders two\nlines (%K and %D) in a separate sub-pane below the main chart, with\noverbought/oversold reference lines at 80/20 by default.\n\n## What it renders\n\n  - %K line (fast or slow depending on smoothK) — blue by default\n  - %D line (SMA of %K) — \n[…]\ntructor alongside RSI and MACD.\n\n## Verification\n- tsc --noEmit: 0 errors\n- npm run build: clean\n- Bundle gzipped: 36621 -> 36941 bytes (+320 bytes for\n  StochasticSubPane + the stochastic() function)",
          "is_bot": false,
          "headline": "feat(indicators): Stochastic Oscillator sub-pane",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T11:00:00Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "1b12b489510942be140c5e0cffba8beda16b589d",
          "body": "Add the MACD (Moving Average Convergence Divergence) sub-pane\nindicator. Renders three components in a separate sub-pane below\nthe main chart: MACD line, signal line, and histogram.\n\n## What it renders\n\n  - Histogram bars (MACD - Signal): green for positive, red for\n    negative, at 60% opacity so t\n[…]\nExport MACDSubPane\n\n## Verification\n- tsc --noEmit: 0 errors\n- npm run build: clean\n- Bundle gzipped: 36109 -> 36621 bytes (+512 bytes for MACDSubPane\n  + the macd() function + ema() helper pulled in)",
          "is_bot": false,
          "headline": "feat(indicators): MACD sub-pane",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T10:59:05Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b19521fefc82d90130281070ab05c882c7291658",
          "body": "Add the RSI (Relative Strength Index) sub-pane indicator — the\nmost popular oscillator. Renders as a 0-100 line in a separate\nsub-pane below the main chart, with overbought/oversold reference\nlines at 70/30 by default.\n\n## What it renders\n\n  - RSI line in a separate sub-pane (configurable color, def\n[…]\n- Export RSISubPane\n\n## Verification\n- tsc --noEmit: 0 errors\n- npm run build: clean\n- Bundle gzipped: 35442 -> 36109 bytes (+667 bytes for RSISubPane +\n  the rsi() function pulled in by tree-shaking)",
          "is_bot": false,
          "headline": "feat(indicators): RSI sub-pane",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T10:57:53Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f9a9b02fe3fd5be4cca8fabca947d5e7a361bb7e",
          "body": "Add a shared math utility module with the most common technical\nindicators, ready to be used by sub-pane indicators (RSI, MACD,\nStochastic, etc.) and overlay indicators (SMA, EMA, Bollinger\nBands, etc.).\n\n## Indicators implemented (all pure functions, no chart dependency)\n\n  sma(bars|values, period,\n[…]\nytes (+1591 bytes for the module\n  declaration + namespace export; the functions themselves are\n  tree-shaken out since no sub-pane imports them yet — they'll be\n  pulled in as each sub-pane is added)",
          "is_bot": false,
          "headline": "feat(indicators): add technical indicator math utilities",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T10:56:15Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "512e3437ff28b06bc7cbb00fb37cf03494add7c2",
          "body": "Update all version references and CHANGELOG entry for the v1.4.1\nrelease (the actual version bump + git tag were done via\n'npm version patch' in the previous commit).\n\n## What this commit does\n\n- New [1.4.1] - 2026-07-20 entry in CHANGELOG covering all 6 fix/feat\n  commits since v1.4.0:\n    * Fixed:\n[…]\nts v1.4.1')\n- npx tsc --noEmit: 0 errors\n- Bundle: 33852 bytes gzipped (33.1KB)\n- No stale 1.4.0 version references in any md/html file\n- v1.4.1 git tag created by 'npm version' in the previous commit",
          "is_bot": false,
          "headline": "release: v1.4.1 — version reference updates",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T04:46:48Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "7ef5c0fd30847a78e1b4ff23c2139cc29a663210",
          "body": null,
          "is_bot": false,
          "headline": "release: v1.4.1 — drawing interaction fixes + OHLC magnet mode",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T00:12:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e261e16b4da793e8c8ef66e907b221833eb97876",
          "body": "Replace the inline binary search in Renderer.previewTimeToX with a\ncall to this.chart.dataManager.getBarAtTime — the same method\nresolveAnchor uses. Removes ~12 lines of duplicated search logic\nand keeps a single source of truth for time→bar lookup.\n\nThe extrapolation fallback (when the time isn't f\n[…]\ne that's a preview-specific\nbehavior not shared with resolveAnchor.\n\n## Verification\n- tsc --noEmit: 0 errors\n- npm run build: clean\n- Bundle gzipped: 33901 -> 33851 bytes (-50 bytes, shrank slightly)",
          "is_bot": false,
          "headline": "refactor(drawings): reuse DataManager.getBarAtTime in preview",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T00:11:58Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4d37f7262f948b31eccc58b2cfa077f4b420bad4",
          "body": "Replace the (this.chart as any).drawingController accesses in\nEventManager with proper IChart methods (routeDrawingMouseDown /\nrouteDrawingMouseMove) so the access goes through the type-safe\ninterface instead of bypassing it with 'as any'.\n\n## Why\n\nThe previous commits used (this.chart as any).drawi\n[…]\nith this.chart.routeDrawingMouseMove(...)\n\n## Verification\n- tsc --noEmit: 0 errors\n- npm run build: clean\n- Bundle gzipped: 33880 -> 33901 bytes (+21 bytes for the two new\n  routing methods on Chart)",
          "is_bot": false,
          "headline": "refactor(drawings): clean drawing controller access via IChart",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T00:11:16Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "301cce23d4a1bf9acd7a708a10176cd5013ac98f",
          "body": "When chart.isDrawing() is true (drawing-creation mode active), set\nthe canvas cursor to 'crosshair' on mousemove. This signals to the\nuser that they're in placement mode and the next click will drop an\nanchor — the standard convention in charting tools.\n\nWithout this, the cursor stayed as 'crosshair\n[…]\nor = 'crosshair' after routing the\n    move to the drawing controller\n\n## Verification\n- tsc --noEmit: 0 errors\n- npm run build: clean\n- Bundle gzipped: unchanged (33880 bytes — one cursor assignment)",
          "is_bot": false,
          "headline": "feat(drawings): crosshair cursor in create mode",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T00:10:31Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "7330936f14cd7c08a1bd40c7a118c0335666e59c",
          "body": "Add a magnet mode for drawings that snaps anchor placement and\ndragging to the nearest Open, High, Low, or Close of the bar under\nthe cursor. Mirrors the existing crosshair magnet mode (which snaps\nto bar centers) but goes one step further: it snaps to the specific\nOHLC value closest to the cursor Y\n[…]\nr\n\n## Verification\n- tsc --noEmit: 0 errors\n- npm run build: clean\n- Bundle gzipped: 33634 -> 33880 bytes (+246 bytes for magnetToOHLC\n  + the option + setDrawingMagnet + the resolveWithMagnet wiring)",
          "is_bot": false,
          "headline": "feat(drawings): OHLC magnet mode for drawing anchors",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T00:09:58Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6bc0f32e5a2906f027dddff4be1f6f7c876c6fb3",
          "body": "The rubber-band preview during drawing-creation mode always drew a\nline from p1 to the cursor, regardless of the drawing type. So when\ncreating a box, the user saw a line while dragging, then the box\nappeared only after the second click — confusing and inconsistent\nwith every other charting tool.\n\nN\n[…]\n both anchors\n\n## Verification\n- tsc --noEmit: 0 errors\n- npm run build: clean\n- Bundle gzipped: 33422 -> 33634 bytes (+212 bytes for the shape\n  switch + getPreviewShape method + IChart/Chart wiring)",
          "is_bot": false,
          "headline": "fix(drawings): type-aware rubber-band preview (box shows a box)",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T00:07:31Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f7e7db78f54a7a83d9173959edef1418124edbb3",
          "body": "Fix four interaction-layer bugs that surfaced during testing:\n\n## Bug 1: Cursor overwritten by chart's cursor logic\n\nDrawingInteraction.onMouseMove() set the cursor when hovering a\ndrawing handle/body, but returned false — so EventManager's cursor\nlogic below it overwrote the cursor with 'crosshair'\n[…]\nections\n\n## Verification\n- tsc --noEmit: 0 errors\n- npm run build: clean\n- Bundle gzipped: 33365 -> 33422 bytes (+57 bytes for hoverActive\n  flag, isHovering/clearHover methods, and mouseleave wiring)",
          "is_bot": false,
          "headline": "fix(drawings): cursor overwrite, hover cleanup, arrow direction",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-20T00:06:16Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f1494fbbf216813534ca11ca4f04406b1c622653",
          "body": "Update all version references and CHANGELOG entry for the v1.4.0\nrelease (the actual version bump + git tag were done via\n'npm version minor' in the previous commit).\n\n## What this commit does\n\n- Convert the new work into a dated [1.4.0] entry (2026-07-20) in\n  the CHANGELOG, placed above [1.3.0]. F\n[…]\nts v1.4.0')\n- npx tsc --noEmit: 0 errors\n- Bundle: 33365 bytes gzipped (32.6KB)\n- No stale 1.3.0 version references in any md/html file\n- v1.4.0 git tag created by 'npm version' in the previous commit",
          "is_bot": false,
          "headline": "release: v1.4.0 — version reference updates",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-19T23:29:04Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "bf95463f206b7d51bbeaafc1d5e1f81844fea54a",
          "body": "… create-by-click, keyboard)",
          "is_bot": false,
          "headline": "release: v1.4.0 — interactive drawing system (hit-test, drag, resize,…",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-19T23:27:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "af0cecedd253d4496d319bb42819ae413c0a6cb2",
          "body": "Add the drawing-creation flow that lets users add drawings by\nclicking on the chart instead of calling chart.addDrawing()\nprogrammatically. This is the final piece that makes the drawing\nsystem actually usable as a drawing tool.\n\n## What it adds\n\n  chart.beginDrawing(type)  → enter create mode for t\n[…]\nfirst endpoint\n  // User moves mouse → dashed preview line follows\n  // User clicks again → commits the trendline, exits create mode\n\n  // Cancel mid-drawing (or press Escape)\n  chart.cancelDrawing();",
          "is_bot": false,
          "headline": "feat(drawings): add drawing-creation mode (click-to-create new drawings)",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-19T23:24:57Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "434b8bcd423d8ae182081c59488048b7452c9f0e",
          "body": "Add keyboard event handling for the drawing interaction layer:\n  Delete / Backspace — remove the currently selected drawing\n  Escape — cancel an in-progress drag, then clear the selection\n\n## Why\n\nWithout keyboard support, the only way to remove a drawing was to\ncall chart.removeDrawing(id) programm\n[…]\nteners, removed in destroy()\n\n## Verification\n- tsc --noEmit: 0 errors\n- npm run build: clean\n- Bundle gzipped: 32337 -> 32507 bytes (+170 bytes for the\n  handleKeyDown listener + Delete/Escape logic)",
          "is_bot": false,
          "headline": "feat(drawings): add Delete + Escape keyboard handling",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-19T23:21:56Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "53560279327fb730df70e89f2b47069ee5d57e8c",
          "body": "Fix the body-drag handler in DrawingInteraction so dragging the\nbody of a two-point drawing (trendline, box, measure, fib,\nhighlighter, position_closed) moves BOTH anchors by the same delta,\npreserving the drawing's shape. Previously body drag only worked for\nsingle-point drawings — two-point body d\n[…]\nate across\ndrag operations.\n\n## Verification\n- tsc --noEmit: 0 errors\n- npm run build: clean\n- Bundle gzipped: 32207 -> 32337 bytes (+130 bytes for the start\n  state capture + delta computation logic)",
          "is_bot": false,
          "headline": "feat(drawings): support two-point body drag (move whole drawing)",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-19T23:21:07Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2604dc35e5dc8a2ee4fd539313c01126c56a408e",
          "body": "Add hitTest() and getHandles() to every drawing renderer so they\nbecome interactive: draggable, resizable, and selectable. This is\nphase 2b of the interactive drawing system — combined with the\ndispatcher from the previous commit, drawings are now fully\ndraggable on the chart.\n\nAlso adds handle + se\n[…]\nimplementations + handle rendering in\n  Renderer.renderDrawings + pointToSegmentDistance helpers)\n- All 14 drawing types now respond to mousedown on their handles\n  and can be dragged around the chart",
          "is_bot": false,
          "headline": "feat(drawings): implement hitTest + getHandles for all 14 drawing types",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-19T23:19:43Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "fb55be5c9b994a27ce26c25edd89cb2c4671ee0c",
          "body": "…outing\n\nAdd the central DrawingInteraction module that EventManager delegates\nto on mousedown/mousemove/mouseup. This is phase 2a of the interactive\ndrawing system — it routes events to drawings, manages drag state,\nand updates drawing anchors in place via chart.updateDrawing().\n\nPer-type hitTest/g\n[…]\ndrag to move)\n  - position_closed: 2 endpoint handles\n  - highlighter: 2 edge handles + body\n  - arrow_up/down/label/text: 1 body handle\n\nEach renderer adds ~20-40 lines. Bundle impact: ~+1.5KB total.",
          "is_bot": false,
          "headline": "feat(drawings): add interaction dispatcher for hit-testing and drag r…",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-19T20:19:10Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "50ccb4496613bdd59dcc727dea7174141f2418c3",
          "body": "…eenToAnchor\n\nAdd the missing core that the drawing system needs to be interactive:\nthe hit-testing + drag-handle contract on DrawingRenderer, the inverse\ncoordinate mapper (screenToAnchor), and the chart-side selection state\n(selectedDrawingId, updateDrawing, selectDrawing).\n\nThis is phase 1 of the\n[…]\n 30400 -> 30550 bytes (+150 bytes for the new\n  interface types, screenToAnchor, and the 3 new Chart methods)\n- No behavior change for existing drawings (the new methods are all\n  optional / additive)",
          "is_bot": false,
          "headline": "feat(drawings): add interaction foundation — hitTest, getHandles, scr…",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-19T20:16:41Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "977f9a7cd880e16195f28fd182af6146a520450d",
          "body": "Update all version references and CHANGELOG entry for the v1.3.0\nrelease (the actual version bump + git tag were done via\n'npm version minor' in the previous commit).\n\n## What this commit does\n\n- Convert the CHANGELOG 'Unreleased' section into a dated [1.3.0]\n  entry (2026-07-19). The content is unc\n[…]\nts v1.3.0')\n- npx tsc --noEmit: 0 errors\n- Bundle: 30400 bytes gzipped (29.7KB)\n- No stale 1.2.x version references in any md/html file\n- v1.3.0 git tag created by 'npm version' in the previous commit",
          "is_bot": false,
          "headline": "release: v1.3.0 — version reference updates",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-19T18:36:38Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4fed7e4f11cc4809b1fc9f9d04fc4443e69b4865",
          "body": "…(9 new drawing types)",
          "is_bot": false,
          "headline": "release: v1.3.0 — onCandleClose callback + extensible drawing system …",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-19T18:34:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6ec2ee8db5f4ac04159ef2dca6539d23e154d400",
          "body": "Add a new 'position_closed' drawing type that visualizes a closed\ntrade with entry + exit markers, a connector line, and a fixed\nrealized PnL label. Complements the 'position' drawing type:\n  - position        = open trade with live unrealized PnL\n  - position_closed = closed trade with entry+exit a\n[…]\nme2: 1704153600000, price2: 42850.0,\n    color: '#3b82f6',\n    data: { side: 'long', qty: 0.5 }\n  });\n  // → renders entry circle + exit square + connector + realized\n  //   PnL label '+350.0' (green)",
          "is_bot": false,
          "headline": "feat: add position_closed drawing type for closed trades",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-19T18:21:05Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6d3cfb88d9cc659f54f7d07f1816baf2382a6c86",
          "body": "Add a new 'highlighter' drawing type that renders a vertical band\nspanning the full chart height between two time anchors. Common\nuses: earnings windows, news event periods, session ranges (London\nopen, NY open), marking a specific bar range for attention.\n\n## What it renders\n\nA filled rectangle fro\n[…]\n200000,         // window start\n    time2: 1704153600000,         // window end\n    color: '#f59e0b',\n    text: 'Earnings Q3',\n    data: { fill: 'rgba(245, 158, 11, 0.10)', lineStyle: 'dashed' }\n  });",
          "is_bot": false,
          "headline": "feat: add highlighter drawing type for vertical time bands",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-19T18:18:41Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ea5b999c525fa799811c3db5b9fc107cb36b7b01",
          "body": "Add a new 'text' drawing type for multi-line freeform text annotations.\nDistinct from the simpler 'label' type (single-line, fixed 16px box,\ncentered on anchor): 'text' accepts an array of lines, sizes the box\nto content, and anchors at the top-left with auto-flip when the box\nwould overflow the rig\n[…]\n 158, 11, 0.10)'\n    }\n  });\n\n  // Single-line convenience\n  chart.addDrawing({\n    id: 'note-2', type: 'text',\n    time: 1704153600000, price: 41800, color: '#3b82f6',\n    text: 'Support level'\n  });",
          "is_bot": false,
          "headline": "feat: add text drawing type for multi-line annotations",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-19T18:17:04Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "135fe4c942e119c8688060eecd4a2a8ed206d6b6",
          "body": "Add a new 'order' drawing type that visualizes a resting order on\nthe chart. Complements the 'position' drawing — where 'position'\nshows a filled trade with live PnL, 'order' shows a pending order\nthat hasn't filled yet (no entry marker, no PnL).\n\n## What it renders\n\n  (a) Dashed horizontal line at \n[…]\noveDrawing('ord-1');\n  chart.addDrawing({\n    id: 'pos-1', type: 'position',\n    time: 1704067200000, price: 42150.5, color: '#3b82f6',\n    data: { side: 'long', qty: 0.5, sl: 41800, tp: 43000 }\n  });",
          "is_bot": false,
          "headline": "feat: add order drawing type for pending limit/stop orders",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-19T18:14:47Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "015afa9a0bd6e8364da860a820bd274922018e49",
          "body": "Add a 2-point measurement annotation — the 'drag to measure' tool.\nDraws a connector line between two anchor points with endpoint\nmarkers and a label showing the price delta, percentage change, and\nbar count between them.\n\n## What it renders\n\n  (a) Connector line between the two anchors (color/lineS\n[…]\n 1704067200000, price: 42150,\n    time2: 1704153600000, price2: 42850,\n    color: '#3b82f6',\n    data: { lineStyle: 'dashed' }\n  });\n  // → renders '+700.0  (+1.66%)' / '10 bars' label near 2nd anchor",
          "is_bot": false,
          "headline": "feat: add measure drawing type",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-19T18:10:06Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "445181722d9135ace6695aa7df1bdbd3d82d4d8a",
          "body": "Add Fibonacci retracement levels — the most-requested indicator\ndrawing. Draws 7 horizontal levels (0%, 23.6%, 38.2%, 50%, 61.8%,\n78.6%, 100%) between a swing's two anchor points, each with a\nright-axis price label.\n\n## What it renders\n\nFor a swing defined by two anchors (start, end), the renderer d\n[…]\n:  1704067200000, price: 41800,   // swing low (start)\n    time2: 1704153600000, price: 42900,   // swing high (end)\n    color: '#3b82f6',\n    text: 'Fib Retracement',\n    data: { lineWidth: 1 }\n  });",
          "is_bot": false,
          "headline": "feat: add fib_retracement drawing type",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-19T18:08:07Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "084e185cad54ebd7858842188314b9299fe72843",
          "body": "Add a 2-point rectangle drawing for trading ranges, supply/demand\nzones, pattern completion zones, and highlight regions. Reuses the\n2-anchor pattern established by TrendlineRenderer.\n\n## What it renders\n\nA rectangle between two opposite-corner anchor points. The renderer\nnormalizes the corners (lef\n[…]\nbox',\n    time: 1704067200000, price: 42800,\n    time2: 1704153600000, price2: 42100,\n    color: '#ef4444',\n    text: 'Supply',\n    data: { fill: 'rgba(239, 68, 68, 0.12)', lineStyle: 'dashed' }\n  });",
          "is_bot": false,
          "headline": "feat: add box drawing type",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-19T18:06:18Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4b305554550c3b6260dc252d6d445156317c6183",
          "body": "Add a 2-point trendline drawing — the most-used drawing in technical\nanalysis. Establishes the 2-anchor pattern that box, fib_retracement,\nand measure will reuse.\n\n## What it renders\n\nA straight line between two anchor points on the chart, with optional\nextension beyond the anchors and an optional e\n[…]\nline',\n    time: 1704067200000, price: 42150,\n    time2: 1704153600000, price2: 42500,\n    color: '#3b82f6',\n    text: 'Support',\n    data: { extend: 'right', lineStyle: 'dashed', lineWidth: 1 }\n  });",
          "is_bot": false,
          "headline": "feat: add trendline drawing type",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-19T18:04:53Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "58dd1f5d5c807d14cde737a499ed158b3180074a",
          "body": "Add a new 'position' drawing type that renders a trading position on\nthe chart with live unrealized PnL and optional stop-loss / take-profit\nlines. This is the first drawing type built on the new plugin registry\nestablished in the previous three commits — it required zero changes\nto Renderer, Chart,\n[…]\nll future\ndrawing types: trendline, box, fib, brush, pitchfork, measure, etc.\nEach will be a single new file under src/drawings/ plus one registry\nline — no core changes, no risk to existing behavior.",
          "is_bot": false,
          "headline": "feat: add position drawing with live PnL, SL/TP lines",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-19T17:57:27Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "68b6dc8458e3edd299cfa23edbfadd6ef8522d21",
          "body": "Update all documentation to reflect the new plugin-based drawing\narchitecture: extended Drawing interface, DrawingData payload,\nregisterDrawingType() for custom types, resolveAnchor() helper, and\nthe extracted built-in renderers.\n\n## Changes\n\ndocs/API.md:\n- Drawing API section rewritten:\n  * Added c\n[…]\nstyle helpers\n  extraction, plugin registry, interface extension + validation)\n\n## Verification\n- tsc --noEmit: 0 errors (docs-only commit, no source changes)\n- npm run build: clean (no bundle change)",
          "is_bot": false,
          "headline": "docs: document the extensible drawing system",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-19T17:55:07Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "36e2aa5e50240cb8ff45ffbc20664be06a1796ed",
          "body": "Restructure the Drawing interface to support multi-anchor drawings\n(trendline, box — future) and a typed data bag for type-specific\npayloads (position side/qty/sl/tp, line width/style, fill, etc.).\nAdd validateDrawing() and expose registerDrawingType() on the Chart\nclass so external apps can add cus\n[…]\nd: clean\n- Bundle gzipped: 26878 → 27488 bytes (+610 bytes for validateDrawing,\n  DrawingData interface, registerDrawingType wiring)\n- registerDrawingType and drawing.data validation present in bundle",
          "is_bot": false,
          "headline": "refactor: extend Drawing interface for extensible drawing types",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-19T17:53:28Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "876075b9482d248e5a309a53bb0649f7b23989ae",
          "body": "Move the five built-in drawing types (arrow_up, arrow_down, label,\nhline, vline) out of Renderer.renderDrawings() into a per-type plugin\narchitecture under src/drawings/. This mirrors the existing\nSeriesRenderer plugin pattern used for series types (candlestick,\nline, area, bar, heiken-ashi, hollow)\n[…]\ns (+169 bytes for the registry,\n  4 renderer classes, interface, and anchor helper)\n- Registry keys (arrow_up, arrow_down, label, hline, vline) present\n  in bundle; chartBottomEdge inlined by minifier",
          "is_bot": false,
          "headline": "refactor: extract drawing renderers to plugin registry",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-19T17:51:46Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "44c1d34bd80fa901f36babc24bb450b989c806eb",
          "body": "Move hexToRgba() and NAMED_COLORS out of Renderer into a new shared\nmodule src/utils/style.ts so they can be reused by the upcoming\ndrawing renderer plugins (and any future module that needs the same\ncolor parsing).\n\n## Why\n\nThe drawing system refactor (next commits) introduces per-type\ndrawing rend\n[…]\n is inlined by the\n  minifier; chartBottomEdge/clampYToChartArea are tree-shaken out\n  since nothing uses them yet)\n- No public API change\n- No behavior change (color parsing fallback chain preserved)",
          "is_bot": false,
          "headline": "refactor: extract color/style helpers to shared util module",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-19T17:49:51Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f1bb1d152311cb1f4941a1c7a23a33823d5904ad",
          "body": "Add a new callback that fires exactly once per actual candle close,\ncomplementing the existing onDataUpdate (which fires on every tick\nand is too noisy for candle-close semantics).\n\n## Implementation\n\nSource (src/):\n- types/index.ts: New CandleCloseCallback type, new onCandleClose\n  option in ChartO\n[…]\n+ integration example.\n- html/docs.html: Options listing entry.\n- README.md: Events API surface.\n- CHANGELOG.md: Unreleased section entry.\n\nNo version bump (more features pending before next release).",
          "is_bot": false,
          "headline": "feat: add onCandleClose callback for candle-close events",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-07-19T17:35:54Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0f07891f4559f2046759349b5967a502b81daa2e",
          "body": null,
          "is_bot": false,
          "headline": "docs: update version references to v1.2.8 and CHANGELOG",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-06-24T17:34:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c772ad8ba943054f07b363b8085945609b98eaa6",
          "body": null,
          "is_bot": false,
          "headline": "fix: separator cursor only shows when sub-panes exist (v1.2.8)",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-06-24T17:32:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9ce13a945258a010da7b3f8d8fb72e05c44d2c62",
          "body": "The ns-resize cursor was appearing near the chart/time-axis boundary\neven when no sub-panes were active. isNearSeparator checked distance\nto chartBottomEdge without verifying that sub-panes actually exist.\n\nReplace with separatorHovered, which is computed by iterating\ngetActiveSubPanes() and only returns true near real separators.\nThis also fixes a latent issue where separators between multiple\nsub-panes didn't show the resize cursor (only the first one did).",
          "is_bot": false,
          "headline": "fix: separator cursor only shows when sub-panes exist",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-06-24T17:31:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "db29230de51533a035a5564aaa86ca7a11eb32f1",
          "body": null,
          "is_bot": false,
          "headline": "docs: update version references to v1.2.7 and CHANGELOG",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-06-24T17:16:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6b25e2c67d6fa219a4f5063d2a3ea8eca40ca1d6",
          "body": null,
          "is_bot": false,
          "headline": "fix: correct center preservation on resize (v1.2.7)",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-06-24T17:15:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fdc8343a7467896a49cdf6de73368ab384683f7a",
          "body": "The preserve-center resize path computed the center bar index using the\nNEW width's center pixel instead of the OLD width's center. When the\nchart was resized while in non-autoscroll mode (user had panned), the\ncentered candle shifted away from where the user was looking.\n\nCapture oldCenterX from ol\n[…]\ntent old coordinate system\n(old center pixel + old barWidth + old offsetX) to find the bar the\nuser was actually viewing, which is then re-centered at the new\nviewport center with the scaled barWidth.",
          "is_bot": false,
          "headline": "fix: use old width center for preserve-center resize calculation",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-06-24T17:11:46Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "12630318110783a25241313cc2cf56c86e62b448",
          "body": null,
          "is_bot": false,
          "headline": "docs: update version references to v1.2.6 and CHANGELOG",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-06-24T14:37:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "18e2eda2858a5f83ad8a4218d79bd091f647de5f",
          "body": null,
          "is_bot": false,
          "headline": "fix: preserve-center resize + crosshair label + separator hover (v1.2.6)",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-06-24T14:36:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3ad032dd097c8017836598aa7a2f45d060a71867",
          "body": "The separator hover check only verified mouseX >= 0 (left bound) but\nnot mouseX <= chart width (right bound). When the cursor was to the\nright of the chart area at the separator's Y position, the separator\nincorrectly highlighted.\n\nAdded mouseX <= this.chart.state.w to the condition so hover only\ntriggers when the cursor is horizontally within the chart canvas.",
          "is_bot": false,
          "headline": "fix: bound separator hover check to chart width",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-06-24T14:35:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4200ebbf7f9996a4003edb4820b191baf7767c4b",
          "body": "The time label was centered at the crosshair X position, causing it to\nclip at the left edge (x < ~60px) and right edge (x > chartAreaWidth -\n~60px). The label is now clamped to stay within [2, chartAreaWidth -\nboxWidth - 2], with text following the adjusted box position.\n\nThe crosshair vertical line stays at the actual cursor position — only\nthe label repositions for visibility. Narrow charts center the label\nas best effort.",
          "is_bot": false,
          "headline": "fix: clamp time axis crosshair label to visible chart area",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-06-24T14:35:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fe288812d41e94a724e134c887db62b590fa582e",
          "body": "The preserve-center resize path broke after v1.2.3's proportional\nbarWidth scaling. xToIndex was called with NEW barWidth but OLD\noffsetX, mixing coordinate systems and producing a wrong center index.\n\nPre-compute preservedCenterIdx before barWidth is scaled, when both\nbarWidth and offsetX are still old values. The saved index is then\nused in the preserve-center branch with the scaled barWidth.\n\nAuto-scroll path unchanged — it never mixed coordinate systems.",
          "is_bot": false,
          "headline": "fix: pre-compute center index before barWidth scaling in resize",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-06-24T13:43:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f7a83b444cd64d23dc5eadfe43f93941eca8fbe5",
          "body": null,
          "is_bot": false,
          "headline": "docs: update version references to v1.2.5 and CHANGELOG",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-06-24T00:04:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "01dd7ac11172601c76846a2eeea2abb7e4d5ca42",
          "body": null,
          "is_bot": false,
          "headline": "fix: guard barWidth scaling against degenerate sizes (v1.2.5)",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-06-24T00:03:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4d22c5289776d918057167aa3bca72617d767191",
          "body": "The proportional barWidth scaling (v1.2.3+) corrupted zoom when resize()\nwas called with degenerate sizes (e.g., 1x1 from detached containers).\nA round-trip 300→1→300 left barWidth clamped at maxBarSpacing (1000),\neffectively max-zooming the chart.\n\nGuard now requires both oldWidth and newWidth >= 5\n[…]\n0px, the chart is in transition, detached, or unusable — none\nof which should permanently alter the zoom level. State.w update stays\noutside the guard so state remains truthful during skipped scaling.",
          "is_bot": false,
          "headline": "fix: guard barWidth scaling against degenerate resize sizes",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-06-24T00:03:21Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "58539839f592f6c9817743080b074b3d80c869d2",
          "body": null,
          "is_bot": false,
          "headline": "docs: update version references to v1.2.4 and CHANGELOG",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-06-23T11:17:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9d77241eabe67d9c47fa2ffaa1fb4a0f6298452d",
          "body": null,
          "is_bot": false,
          "headline": "fix: buffer height resize + dynamic version loading (v1.2.4)",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-06-23T11:15:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e1511e5fade82b1b8d1074f2b16c2fed86923852",
          "body": "Buffer was not recreated when only chart height changed (width stayed\nthe same), causing candles to render into a stale-height buffer and\nappear invisible or distorted beyond a height threshold.\n\nAdded currentBufferHeight check to the reuse condition so the buffer\nis properly resized when height changes beyond the threshold.",
          "is_bot": false,
          "headline": "fix: check buffer height in createBuffer reuse logic",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-06-23T11:13:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "baef63c6d3a86efeaba11b67c4a89080c864c010",
          "body": "Replace hardcoded version strings with dynamic reads from package.json,\nensuring version consistency across build banner, global registry, and\ngetContext() API. Version is now never manually updated in source files.\n\n- Create src/version.ts as single source of truth\n- Update src/index.ts global registry to use LIB_VERSION\n- Update src/core/chart.ts getContext() to use LIB_VERSION\n- Update esbuild.config.js to read version from package.json at build time",
          "is_bot": false,
          "headline": "refactor: dynamic version loading from package.json",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-06-23T11:12:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a7831e53c68d0f8604accc94252868ebf4f9befb",
          "body": null,
          "is_bot": false,
          "headline": "docs: update CHANGELOG for v1.2.3",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-06-23T10:21:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "34f7098064d14c275b1f3cb1ba4a0260316a265b",
          "body": "Candles now scale proportionally when chart is resized,\npreventing them from appearing cut at chart edges.",
          "is_bot": false,
          "headline": "fix: barWidth scaling on resize (v1.2.3)",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-06-23T10:18:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "143cacd6b4a602ef6c38847928ae29ea4ee70509",
          "body": "Candles now scale proportionally when the chart is resized,\npreserving the visible range and preventing them from appearing\ncut at chart edges. Respects minBarSpacing/maxBarSpacing limits.",
          "is_bot": false,
          "headline": "fix: scale barWidth on resize to prevent cut candles",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-06-23T10:16:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9ac19f7cd5154014f99d6c51374bebc2db741338",
          "body": null,
          "is_bot": false,
          "headline": "docs: update CHANGELOG for v1.2.2",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-05-25T18:51:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c7eae95cf9749e45ee4dbf93d36073f14b74e740",
          "body": null,
          "is_bot": false,
          "headline": "fix: crosshair virtual time projection (v1.2.2)",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-05-25T18:46:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9047c30815dec9d102275c43c0d9223ce4280430",
          "body": null,
          "is_bot": false,
          "headline": "fix: crosshair virtual time for empty chart areas",
          "author_name": "sithon.eth",
          "author_login": "sithon-eth",
          "committed_at": "2026-05-25T18:44:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        }
      ],
      "releases_count": 24,
      "commits_last_year": 196,
      "latest_release_at": "2026-07-21T17:40:09Z",
      "latest_release_tag": "v1.5.8",
      "releases_from_tags": true,
      "days_since_last_push": 1,
      "active_weeks_last_year": 9,
      "days_since_latest_release": 6,
      "mean_days_between_releases": 0.2
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": true,
      "health_percentage": 62,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "axon-charts",
          "exists": true,
          "license": "Apache-2.0",
          "keywords": [
            "candlestick",
            "chart",
            "financial",
            "trading",
            "canvas",
            "llm",
            "ai",
            "axon",
            "fintech",
            "charting",
            "candlestick-chart",
            "financial-chart",
            "trading-chart",
            "realtime"
          ],
          "ecosystem": "npm",
          "matches_repo": true,
          "registry_url": "https://www.npmjs.com/package/axon-charts",
          "is_deprecated": false,
          "latest_version": "1.5.9",
          "repository_url": "https://github.com/AxonWatch/axon-charts",
          "versions_count": 18,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": 1,
          "monthly_downloads": 1477,
          "first_published_at": "2026-05-22T14:50:49.226000Z",
          "latest_published_at": "2026-07-26T01:07:43.838000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 1
        }
      ]
    },
    "popularity": {
      "forks": 0,
      "stars": 1,
      "watchers": 0,
      "fork_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_forks": 0
      },
      "star_history": null,
      "open_issues_and_prs": 0
    },
    "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": 61125,
      "source_files_sampled": 68,
      "oversized_source_files": 1,
      "agent_instruction_files": [],
      "agent_instruction_max_bytes": null
    },
    "dependencies": {
      "manifests": [
        "package.json"
      ],
      "advisories": {
        "error": null,
        "scope": null,
        "source": null,
        "findings": [],
        "collected": false,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 0,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "npm"
      ],
      "dependencies": [],
      "all_dependencies": {
        "error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
        "source": null,
        "packages": [],
        "collected": false,
        "truncated": false,
        "total_count": null,
        "direct_count": null,
        "indirect_count": null
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 0,
        "open_issues": 0,
        "closed_ratio": null,
        "closed_issues": 0,
        "closed_unmerged_prs": 0
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "sithon-eth",
          "commits": 196,
          "avatar_url": "https://avatars.githubusercontent.com/u/183833645?v=4"
        }
      ],
      "contributors_sampled": 1,
      "top_contributor_share": 1
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": false,
      "ci_workflows": [
        "static.yaml"
      ],
      "has_docs_dir": true,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": false,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [
        "package-lock.json"
      ],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 10,
            "reason": "no binaries found in the repo",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 0,
            "reason": "branch protection not enabled on development/release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": null,
            "reason": "no pull request found",
            "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/30 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 0,
            "reason": "project has 0 contributing companies or organizations -- score normalized to 0",
            "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": 0,
            "reason": "project was created within the last 90 days. Please review its contents carefully",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": null,
            "reason": "packaging workflow not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": 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": "no SAST tool detected",
            "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": 10,
            "reason": "GitHub workflow tokens follow principle of least privilege",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 9,
            "reason": "1 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "69c285e3e4b08922717d5c0c97c29ac4e69a407f",
        "ran_at": "2026-07-27T17:41:49Z",
        "aggregate_score": 3.8,
        "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-26T01:08:12Z",
      "oldest_open_prs": [],
      "last_merged_pr_at": null,
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": []
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/AxonWatch/axon-charts",
    "host": "github.com",
    "name": "axon-charts",
    "owner": "AxonWatch"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "at_risk",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 47,
      "inputs": {
        "security": 38,
        "vitality": 71,
        "community": 38,
        "governance": 32,
        "engineering": 54
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 71,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "moderate",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 60,
            "inputs": {
              "commits_last_year": 196,
              "human_commit_share": 1,
              "days_since_last_push": 1,
              "active_weeks_last_year": 9
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 1 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 1
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "9/52 weeks with commits",
                "points": 6.2,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 9
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "196 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 196
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "project was created within the last 90 days. Please review its contents carefully",
                "points": 0,
                "status": "missed",
                "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": 88,
            "inputs": {
              "releases_count": 24,
              "latest_release_tag": "v1.5.8",
              "releases_from_tags": true,
              "days_since_latest_release": 6,
              "mean_days_between_releases": 0.2
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "24 version tags (no GitHub releases)",
                "points": 16.2,
                "status": "partial",
                "details": [
                  {
                    "code": "version_tags_no_releases",
                    "params": {
                      "count": 24
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 6 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 6
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~0.2 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 0.2
                    }
                  }
                ],
                "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": 38,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 1,
            "inputs": {
              "forks": 0,
              "stars": 1,
              "watchers": 0,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "1 stars",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "0 forks",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "0 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "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 (Apache-2.0)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "Apache-2.0"
                    }
                  }
                ],
                "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": 53,
            "inputs": {
              "packages": [
                "axon-charts"
              ],
              "dependents": null,
              "ecosystems": "npm",
              "total_downloads": null,
              "monthly_downloads": 1477
            },
            "components": [
              {
                "key": "monthly_downloads",
                "name": "Monthly downloads",
                "detail": "1,477 downloads/month across npm",
                "points": 42.3,
                "status": "partial",
                "details": [
                  {
                    "code": "downloads_monthly",
                    "params": {
                      "count": 1477,
                      "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": "at_risk",
        "name": "Sustainability & Governance",
        "value": 32,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 10,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 1,
              "top_contributor_share": 1
            },
            "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 100% of commits",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 100
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "1 contributors",
                "points": 1.4,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 0 contributing companies or organizations -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "critical",
            "name": "Issue & PR responsiveness",
            "note": "Excluded from scoring (no data or not applicable): Issue resolution, PR acceptance. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "issue_resolution",
                    "pr_acceptance"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 1,
            "inputs": {
              "merged_prs": 0,
              "open_issues": 0,
              "closed_issues": 0,
              "issue_closed_ratio": null,
              "closed_unmerged_prs": 0
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "no issues or no data",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_issues_or_data",
                    "params": {}
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "no decided pull requests or no data",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_decided_prs_or_data",
                    "params": {}
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "at_risk",
            "name": "Ownership & stewardship",
            "note": null,
            "notes": [],
            "value": 33,
            "inputs": {
              "followers": 0,
              "owner_type": "Organization",
              "is_verified": null,
              "owner_login": "AxonWatch",
              "public_repos": 1,
              "account_age_days": 83
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "organization-owned",
                "points": 30,
                "status": "met",
                "details": [
                  {
                    "code": "owner_organization",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "0 followers of AxonWatch",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 0,
                      "login": "AxonWatch"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "1 public repos, account ~0 yr old",
                "points": 2.6,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 1
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 0
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "axon-charts"
              ],
              "ecosystems": "npm",
              "any_deprecated": false,
              "min_days_since_publish": 1
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "1 package(s) on npm",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 1,
                      "ecosystems": "npm"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 1 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 1
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "18 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 18
                    }
                  }
                ],
                "max_points": 20
              },
              {
                "key": "not_deprecated",
                "name": "Not deprecated",
                "detail": "active, not deprecated or yanked",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "package_not_deprecated",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "moderate",
        "name": "Engineering Quality",
        "value": 54,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "at_risk",
            "name": "Engineering practices",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: CI-Tests. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_ci_tests"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 30,
            "inputs": {
              "has_ci": true,
              "has_tests": false,
              "has_editorconfig": false,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "1 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 0,
                "status": "missed",
                "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": "no pull request found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "excellent",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 90,
            "inputs": {
              "topics": [],
              "has_wiki": true,
              "homepage": "https://axonwatch.github.io/axon-charts/",
              "has_readme": true,
              "has_docs_dir": true,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 25,
                "status": "met",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": "https://axonwatch.github.io/axon-charts/",
                "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": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "at_risk",
        "name": "Security",
        "value": 38,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "at_risk",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): CI-Tests, Packaging, Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "ci_tests",
                    "packaging",
                    "signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 38,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 15,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 3,
              "scorecard_aggregate": 3.8
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection not enabled on development/release branches",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "no pull request found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "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/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 0 contributing companies or organizations -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "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": "project was created within the last 90 days. Please review its contents carefully",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow not detected",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "no SAST tool detected",
                "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": "GitHub workflow tokens follow principle of least privilege",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "1 existing vulnerabilities detected",
                "points": 6.8,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "at_risk",
        "name": "AI Readiness",
        "value": 41,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "at_risk",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 1,
              "agent_instruction_files": [],
              "agent_instruction_max_bytes": null
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "no CLAUDE.md / AGENTS.md / editor rules",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_instructions",
                    "params": {}
                  }
                ],
                "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": "100 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 100,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "critical",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 21,
            "inputs": {
              "has_nix": false,
              "has_tests": false,
              "lockfiles": [
                "package-lock.json"
              ],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [
                "tsconfig.json"
              ],
              "agent_commit_share": 0,
              "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": 0,
                "status": "missed",
                "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": "lockfile",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "lockfile"
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "no agent-authored commits among the last 100",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_authored_commits",
                    "params": {
                      "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": 99,
            "inputs": {
              "primary_language": "TypeScript",
              "largest_source_bytes": 61125,
              "source_files_sampled": 68,
              "oversized_source_files": 1
            },
            "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": "1/68 source files over 60KB",
                "points": 54.2,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 68,
                      "oversized": 1
                    }
                  }
                ],
                "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",
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-27T17:41:53.413872Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/a/AxonWatch/axon-charts.svg",
  "full_name": "AxonWatch/axon-charts",
  "license_state": "standard",
  "license_spdx": "Apache-2.0"
}

评分是信号,而非担保。 评分反映的是 GitHub 上公开可见的实践——不是代码审计,也不是安全保证。

缺失数据将被剔除并重新归一化权重,绝不按零分计。方法论已版本化并公开:指标 v1.13.0、模式 v0.27.0—— 完整方法论 · 指标知识库.

单项结果在整体记录中的位置: 汇总统计npm.