Public record
Software health reportschema 0.23.0 · metrics 1.13.0 · 2026-07-21 18:26 UTC

TestSprite / testsprite-cli

Official TestSprite CLI — AI-powered automated testing from your terminal

TypeScriptApache-2.0★ 2,415 stars⑂ 98 forkssince Jun 2026View on GitHub ↗

TestSprite/testsprite-cli holds a health index of 76 out of 100, placing it in the Good band. It scores highest on Engineering Quality (90/100) and lowest on Security (63/100). It was last updated 1 day ago. 5 contributors account for most of its recent work.

76
overall / 100
Good

Software health index

Metrics are grouped into weighted categories on one standardized 1–100 scale. Overall starts as their weighted mean; when public evidence triggers the High-Risk Jurisdiction Policy, the rating is adjusted and receives an At risk ceiling of 49. AI Readiness sits outside the overall score.

76
Excellent85-100Exemplary; meets essentially all checked criteria
Good70-84Healthy; minor gaps
Moderate50-69Acceptable with notable gaps; review recommended
At risk30-49Significant weaknesses; adoption warrants caution
Critical1-29Severe problems (abandoned, single-maintainer, no hygiene)
VitalityCommunity &AdoptionSustainability &GovernanceEngineeringQualitySecurityAI Readiness

Score profile

Each axis is a category. The shape matters more than the average — a healthy subject fills the whole shape, while a spike-and-crater profile means strength in one dimension is masking risk in another.

Ownership

TestSpriteOrganization
71 followers4 public repossince May 2024

This repository is backed by an organization — shared, accountable stewardship that can outlive any single maintainer.

Package ecosystems

RegistryPackageVersionDownloads / moVersionsLast publishTags
npm@testsprite/testsprite-cli0.4.03,37464 days agotestspriteclitestingautomation

Metrics by category

Vitality

Is the project alive — is code being written and are releases shipping?

75Good · 22% of overall
How it's scored
36/36Push recency — last push 1 days ago
4.2/36Commit cadence — 6/52 weeks with commits
17.8/18Commit volume — 96 commits in the last year
0/10OpenSSF Scorecard: Maintained — project was created within the last 90 days. Please review its contents carefully
Inputs used
commits_last_year96
human_commit_share0.99
days_since_last_push1
active_weeks_last_year6

Release discipline

100Excellent
How it's scored
27/27Ships releases — 5 releases published
36/36Release recency — latest release 4 days ago
27/27Release cadence — a release every ~8.8 days
0/10OpenSSF Scorecard: Signed-Releases — no data
Inputs used
releases_count5
latest_release_tagv0.4.0
releases_from_tagsno
days_since_latest_release4
mean_days_between_releases8.8
Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.

Community & Adoption

Does the project have users, downloads, attention, and a welcoming setup for contributors?

76Good · 18% of overall
How it's scored
54.9/60Stars — 2,415 stars
16.6/25Forks — 98 forks
1.7/15Watchers — 3 watchers
Inputs used
forks98
stars2,415
watchers3
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonwindow_too_short

Community health

92Excellent
How it's scored
22.5/22.5README
22.5/22.5License — recognized license (Apache-2.0)
18/18CONTRIBUTING guide
13.5/13.5Code of conduct
0/7.2Issue template
6.3/6.3PR template
Inputs used
has_readmeyes
has_licenseyes
has_contributingyes
has_issue_templateno
has_code_of_conductyes
has_pull_request_templateyes
How it's scored
47/80Monthly downloads — 3,374 downloads/month across npm
0/20Registry dependents — not reported by this ecosystem
Inputs used
packages@testsprite/testsprite-cli
dependents
ecosystemsnpm
total_downloads
monthly_downloads3,374
Excluded from scoring (no data or not applicable): Registry dependents. Remaining weights renormalized.

Sustainability & Governance

Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?

75Good · 24% of overall
How it's scored
45.9/54Bus factor — 5 contributor(s) cover half of all commits
19.7/22.5Commit distribution — top contributor authored 13% of commits
13.5/13.5Contributor breadth — 22 contributors
3/10OpenSSF Scorecard: Contributors — project has 1 contributing companies or organizations -- score normalized to 3
Inputs used
bus_factor5
contributors_sampled22
top_contributor_share0.126
How it's scored
32.8/46.8Issue resolution — 70% of issues closed
21.1/38.3PR acceptance — 85/154 decided PRs merged
13.5/15OpenSSF Scorecard: Code-Review — Found 26/27 approved changesets -- score normalized to 9
Inputs used
merged_prs85
open_issues29
closed_issues68
issue_closed_ratio0.701
closed_unmerged_prs69
How it's scored
30/30Ownership backing — organization-owned
0/20Verified domain
13.4/25Owner reach — 71 followers of TestSprite
9.4/25Track record — 4 public repos, account ~2 yr old
Inputs used
followers71
owner_typeOrganization
is_verified
owner_loginTestSprite
public_repos4
account_age_days784
How it's scored
25/25Published & resolvable — 1 package(s) on npm
35/35Publish recency — latest publish 4 days ago
20/20Version history — 6 published versions
20/20Not deprecated — active, not deprecated or yanked
Inputs used
packages@testsprite/testsprite-cli
ecosystemsnpm
any_deprecatedno
min_days_since_publish4

Engineering Quality

Are baseline engineering and documentation practices in place?

90Excellent · 20% of overall
How it's scored
24/24CI workflows — 8 workflow(s)
24/24Tests present
16/16Linter config — eslint.config.mjs
0/9.6Pre-commit hooks
0/6.4.editorconfig
20/20OpenSSF Scorecard: CI-Tests — 28 out of 28 merged PRs checked by a CI test -- score normalized to 10
Inputs used
has_ciyes
has_testsyes
has_editorconfigno
has_linter_configyes
has_precommit_configno

Documentation

100Excellent
How it's scored
30/30README
25/25Documentation directory
15/15Documentation / homepage site — https://www.testsprite.com
10/10Repository description
10/10Topics — 7 topics
10/10Wiki
Inputs used
topicsai, cli, e2e-testing, playwright, qa, test-automation, testing
has_wikiyes
homepagehttps://www.testsprite.com
has_readmeyes
has_docs_diryes
has_descriptionyes

Security

Are visible security and supply-chain practices strong, without unresolved high-risk jurisdiction exposure?

63Moderate · 16% of overall
How it's scored
7.5/7.5Binary-Artifacts — no binaries found in the repo
3.8/7.5Branch-Protection — branch protection is not maximal on development and all release branches
2.5/2.5CI-Tests — 28 out of 28 merged PRs checked by a CI test -- score normalized to 10
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
6.8/7.5Code-Review — Found 26/27 approved changesets -- score normalized to 9
0.8/2.5Contributors — project has 1 contributing companies or organizations -- score normalized to 3
10/10Dangerous-Workflow — no dangerous workflow patterns detected
7.5/7.5Dependency-Update-Tool — update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5License — license file detected
0/7.5Maintained — project was created within the last 90 days. Please review its contents carefully
0/5Packaging — no data
4.5/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 9
0/5SAST — SAST tool is not run on all commits -- score normalized to 0
5/5Security-Policy — security policy file detected
0/7.5Signed-Releases — no data
6.8/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
0.8/7.5Vulnerabilities — 9 existing vulnerabilities detected
Inputs used
sourceopenssf_scorecard
checks_evaluated16
scorecard_versionv5.5.0
checks_inconclusive2
scorecard_aggregate6.3
Excluded from scoring (no data or not applicable): packaging, signed_releases. Remaining weights renormalized.

AI Readiness

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.

69Moderate · 0% of overall
How it's scored
0/45Agent instructions — no CLAUDE.md / AGENTS.md / editor rules
0/15Machine-readable docs (llms.txt)
40/40Legible commit history — 94 of 95 human commits state their intent (structured subject or explanatory body)
Inputs used
has_llms_txtno
legible_history_share0.989
agent_instruction_files
agent_instruction_max_bytes
How it's scored
0/18One-command bootstrap
22/22Automated tests
11/11Lint / format config — eslint.config.mjs
11/11Static type checking — tsconfig.json
10/10Reproducible environment — lockfile
10/10Demonstrated agent practice — 9 of the last 96 commits agent-authored or agent-credited
8/8Automated maintenance — 1 of the last 96 commits are automated dependency updates
9/10OpenSSF Scorecard: Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 9
Inputs used
has_nixno
has_testsyes
lockfilespackage-lock.json
has_dockerfileno
typed_languageyes
bootstrap_files
has_devcontainerno
has_linter_configyes
typecheck_configstsconfig.json
agent_commit_share0.094
toolchain_manifests
dependency_bot_commit_share0.01
How it's scored
45/45Type-checkable code — TypeScript (statically typed)
52.1/55Manageable file sizes — 6/115 source files over 60KB
Inputs used
primary_languageTypeScript
largest_source_bytes441,972
source_files_sampled115
oversized_source_files6

Key facts

2,415GitHub stars
22contributors
96commits, last 12 months
1days since last push
5releases
5bus factor
29open issues
npmpackage ecosystems

Data collection warnings

  • GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository
  • deps.dev does not index npm:@testsprite/testsprite-cli@0.4.0; advisories assessed against the repository dependency graph instead

More detail

Star and fork history 2,415 ★ / 98 ⇿
2,415Stars
98Forks
5Releases

When each star and fork was added, collected from GitHub and bucketed by day. Cumulative growth sits directly above the daily additions it is made of, so the two read against each other: steady organic accretion looks nothing like an abrupt, short-lived burst. Where that difference is measurable, it is reported as growth authenticity.

Only the most recent history is shown — this repository exceeds the collection window, so the earliest history is not captured.

05001,0001,5002,0002,5002,415981772026-062026-072026-07
Major 0Minor 3Patch 2
OpenSSF Scorecard 6.3 / 10
6.3aggregate

Independent, tool-agnostic security assessment from the open-source OpenSSF Scorecard. Each check rewards a security practice, not a specific vendor's tool. Checks Scorecard could not determine are marked n/a and excluded from the security score (never counted as zero).Scorecard v5.5.0 · 2026-07-21 18:26 UTC

10Binary-Artifactsno binaries found in the repo
5Branch-Protectionbranch protection is not maximal on development and all release branches
10CI-Tests28 out of 28 merged PRs checked by a CI test -- score normalized to 10
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
9Code-ReviewFound 26/27 approved changesets -- score normalized to 9
3Contributorsproject has 1 contributing companies or organizations -- score normalized to 3
10Dangerous-Workflowno dangerous workflow patterns detected
10Dependency-Update-Toolupdate tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
0Maintainedproject was created within the last 90 days. Please review its contents carefully
n/aPackagingpackaging workflow not detected
9Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 9
0SASTSAST tool is not run on all commits -- score normalized to 0
10Security-Policysecurity policy file detected
n/aSigned-Releasesno releases found
9Token-Permissionsdetected GitHub workflow tokens with excessive permissions
1Vulnerabilities9 existing vulnerabilities detected
Direct dependencies 3
RegistryPackageVersion constraintManifest
npmcommander^12.1.0package.json
npmundici^7.16.0package.json
npmvalibot^1.4.1package.json
All dependencies not collected

The resolved dependency set could not be collected for this report: GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Raw JSON report machine-readable
{
  "data": {
    "repo": {
      "topics": [
        "ai",
        "cli",
        "e2e-testing",
        "playwright",
        "qa",
        "test-automation",
        "testing"
      ],
      "is_fork": false,
      "size_kb": 1097,
      "has_wiki": true,
      "homepage": "https://www.testsprite.com",
      "languages": {
        "JavaScript": 17913,
        "TypeScript": 2624471
      },
      "pushed_at": "2026-07-20T05:56:13Z",
      "created_at": "2026-06-11T10:44:15Z",
      "owner_type": "Organization",
      "updated_at": "2026-07-21T18:05:28Z",
      "description": "Official TestSprite CLI — AI-powered automated testing from your terminal",
      "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"
      ]
    },
    "owner": {
      "blog": "https://www.testsprite.com/",
      "name": "TestSprite",
      "type": "Organization",
      "login": "TestSprite",
      "company": null,
      "location": "United States of America",
      "followers": 71,
      "avatar_url": "https://avatars.githubusercontent.com/u/170984515?v=4",
      "created_at": "2024-05-27T22:17:51Z",
      "is_verified": null,
      "public_repos": 4,
      "account_age_days": 784
    },
    "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": "v0.4.0",
          "kind": "minor",
          "published_at": "2026-07-17T02:41:43Z"
        },
        {
          "tag": "v0.3.0",
          "kind": "minor",
          "published_at": "2026-07-09T23:21:09Z"
        },
        {
          "tag": "v0.2.0",
          "kind": "minor",
          "published_at": "2026-07-09T00:57:20Z"
        },
        {
          "tag": "v0.1.2",
          "kind": "patch",
          "published_at": "2026-06-20T03:56:02Z"
        },
        {
          "tag": "v0.1.1",
          "kind": "patch",
          "published_at": "2026-06-12T02:18:03Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "2708a4069fba72822f94906d05001b4d19e66d9c",
          "body": "Add --skip-if-configured to testsprite setup (and the deprecated init\nalias). When the active profile already has a saved API key and no\nexplicit key source (--api-key or --from-env) is given, the interactive\nprompt is skipped and the existing key is reused.\n\nMotivation: re-running setup to refresh \n[…]\nxt + JSON)\n- proceeds to prompt when no credentials exist\n- allows isTTY=false CI runs when skip applies\n- --api-key overwrites despite skip flag\n- --from-env overwrites despite skip flag\n\nCloses #206",
          "is_bot": false,
          "headline": "fix(init): skip API key prompt when credentials already exist (#234)",
          "author_name": "Tasfia Chowdhury",
          "author_login": "Tasfia-17",
          "committed_at": "2026-07-18T00:04:01Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5fe0b0012c7a16209caaeee2bb0771ea0da4d39c",
          "body": "…#233)",
          "is_bot": false,
          "headline": "fix(config): normalize empty/whitespace TESTSPRITE_PROFILE to unset (…",
          "author_name": "Shalahuddin Al-Ayyubi",
          "author_login": "0xshalah",
          "committed_at": "2026-07-18T00:03:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "326fa97aae538a3069395f7aa06e51a0e5d6df3c",
          "body": "Co-authored-by: Lexiie <28455136+Lexiie@users.noreply.github.com>",
          "is_bot": false,
          "headline": "test(test): guard status filter validation order (#222)",
          "author_name": "Lex",
          "author_login": "Lexiie",
          "committed_at": "2026-07-18T00:02:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9d4af09af285ad9863c9c1bc9106d968d3d1bf05",
          "body": "* feat(cli): add text list column controls\n\n* fix(cli): address list column review feedback",
          "is_bot": false,
          "headline": "feat(cli): add text list column controls (#165) (#252)",
          "author_name": "nopp",
          "author_login": "naufalfx805-source",
          "committed_at": "2026-07-18T00:01:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8db1882964b93db3dcd9b7de526cc7d179cd6619",
          "body": "…e dashboard (#226)\n\n* feat(test): add \"test open <test-id>\" to jump from the terminal to the dashboard\n\n* fix(open): derive the dry-run URL via resolvePortalUrl and handle async spawn ENOENT\n\n* fix(browser): map non-http(s) URL rejection to exit 5 (validation error)\n\nopenInBrowser threw a plain Err\n[…]\nthrough localValidationError so it is classified as VALIDATION_ERROR and maps to the documented exit code 5, matching every other bad-argument path. Test asserts the exit code, not the message string.",
          "is_bot": false,
          "headline": "feat(test): add \"test open <test-id>\" to jump from the terminal to th…",
          "author_name": "Andy",
          "author_login": "Andy00L",
          "committed_at": "2026-07-18T00:00:18Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "eaf0585dd29b960161fe3d160adb23ce0e6040ad",
          "body": null,
          "is_bot": false,
          "headline": "fix(flaky): propagate auth trigger errors (#217)",
          "author_name": "JerryNee",
          "author_login": "JerryNee",
          "committed_at": "2026-07-18T00:00:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "45dcd0895f10b406646333e537c658f2b3cd0b41",
          "body": null,
          "is_bot": false,
          "headline": "fix(agent): update verify skill auth commands (#216)",
          "author_name": "JerryNee",
          "author_login": "JerryNee",
          "committed_at": "2026-07-17T23:54:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "759a1c7df81b926c70ab125b16754460e47055dd",
          "body": "Emit a shell completion script for bash, zsh, or fish. Command names,\nsubcommands, and global flags are derived from the fully-assembled Commander\ntree at call time (buildCompletionSpec walks program.commands), so the script\ncan never drift from the real command surface. The shell auto-detects from\n$SHELL when the argument is omitted.\n\nFixes #74",
          "is_bot": false,
          "headline": "feat(cli): add \"testsprite completion\" for bash/zsh/fish (#227)",
          "author_name": "Andy",
          "author_login": "Andy00L",
          "committed_at": "2026-07-17T23:54:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "34f5d430797437ab2f67910fe356c3732ea0be57",
          "body": null,
          "is_bot": false,
          "headline": "fix(http): avoid retrying keyless writes (#256)",
          "author_name": "nopp",
          "author_login": "naufalfx805-source",
          "committed_at": "2026-07-17T23:54:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "94f78ad88b427bcdf87079705ae3723019cd67d5",
          "body": "* fix(auth): tighten Windows credentials ACL\n\n* docs(auth): document credential permission tightening",
          "is_bot": false,
          "headline": "fix(auth): tighten Windows credentials ACL (#104) (#253)",
          "author_name": "nopp",
          "author_login": "naufalfx805-source",
          "committed_at": "2026-07-17T23:53:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "36e5b14fd1e2983bdacadd895313e0ef5881b9cd",
          "body": "Co-authored-by: Lexiie <28455136+Lexiie@users.noreply.github.com>",
          "is_bot": false,
          "headline": "fix(init): debug log whoami fallback (#223)",
          "author_name": "Lex",
          "author_login": "Lexiie",
          "committed_at": "2026-07-17T23:53:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3c3a2e05b976abc7f4e5f823a55a78c9cf16ad25",
          "body": "… @SahilRakhaiya05) (#246)\n\n* fix(bundle): atomic re-commit via per-entry aside with rollback\n\n* fix(bundle): move meta.json aside before other bundle entries during commit\n\n---------\n\nCo-authored-by: SahilRakhaiya05 <sahil.rakhaiya117814@marwadiuniversity.ac.in>",
          "is_bot": false,
          "headline": "Recovered: fix(bundle): atomic re-commit via per-entry aside (#196 by…",
          "author_name": "Joseph Jang",
          "author_login": "jangjos-128",
          "committed_at": "2026-07-17T23:53:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3abcf2d501533caa2e803b922825ab0d5239caa4",
          "body": "Co-authored-by: Yazan-O <mohamad.yazan@ou.edu>",
          "is_bot": false,
          "headline": "fix(doctor): validate output mode (#251)",
          "author_name": "Joseph Jang",
          "author_login": "jangjos-128",
          "committed_at": "2026-07-17T23:52:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d2f0357ec1f9f08419768a40bd89beead8bc7cb3",
          "body": "…te check (#260)\n\nGitHub's runner infra force-upgrades actions/github-script@v7 to Node 24,\nwhere the script-side require('@actions/github') can no longer resolve.\nEvery recent PR shows a red 'gate' check with 'Cannot find module\n@actions/github' regardless of whether it links an issue.\n\n- Pin actio\n[…]\nn #257 — thank you! This lands\nseparately with a SHA pin and a require-free client construction.\n\nCo-authored-by: Zeshi Du <duke.zeshi@gmail.com>\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ci): migrate github-script to v8 — repair the repo-wide broken ga…",
          "author_name": "zeshi-du",
          "author_login": "zeshi-du",
          "committed_at": "2026-07-17T23:44:17Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "7b4937bd903fcd201b30a7e7ee4dc8f3af4d871c",
          "body": "release: v0.4.0",
          "is_bot": false,
          "headline": "Merge pull request #259 from TestSprite/release/v0.4.0",
          "author_name": "Fangyuan Zhang",
          "author_login": "fyZhang66",
          "committed_at": "2026-07-17T00:43:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e91c5a107867f16ca183b11684c84d953d972cbf",
          "body": "Private-Snapshot-RevId: afa3bf501545df536cfa638a86ae096fb7c34880",
          "is_bot": false,
          "headline": "release: v0.4.0",
          "author_name": "zeshi-du",
          "author_login": "zeshi-du",
          "committed_at": "2026-07-16T21:56:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "60d55e47883e924ff1a5f0ab1fe67a25bc3b0877",
          "body": "release: v0.3.0",
          "is_bot": false,
          "headline": "Merge pull request #230 from TestSprite/release/v0.3.0",
          "author_name": "Joseph Jang",
          "author_login": "jangjos-128",
          "committed_at": "2026-07-09T23:02:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3d65ff5a0e25399a7b87e8c75b6f8eb90f0ef2f8",
          "body": "Private-Snapshot-RevId: d22d9f18f5d9712921097d5829c28d056e3ffd31",
          "is_bot": false,
          "headline": "release: v0.3.0",
          "author_name": "zeshi-du",
          "author_login": "zeshi-du",
          "committed_at": "2026-07-09T22:29:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3305dfa57ab258b11311d15197a80dd9eb654911",
          "body": "… or backend skeleton (#180)",
          "is_bot": false,
          "headline": "feat(test): add \"test scaffold\" to emit a schema-correct starter plan…",
          "author_name": "Andy",
          "author_login": "Andy00L",
          "committed_at": "2026-07-06T20:14:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "946f5b326453b55aaeac97dffb5bac2aa844901f",
          "body": "* feat(cli): graceful termination signals + broken-pipe guard\n\nInstall handlers for SIGINT/SIGTERM/SIGHUP that print a one-line explanation\n(any started run keeps executing server-side; resume with `testsprite test list`\nor `testsprite test wait <runId>`) and exit with the conventional 128+signum\nco\n[…]\ndefault stderr\nwriter now uses fs.writeSync (best-effort, guarded against EPIPE) so the hint is\nreliably emitted. Added a test mocking fs.writeSync to assert the synchronous\nwrite on the default path.",
          "is_bot": false,
          "headline": "feat(cli): graceful termination signals + broken-pipe guard (#185)",
          "author_name": "Andy",
          "author_login": "Andy00L",
          "committed_at": "2026-07-06T20:13:57Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "edc31c8e0e82599a9b95d15ba761eede61683517",
          "body": "* feat(cli): add \"testsprite doctor\" environment diagnostic\n\nOne-shot preflight: checks CLI version, Node runtime, profile, API endpoint,\ncredentials, live connectivity (GET /me), and verify-skill install. Prints an\nOK/WARN/FAIL report and exits non-zero when any check fails, so it gates a CI\nstep o\n[…]\ned input instead of\n  silently defaulting, matching the other commands.\n- The --output json test asserts the API key never appears in the JSON path\n  (distinct from the text renderer already covered).",
          "is_bot": false,
          "headline": "feat(cli): add \"testsprite doctor\" environment diagnostic (#183)",
          "author_name": "Andy",
          "author_login": "Andy00L",
          "committed_at": "2026-07-06T20:13:18Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e819e4543e5993f7548965b15cd9a03c1ee87b95",
          "body": "* feat(agent): add GitHub Copilot as an install target\n\nAdds `copilot` to the agent-install targets. GitHub Copilot reads\npath-specific custom instructions from `.github/instructions/*.instructions.md`\n(VS Code / Visual Studio / Copilot Chat), with YAML frontmatter carrying an\n`applyTo` glob. The sk\n[…]\ner targets but\nomitted Kiro (a pre-existing gap), leaving it inconsistent with the\n`--target` help text and the docs. Align the description with the\n`--target` list so every supported target is named.",
          "is_bot": false,
          "headline": "feat(agent): add GitHub Copilot as an install target (#194)",
          "author_name": "Awokoya Olawale Davidson",
          "author_login": "Davidson3556",
          "committed_at": "2026-07-06T20:12:45Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8ac2ff0132e01c2c63e4a411ba4c0fbfc48a7a1d",
          "body": "… invocation (#178)\n\n* feat(test): make \"test wait\" variadic — attach to several runs in one invocation\n\n* fix(wait): honor the shared deadline for queued members and hint only resumable runs",
          "is_bot": false,
          "headline": "feat(test): make \"test wait\" variadic — attach to several runs in one…",
          "author_name": "Andy",
          "author_login": "Andy00L",
          "committed_at": "2026-07-06T20:12:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "108a91315762ccb8c1c157cbc5e15fb1914a7401",
          "body": "…an-out (#154)\n\n* fix(batch): classify RequestTimeoutError as timeout in --all --wait fan-out\n\nWhen test run --all --wait or test rerun --all --wait hit a per-request timeout\nduring batch fan-out polling, RequestTimeoutError rejected the fan-out before\nout.print(). Classify it as status:'timeout' in\n[…]\nCursor <cursoragent@cursor.com>\n\n* Remove unused readFileSync import from test file\n\n---------\n\nCo-authored-by: Contributor <contributor@testsprite.com>\nCo-authored-by: Cursor <cursoragent@cursor.com>",
          "is_bot": false,
          "headline": "fix(batch): classify RequestTimeoutError as timeout in --all --wait f…",
          "author_name": "Muath Awad",
          "author_login": "Awad-de",
          "committed_at": "2026-07-06T20:11:31Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "78ad224ba55231d383f7bc44f949b8ad016235d7",
          "body": "Bumps [marocchino/sticky-pull-request-comment](https://github.com/marocchino/sticky-pull-request-comment) from 2.9.4 to 3.0.5.\n- [Release notes](https://github.com/marocchino/sticky-pull-request-comment/releases)\n- [Commits](https://github.com/marocchino/sticky-pull-request-comment/compare/773744901\n[…]\nirect:production\n  update-type: version-update:semver-major\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
          "is_bot": true,
          "headline": "chore(ci): bump marocchino/sticky-pull-request-comment (#187)",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-07-06T20:10:58Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c6d37b7e5cfc85cd56b3ac2f5d39c7177e019a46",
          "body": "* fix(http): clear per-attempt timeout timers\n\n* fix(http): preserve timeout race classification",
          "is_bot": false,
          "headline": "fix(http): clear per-attempt timeout timers (#137)",
          "author_name": "JerryNee",
          "author_login": "JerryNee",
          "committed_at": "2026-07-06T20:10:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f7b10b724442b81b46275a51b4f0a37051ba19af",
          "body": "* fix(config): treat empty env vars as unset in loadConfig\n\n* test: address review — dry-run whoami uses offline client; fix whitespace env key expectation",
          "is_bot": false,
          "headline": "fix(config): treat empty env vars as unset in loadConfig (#8)",
          "author_name": "Sahil Rakhaiya",
          "author_login": "SahilRakhaiya05",
          "committed_at": "2026-07-06T20:09:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b9e9601c4926e21c89066d30d56312524036ecb0",
          "body": "* feat(test): add \"test lint\" offline plan/steps validator\n\n* fix(lint): report physical JSONL line numbers (blank lines no longer shift them)",
          "is_bot": false,
          "headline": "feat(test): add \"test lint\" offline plan/steps validator (#176)",
          "author_name": "Andy",
          "author_login": "Andy00L",
          "committed_at": "2026-07-05T22:28:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4b724619e27a360a00e6c578db3e5068bb566d91",
          "body": "* feat(cli): add 'test flaky' repeat-run flaky-test detector\n\n* fix(flaky): cap --runs at 10 per maintainer scope (#115)\n\nRescope the flaky detector's --runs bound from 1-100 to 1-10 as requested in the #115 triage: uncapped FE replays amplify free executions. Updates the MAX_FLAKY_RUNS constant (wh\n[…]\nine rendered in the test flaky --help output. Regenerate the snapshot so the help snapshot test stays green on CI.\n\n* docs(changelog): resolve leftover merge-conflict markers (keep JUnit + flaky 1-10)",
          "is_bot": false,
          "headline": "feat(cli): add 'test flaky' repeat-run flaky-test detector (#132)",
          "author_name": "Resque",
          "author_login": "lxcario",
          "committed_at": "2026-07-05T22:27:46Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c6f946e574dc402abf2be1f5d8f56a3a219393cb",
          "body": "…m check, opt-out, CI-safe) (#181)",
          "is_bot": false,
          "headline": "feat(cli): non-blocking \"new version available\" notice (24h-cached np…",
          "author_name": "Andy",
          "author_login": "Andy00L",
          "committed_at": "2026-07-05T22:27:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "768da46510d4c4d15ce2a70ff50acc7ef0c4c245",
          "body": "… CI proxies (#169)\n\n* feat(cli): honor HTTPS_PROXY/HTTP_PROXY/NO_PROXY behind corporate and CI proxies\n\n* fix(proxy): degrade to default dispatcher when proxy agent init fails instead of crashing startup\n\n* fix(proxy): pin undici to ^7.16.0 for Node 20 compatibility (8.x requires Node >=22.19)",
          "is_bot": false,
          "headline": "feat(cli): honor HTTPS_PROXY/HTTP_PROXY/NO_PROXY behind corporate and…",
          "author_name": "Andy",
          "author_login": "Andy00L",
          "committed_at": "2026-07-05T22:27:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8eb4acff70e216ed6b63bfd19fb1fde7107b5c7f",
          "body": "Windsurf (Cascade) reads workspace rules from `.windsurf/rules/*.md`. Add it\nas an own-file agent target so `testsprite agent install --target windsurf`\n(and `setup --agent windsurf`) installs the TestSprite skills into a Windsurf\nproject. Reworked onto the v0.2.0 multi-skill agent-targets API (path\n[…]\ns (incl.\nCascade-frontmatter and per-skill budget tests), the e2e matrix guards /\ncontent-integrity (gated on compactBody), and the README/DOCUMENTATION target\nlists (incl. the --force own-file list).",
          "is_bot": false,
          "headline": "feat(agent): add windsurf as an install target (#29)",
          "author_name": "Awokoya Olawale Davidson",
          "author_login": "Davidson3556",
          "committed_at": "2026-07-05T22:27:00Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2ddb03d5674ed4bfd7d0e7655170ce8b8d2bdd54",
          "body": "… (#11)\n\n* feat(cli): add runtime Node.js version check with clear error message\n\n* refactor(version-guard): extract to a documented module tested against the real implementation",
          "is_bot": false,
          "headline": "feat(cli): add runtime Node.js version check with clear error message…",
          "author_name": "Resque",
          "author_login": "lxcario",
          "committed_at": "2026-07-05T19:41:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d72290d6d92d2806b33608d67af304782597f753",
          "body": "* fix(test): validate artifact run id default path\n\n* fix(test): reject windows dot artifact run ids\n\n* fix(test): reject windows dot-suffix artifact run ids\n\n* style(test): format artifact run id guard\n\n---------\n\nCo-authored-by: Lexiie <28455136+Lexiie@users.noreply.github.com>",
          "is_bot": false,
          "headline": "fix(test): guard default artifact run id path (#172)",
          "author_name": "Lexiie",
          "author_login": "Lexiie",
          "committed_at": "2026-07-05T19:41:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "17650be02c06d9fef2742039a16bb678595bdf89",
          "body": "* block artifact download redirects\n\n* redact artifact download urls\n\n---------\n\nCo-authored-by: merlinsantiago982-cmd <merlinsantiago982-cmd@users.noreply.github.com>",
          "is_bot": false,
          "headline": "fix: harden failure bundle artifact downloads (#60)",
          "author_name": "merlinsantiago982-cmd",
          "author_login": "merlinsantiago982-cmd",
          "committed_at": "2026-07-05T19:38:34Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5ff639978187dc521aecf344de132dfbc5db0ed1",
          "body": "…t pure) (#31)\n\nInteractive prompts (`prompt.ts` — the API-key prompt during `setup`/`auth\nconfigure`, the target prompt during `agent install`) wrote the question and\nmasking to STDOUT, and the \"Configuring profile …\" prelude defaulted to\nstdout too. On the interactive path that mixes UI text into \n[…]\ned.\nCallers that inject explicit streams are unaffected.\n\nAdds regression tests: promptText writes the question to stderr by default,\nand the configure prelude lands on stderr (not the result stdout).",
          "is_bot": false,
          "headline": "fix(cli): route interactive prompts and prelude to stderr (keep stdou…",
          "author_name": "Awokoya Olawale Davidson",
          "author_login": "Davidson3556",
          "committed_at": "2026-07-05T19:38:16Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "759e85c2e046af365c7904376ab577d9e38e0cb3",
          "body": "The 'testsprite usage' command help text listed three examples but\nomitted the --debug flag (a global option useful for diagnosing auth\nand network issues). It also didn't document the exit codes, which\nmatters for CI/CD scripts that gate on the return value.\n\nThis PR adds:\n- A --debug example showi\n[…]\n the CLI know what to expect.\n\nPure documentation improvement — no behavioral change, no new deps.\nTested: existing unit tests pass (npm test).\n\nCo-authored-by: MOAAMN SAYED <moaamnsayed560@gmail.com>",
          "is_bot": false,
          "headline": "docs(usage): add --debug example + exit codes to help text (#171)",
          "author_name": "mo01115285816-cyber",
          "author_login": "mo01115285816-cyber",
          "committed_at": "2026-07-05T19:34:58Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "93c621c6ba021dc513c31506c35fd632c394b536",
          "body": "…al without --all (#163)\n\nTwo silent-footgun gaps in test rerun's flag validation:\n\n1. Explicit test IDs combined with --all silently discarded the listed\n   IDs — the --all branch resolves the full project test set and\n   overwrites them — so 'rerun test_abc --all' dispatched a batch rerun\n   of EV\n[…]\nth reject with VALIDATION_ERROR (exit 5) before any network dispatch.\n\nFixes #160\n\nCo-authored-by: Kshitij Bhardwaj <tothemoon202154@outlook.com>\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(rerun): reject explicit IDs with --all and --status/--skip-termin…",
          "author_name": "kshitij-heizen",
          "author_login": "kshitij-heizen",
          "committed_at": "2026-07-05T19:34:42Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f732fdb1663b4dddb3a75db6e471359fed6fa054",
          "body": "… files in --out dir (#162)\n\ncommitBundle's stale-file sweep removed EVERY directory entry not part\nof the fresh bundle, so 'test failure get --out <dir>' / 'test artifact\nget --out <dir>' pointed at a pre-existing, populated directory silently\ndeleted the user's unrelated files (exit 0, no warning)\n[…]\nwrites code.ts — but\nforeign files and directories are never touched.\n\nFixes #159\n\nCo-authored-by: Kshitij Bhardwaj <tothemoon202154@outlook.com>\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(bundle): only sweep bundle-owned files in commit, preserving user…",
          "author_name": "kshitij-heizen",
          "author_login": "kshitij-heizen",
          "committed_at": "2026-07-05T19:34:26Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "011208c46f3d132e98cb3138b0b36770eb05e639",
          "body": "…d \"agent status\" (#177)",
          "is_bot": false,
          "headline": "feat(agent): stamp installed skills with a version/hash marker and ad…",
          "author_name": "Andy",
          "author_login": "Andy00L",
          "committed_at": "2026-07-05T19:34:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9457583f27b8c4e57541933db9ed45e554dc9ad2",
          "body": "…ressions (#168)\n\n* feat(test): add \"test diff <run-a> <run-b>\" to isolate run-to-run regressions\n\n* test(diff): cover runDiff --dry-run branch (offline canned sample)",
          "is_bot": false,
          "headline": "feat(test): add \"test diff <run-a> <run-b>\" to isolate run-to-run reg…",
          "author_name": "Andy",
          "author_login": "Andy00L",
          "committed_at": "2026-07-05T19:33:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "dcbcbee16c868e8fb96dc84824d0596e6f1c2703",
          "body": null,
          "is_bot": false,
          "headline": "fix(steps): surface run-scoped per-step error text and stepType (#167)",
          "author_name": "Andy",
          "author_login": "Andy00L",
          "committed_at": "2026-07-05T19:33:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3fd703ffac59a38b6b5c227befdaf2510497b308",
          "body": "…nd test wait (#153)\n\nApply the fix in src/commands/ (the compiled CLI path). When the overall\n--timeout polling deadline is exceeded, emit {runId, status:\"running\"} to\nstdout before exit 7 so JSON agents can chain into test wait.\n\nCo-authored-by: Contributor <contributor@testsprite.com>\nCo-authored-by: Cursor <cursoragent@cursor.com>",
          "is_bot": false,
          "headline": "fix(poll): emit partial run to stdout on TimeoutError in run --wait a…",
          "author_name": "Muath Awad",
          "author_login": "Awad-de",
          "committed_at": "2026-07-05T19:32:44Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "e1d00f1816cd87fd2f64337708f2ed8849456efa",
          "body": "* feat(agent): add kiro as an install target\n\nAdds kiro as an own-file agent target on the current multi-skill model: AgentTarget union, a pathFor('kiro') case landing at .kiro/skills/<skill>/SKILL.md, and a TARGETS entry (experimental, own-file, wrapSkill frontmatter like claude/antigravity). Kiro \n[…]\nde the new kiro target. Add kiro (own-file, between cline and codex to match TARGETS order) to both guards, and add kiro to the multi-target install e2e so the target is actually exercised end-to-end.",
          "is_bot": false,
          "headline": "feat(agent): add kiro as an install target (#10)",
          "author_name": "Resque",
          "author_login": "lxcario",
          "committed_at": "2026-07-05T19:32:23Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "38e0f190666267e2c9b5d526424f7b5a9682db0e",
          "body": "…n (#33)\n\npollAccepted in runTestRerun hardcoded exitCode:1 on ApiError, causing\nthe auth-escalation find(r => r.error?.exitCode === 3) to always return\nundefined -- auth failures silently exited 1 instead of 3.\n\n- preserve err.exitCode in pollAccepted (mirrors runTestRunAll fix)\n- add auth escalation block before generic exit-1 throw\n- bound initial chunk idempotency key to <=256 chars (mirrors retry path)",
          "is_bot": false,
          "headline": "fix(rerun): preserve exit code and escalate auth errors in batch reru…",
          "author_name": "Rahul Joshi",
          "author_login": "crypticsaiyan",
          "committed_at": "2026-07-05T19:32:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b675630b852e73b1f474d905a060cbb9eeb40b0a",
          "body": "* feat(test): JUnit XML report export for batch --wait runs\n\n* fix(ci): prettier formatting and help snapshot alignment for report flags\n\n* fix(test): address CodeRabbit review on JUnit report export\n\n* fix(test): add projectId to CliBatchRunFreshResult for JUnit inference",
          "is_bot": false,
          "headline": "feat(test): JUnit XML report export for batch --wait runs (#96)",
          "author_name": "Sahil Rakhaiya",
          "author_login": "SahilRakhaiya05",
          "committed_at": "2026-07-05T19:31:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0de372c51d1282d61ccf11b1c3c7b1f1a0d22398",
          "body": "A successful (200) response whose body is not JSON — a misconfigured\nendpoint, a proxy / captive-portal / login page returning HTML with a\nsuccess status, or an empty body — caused the OK path to call raw\n`response.json()`, whose SyntaxError escaped to the top-level handler.\nThat produced an opaque \n[…]\n\npoints the operator at their endpoint config; details include the HTTP\nstatus, content-type, and underlying parse message. Abort/timeout\nerrors mid-read keep their existing classification.\n\nFixes #94",
          "is_bot": false,
          "headline": "fix(http): map non-JSON 200 responses to a typed error envelope (#166)",
          "author_name": "Awokoya Olawale Davidson",
          "author_login": "Davidson3556",
          "committed_at": "2026-07-05T19:31:15Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c0b52f852394e0199e663ddf02262ad2feb9fe51",
          "body": null,
          "is_bot": false,
          "headline": "fix(setup): validate endpoint before key check (#149)",
          "author_name": "JerryNee",
          "author_login": "JerryNee",
          "committed_at": "2026-07-05T19:30:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b5879de422891208a9b5a57fec8d45d04267c587",
          "body": null,
          "is_bot": false,
          "headline": "fix: reject malformed api keys (#141)",
          "author_name": "nopp",
          "author_login": "naufalfx805-source",
          "committed_at": "2026-07-05T19:30:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "87a6dff24e5f9744a1c5f6c9335100e60961e000",
          "body": null,
          "is_bot": false,
          "headline": "fix: reject directory code output paths (#140)",
          "author_name": "nopp",
          "author_login": "naufalfx805-source",
          "committed_at": "2026-07-05T19:30:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "25ed285cbadb7c1a7a56cac1fd2ec25f8cdb437f",
          "body": null,
          "is_bot": false,
          "headline": "fix: reject blank project passwords (#139)",
          "author_name": "nopp",
          "author_login": "naufalfx805-source",
          "committed_at": "2026-07-05T19:30:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "495db2f9f098b30cbb9db3bd7fe809332150cf7b",
          "body": null,
          "is_bot": false,
          "headline": "fix(test): validate list status before client setup (#152)",
          "author_name": "JerryNee",
          "author_login": "JerryNee",
          "committed_at": "2026-07-05T19:29:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "06d2c4deb5c2e51123ca6358673af782f2fb56a6",
          "body": null,
          "is_bot": false,
          "headline": "fix(project): validate list flags before client setup (#150)",
          "author_name": "JerryNee",
          "author_login": "JerryNee",
          "committed_at": "2026-07-05T19:29:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "205b1fb37f2778bf7a3ddaf7c1ab458dec9ae119",
          "body": "* fix(paginate): break loop on empty items with non-null nextToken\n\npaginate() in pagination.ts entered an infinite loop when the API\nreturned { items: [], nextToken: 'cursor' }. The loop only checked\nnextToken !== null, never whether items was empty. Any filtered list\ncommand returning zero results\n[…]\n remains >=80% on all 4 metrics (lines/statements/functions/branches).\n\n* fix(paginate): bound cursor loops without dropping empty pages\n\n---------\n\nSigned-off-by: Aldo Rizona <aldorizona10@gmail.com>",
          "is_bot": false,
          "headline": "fix(paginate): bound cursor loops without dropping empty pages (#48)",
          "author_name": "Aldo Rizona",
          "author_login": "aldorizona10-glitch",
          "committed_at": "2026-07-05T19:29:22Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6b90ff405006ff0731c944bec961ae7d120c2250",
          "body": "* feat(cli): respect NO_COLOR environment variable per no-color.org\n\n* fix(ticker): treat empty NO_COLOR as color-enabled per no-color.org",
          "is_bot": false,
          "headline": "feat(cli): respect NO_COLOR environment variable per no-color.org (#12)",
          "author_name": "Resque",
          "author_login": "lxcario",
          "committed_at": "2026-07-05T19:29:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "dc4d3375dc6ff0cff0a9104bbc1776898f14ed5d",
          "body": "…ON_ERROR (#27)",
          "is_bot": false,
          "headline": "fix(test): guard parseDuration --since against overflow with VALIDATI…",
          "author_name": "Rahul Joshi",
          "author_login": "crypticsaiyan",
          "committed_at": "2026-07-05T19:28:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6e7f2b3f0aafa61328c01daf276497b3030b192a",
          "body": "…test create) (#39)\n\n* fix(test): reject whitespace-only --name in test update (parity with test create)\n\n* style: run prettier on src/commands/test.ts",
          "is_bot": false,
          "headline": "fix(test): reject whitespace-only --name in test update (parity with …",
          "author_name": "Resque",
          "author_login": "lxcario",
          "committed_at": "2026-07-05T19:27:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e53257d00887b636a05f0aad09828c13eb28e83c",
          "body": "… (#17)\n\n`parseRequestTimeoutFlag` was copy-pasted byte-for-byte into five command\nfiles (auth, project, usage, init, test). Every copy silently returned\n`undefined` for an invalid value, so an explicit `--request-timeout 30s`\n(a natural \"30 seconds\" typo) resolved to undefined and the command ran\nw\n[…]\nay global env var should not hard-fail every command).\n\nAdds unit coverage for parseRequestTimeoutFlag and a subprocess\nregression that `--request-timeout 30s` exits 5 instead of falling back\nto 120s.",
          "is_bot": false,
          "headline": "fix(cli): validate --request-timeout flag and de-duplicate its parser…",
          "author_name": "Awokoya Olawale Davidson",
          "author_login": "Davidson3556",
          "committed_at": "2026-07-02T20:48:31Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8da07fb4b11bf003e9bc62c5d479424c663350b2",
          "body": null,
          "is_bot": false,
          "headline": "fix(project): avoid password file reads in dry-run update (#54)",
          "author_name": "JerryNee",
          "author_login": "JerryNee",
          "committed_at": "2026-07-02T20:48:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "76fff29c91c95f0900ba3ea2dd14f75e69396042",
          "body": "…rd (#37)\n\nassertNotLocal lowercased the hostname but did not strip a trailing dot, so http://localhost. (the FQDN form of localhost, RFC 6761) and http://localhost%2e bypassed the host === 'localhost' loopback check. IP literals are already dot-normalized by the WHATWG URL parser, so only named hosts were affected. Strips one trailing dot before the comparison. Adds 4 regression tests (3 blocked variants + 1 public-FQDN no-false-positive).",
          "is_bot": false,
          "headline": "fix(target-url): treat trailing-dot hostnames as loopback in SSRF gua…",
          "author_name": "Resque",
          "author_login": "lxcario",
          "committed_at": "2026-07-02T20:48:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7b7d80db786068b50e4f44b7f200ed3556e31a1f",
          "body": "…131)",
          "is_bot": false,
          "headline": "fix(credentials): strip CR/LF from values to prevent INI injection (#…",
          "author_name": "Resque",
          "author_login": "lxcario",
          "committed_at": "2026-07-02T20:46:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "03251d744a0d5324eac177f2c42a1eb7e7f3277b",
          "body": "…ared deadline (#130)\n\nrunTestRunAll computes each member's poll budget as\nMath.max(1, ceil(batchDeadlineMs - now)), so a run whose turn arrives\nafter the shared --timeout deadline still gets a fresh >=1s poll. With\n--max-concurrency bounding the fan-out, a batch could overshoot the\ndocumented share\n[…]\n poll and asserts the second member\nis never polled and reports 'timeout'.\n\nCo-authored-by: ahndohun <19940813+ahndohun@users.noreply.github.com>\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(test): stop run --all --wait from polling queued runs past the sh…",
          "author_name": "안도훈",
          "author_login": "ahndohun",
          "committed_at": "2026-07-02T20:46:05Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "03c4f11ae8ef14251299863d521e49d1e4f10a80",
          "body": "…alls (#129)\n\nThe codex managed-section branch already runs inspectTargetPath during\n--dry-run ([P2]) so a planted symlink is refused the same way the real\ninstall refuses it. The own-file targets (claude, cursor, cline,\nantigravity) skipped that guard in dry-run and reported the write as\nsuccessful\n[…]\noth the\nsymlinked-target and symlinked-parent cases with regression tests.\n\nCo-authored-by: ahndohun <19940813+ahndohun@users.noreply.github.com>\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(agent): apply symlink fail-close guard to own-file --dry-run inst…",
          "author_name": "안도훈",
          "author_login": "ahndohun",
          "committed_at": "2026-07-02T20:45:59Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "be9784a639931fb602b00cb00624793db35f6557",
          "body": "…run and run --all (#128)\n\ntest run, test create, create-batch, plan put, code put, update, and\ndelete all print the auto-minted idempotency key to stderr under\n--output json (as well as --verbose / --debug) so JSON-mode automation\ncan capture the key and replay a retry safely. test rerun and\ntest r\n[…]\n the JSON-mode emission (and the text-mode silence)\nwith regression tests.\n\nCo-authored-by: ahndohun <19940813+ahndohun@users.noreply.github.com>\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(test): emit auto-minted idempotency-key under --output json in re…",
          "author_name": "안도훈",
          "author_login": "ahndohun",
          "committed_at": "2026-07-02T20:45:52Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "dfdee5a3e051987c0ce090512c6d197532f4deb1",
          "body": "Co-authored-by: cmdr-chara <249489759+cmdr-chara@users.noreply.github.com>",
          "is_bot": false,
          "headline": "fix(prompt): preserve buffered input between prompts (#118)",
          "author_name": "Chara",
          "author_login": "cmdr-chara",
          "committed_at": "2026-07-02T20:45:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5e0f7c4db423885eb2b442e9627643bd6f8c6199",
          "body": "* fix(test): reject empty code get --out and strip code-file BOM\n\nWhen test code get --out receives an empty inline body, closeOutputFile left a zero-byte file with exit 0 — scripts and agents treated that as a successful download. Abort the sink, unlink any artifact, and surface VALIDATION_ERROR in\n[…]\n5)\n- abortOutputFile: wait for stream close before unlinking tmpPath\n- BOM test: use .py code-file (assertPythonCodeFile from v0.2.0)\n- CI: build before test + fileParallelism false (dist/ race flake)",
          "is_bot": false,
          "headline": "fix(test): reject empty code get --out and strip code-file BOM (#34)",
          "author_name": "Sahil Rakhaiya",
          "author_login": "SahilRakhaiya05",
          "committed_at": "2026-07-02T20:45:39Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "000c196375883e2df773a55c53df79ff7f67412f",
          "body": null,
          "is_bot": false,
          "headline": "ci: add Node 20 to test and build matrix (#133)",
          "author_name": "Resque",
          "author_login": "lxcario",
          "committed_at": "2026-07-02T20:45:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "21dc760f1bcc898d300ba5c4d873ad807cdde7b8",
          "body": "Only `test` and `project` validated the global `--output` flag. The\n`auth`, `usage`, `agent`, and `init` command groups resolved it with\n`globals.output ?? 'text'`, so an unrecognised value (e.g. a typo like\n`--output josn`) was silently coerced to text mode instead of being\nrejected. A coding agent\n[…]\nywhere. This also unifies the error\nwording, which previously differed between `test`\n(\"Flag `--output` is invalid: must be one of: json, text.\") and\n`project` (\"--output must be one of: json, text\").",
          "is_bot": false,
          "headline": "fix(cli): validate --output uniformly across all command groups (#14)",
          "author_name": "Awokoya Olawale Davidson",
          "author_login": "Davidson3556",
          "committed_at": "2026-07-02T20:45:24Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9aa7ba9d6767b64234b28de044cec76bf15aee6e",
          "body": "…e (#36)\n\nproject create/update validated --name with the action handler's if (!name) check, which a whitespace-only string passes (a non-empty string is truthy). The blank name was then sent verbatim, creating a junk-named project. The sibling \test create already rejects this via the requireString whitespace guard (dogfood P1 fix #1); this aligns project create/update with that behavior. Adds 2 regression tests.",
          "is_bot": false,
          "headline": "fix(project): reject empty/whitespace-only --name in create and updat…",
          "author_name": "Resque",
          "author_login": "lxcario",
          "committed_at": "2026-07-02T20:45:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "497bf62e3e444f8e0d8e4eda15a8b9a275eb2809",
          "body": null,
          "is_bot": false,
          "headline": "fix(pagination): reject fractional pagination flags (#40)",
          "author_name": "JerryNee",
          "author_login": "JerryNee",
          "committed_at": "2026-07-02T20:45:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a524702e75b24d563b351b9a1c6c9aa70d45796b",
          "body": null,
          "is_bot": false,
          "headline": "fix: align documented Node engine floor (#84)",
          "author_name": "nopp",
          "author_login": "naufalfx805-source",
          "committed_at": "2026-07-02T20:44:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2fd8f4cb78ca1cc100b634880383a8a4270ea64d",
          "body": "* fix(skill-nudge): require complete Codex managed section\n\n* docs(skill-nudge): document helper contracts\n\n---------\n\nCo-authored-by: ahndohun <19940813+ahndohun@users.noreply.github.com>",
          "is_bot": false,
          "headline": "fix(skill-nudge): require complete Codex managed section (#90)",
          "author_name": "안도훈",
          "author_login": "ahndohun",
          "committed_at": "2026-07-02T20:44:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "33b78482203a15fc7c2fb9473d6be9f50994befd",
          "body": "…ils (#38)",
          "is_bot": false,
          "headline": "fix(auth): preserve typed API error envelope when key verification fa…",
          "author_name": "Resque",
          "author_login": "lxcario",
          "committed_at": "2026-07-02T20:43:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "91024301832cbba0e4beb2ef34ad72a8d85712cd",
          "body": "…rd (#37)\n\nassertNotLocal lowercased the hostname but did not strip a trailing dot, so http://localhost. (the FQDN form of localhost, RFC 6761) and http://localhost%2e bypassed the host === 'localhost' loopback check. IP literals are already dot-normalized by the WHATWG URL parser, so only named hosts were affected. Strips one trailing dot before the comparison. Adds 4 regression tests (3 blocked variants + 1 public-FQDN no-false-positive).",
          "is_bot": false,
          "headline": "fix(target-url): treat trailing-dot hostnames as loopback in SSRF gua…",
          "author_name": "Resque",
          "author_login": "lxcario",
          "committed_at": "2026-07-02T20:43:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "547b5be45799f5c8287638eb0ebc6a8bdef4cecb",
          "body": null,
          "is_bot": false,
          "headline": "fix(history): reject fractional page sizes (#55)",
          "author_name": "JerryNee",
          "author_login": "JerryNee",
          "committed_at": "2026-07-02T20:43:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5f7dba1ca26d1bd3b45d1a6eaeabc0f5c4622e80",
          "body": null,
          "is_bot": false,
          "headline": "fix(auth): honor request timeout during configure (#52)",
          "author_name": "JerryNee",
          "author_login": "JerryNee",
          "committed_at": "2026-07-02T20:43:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7928b5ce2f026f397c107bf4172469a1bba2f4b0",
          "body": null,
          "is_bot": false,
          "headline": "fix(help): include request-timeout in global flag guidance (#41)",
          "author_name": "JerryNee",
          "author_login": "JerryNee",
          "committed_at": "2026-07-02T20:43:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9a8a5cdfad3765f28665299b71d2eb6b364a43a6",
          "body": null,
          "is_bot": false,
          "headline": "docs(project): fix create URL flag example (#42)",
          "author_name": "JerryNee",
          "author_login": "JerryNee",
          "committed_at": "2026-07-02T20:43:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3ab8136d509eb99eddd121b3a29e2fd773a1f316",
          "body": "New issue form for hackathon submissions — auto-applies the `hackathon`\nlabel and captures the submitter's Discord identity for reward payout\ncoordination.",
          "is_bot": false,
          "headline": "feat(github): add Hackathon Improvement issue template",
          "author_name": "zeshi-du",
          "author_login": "zeshi-du",
          "committed_at": "2026-06-30T21:24:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c4ebb9ce16dbfe183b75b14399b549a1ecb43cce",
          "body": null,
          "is_bot": false,
          "headline": "release: v0.2.0",
          "author_name": "zeshi-du",
          "author_login": "zeshi-du",
          "committed_at": "2026-06-30T01:33:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "15e95de321a64b3393ec30f58ab34e315480ab87",
          "body": "…t json (#22)\n\nWhen a subcommand fired a parse error (unknown command, missing required\nargument, invalid option), Commander's outputError callback wrote plain\ntext to stderr immediately and the catch block exited 5 with no further\noutput. A machine consumer that always parses stderr as JSON receive\n[…]\nbedding. Four subprocess\nregression tests in the [fix-5] block cover missing-arg, unknown subcommand,\nargv-fallback, and text-mode no-regression paths.\n\nCo-authored-by: zeshi-du <zeshi@testsprite.com>",
          "is_bot": false,
          "headline": "fix(cli): emit JSON envelope for Commander parse errors under --outpu…",
          "author_name": "Rahul Joshi",
          "author_login": "crypticsaiyan",
          "committed_at": "2026-06-25T23:35:44Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b2fae59ba810fd76abc695d777a723f516a10ef3",
          "body": "…on (#21)\n\nA profile name (`--profile` / `TESTSPRITE_PROFILE`) is written verbatim as\nan INI section header (`[name]`) in `~/.testsprite/credentials`, but was\nnever validated. A name containing the characters that break that grammar\nsilently corrupted the file:\n\n  --profile \"prod]\"   -> serialises t\n[…]\nd of\nsilently corrupting or failing to persist credentials.\n\nAdds unit coverage for the guard and the three entry points, plus a\nsubprocess regression.\n\nCo-authored-by: Zeshi Du <duke.zeshi@gmail.com>",
          "is_bot": false,
          "headline": "fix(cli): validate profile names to prevent credentials-file corrupti…",
          "author_name": "Awokoya Olawale Davidson",
          "author_login": "Davidson3556",
          "committed_at": "2026-06-25T23:35:25Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "97c04a4ce935baafa3690b4f1430193b80be16c9",
          "body": "… (#23)\n\nCo-authored-by: zeshi-du <zeshi@testsprite.com>",
          "is_bot": false,
          "headline": "fix(bundle): add retry loop to streamUrlToFile for transport failures…",
          "author_name": "Rahul Joshi",
          "author_login": "crypticsaiyan",
          "committed_at": "2026-06-25T23:35:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1f37de11097e4f4c67510fd302b059d695bde1b5",
          "body": "runFailureGet now resolves and validates --out via resolveBundleDir and assertOutDirParentExists before calling GET /tests/{id}/failure, matching runArtifactGet and runCodeGet fast-fail behavior.\n\nAdds regression tests asserting zero fetch calls on empty --out and missing parent dir paths.",
          "is_bot": false,
          "headline": "fix(test): validate failure get --out before API fetch (#26)",
          "author_name": "Sahil Rakhaiya",
          "author_login": "SahilRakhaiya05",
          "committed_at": "2026-06-25T23:19:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3b7ce0729c00bd2f8fdd5285f5efbdafb38d6271",
          "body": "…RROR (#19)\n\nA malformed API endpoint produced an opaque or misleading failure instead\nof a clear config error:\n\n  --endpoint-url \"not a url\"   -> `Error: Invalid URL` (exit 1, a raw\n                                  `new URL()` throw with no guidance)\n  --endpoint-url \"localhost:3000\" (missing sche\n[…]\nxisting\nself-hosted/CI configs and the test suite's localhost mock backend are\nunaffected.\n\nAdds unit coverage for assertValidEndpointUrl and the two makeHttpClient\npaths, plus subprocess regressions.",
          "is_bot": false,
          "headline": "fix(cli): reject a malformed --endpoint-url with a clear VALIDATION_E…",
          "author_name": "Awokoya Olawale Davidson",
          "author_login": "Davidson3556",
          "committed_at": "2026-06-25T23:19:02Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4dac1d68388d8413be66e07cd5f25204a7c96453",
          "body": "Batch-rerun chunks (>50 testIds) were dispatched concurrently via\nPromise.all. The backend's producer/teardown closure dedup happens\nper-request, not across requests, so two concurrent chunks sharing a\nproject's producer could each independently decide to trigger it,\ndouble-running the producer or t\n[…]\nd layer, warning on stderr if a duplicate trigger is\ndetected.\n\nFixed a pre-existing test whose fixture relied on the old\ndouble-counting behavior (same accepted entry returned from every\nretry call).",
          "is_bot": false,
          "headline": "fix(test): dedupe and serialize chunked batch-rerun dispatch (#9)",
          "author_name": "Rahul Joshi",
          "author_login": "crypticsaiyan",
          "committed_at": "2026-06-25T23:18:58Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "1963461d4bb1d43ce7385e88a9791553c8305701",
          "body": "…(#7)\n\ntest code get --out <path> opened (truncated) the destination file\nbefore the network request. If the GET then failed, or hit the\n\"no code generated yet\" branch which writes nothing, the user's\npre-existing --out file was left emptied with no way to recover it.\n\nWrite to a sibling temp file i\n[…]\ndle.ts already uses for multi-file bundles.\n\nAdd regression tests for both failure modes: a failing fetch and\nthe no-code-yet branch. Both reproduce the truncation on the old\ncode and pass on the fix.",
          "is_bot": false,
          "headline": "fix(test): atomic write for code get --out, no truncate before fetch …",
          "author_name": "Rahul Joshi",
          "author_login": "crypticsaiyan",
          "committed_at": "2026-06-25T23:18:55Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5ebcba856f9afe56b477bceaa97574c59c6c1a30",
          "body": "fix(test): prevent batch-run scheduler from serializing after first wave",
          "is_bot": false,
          "headline": "Merge pull request #6 from crypticsaiyan/fix/batch-run-concurrency",
          "author_name": "ruili-testsprite",
          "author_login": "ruili-testsprite",
          "committed_at": "2026-06-25T22:37:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fc928772ae22e3d294f98fab9b990afb4d1ae9b5",
          "body": "create-batch --run launched its first concurrencyLimit triggers in\nparallel, but the steady-state loop awaited each subsequent job to\nfully finish (trigger + full --wait poll) before launching the next\none. Effective concurrency dropped to 1 after the initial wave\nregardless of --max-concurrency.\n\nS\n[…]\n(), never await a whole job inline.\n\nAdd a regression test using equal-delay trigger responses so the\nfirst wave settles in the same microtask batch, which is the exact\ncondition that exposed the bug.",
          "is_bot": false,
          "headline": "fix(test): batch-run scheduler serializes after first wave",
          "author_name": "Rahul Joshi",
          "author_login": "crypticsaiyan",
          "committed_at": "2026-06-23T10:55:45Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "18f6e6ee1c0dd131b5015bf58d56a2496086f8a6",
          "body": "- Onboarding consolidated into `testsprite setup` (formerly `init`); the\n  granular auth commands remain as hidden, deprecated aliases.\n- CLI reports its version in the User-Agent header.\n- README: the launch video no longer renders as a bare URL on npm.",
          "is_bot": false,
          "headline": "release: v0.1.2",
          "author_name": "zeshi-du",
          "author_login": "zeshi-du",
          "committed_at": "2026-06-20T03:43:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4b33601285a95e8ffe346eb87c572ee708d007d0",
          "body": "ci(release): switch npm publish to OIDC trusted publishing",
          "is_bot": false,
          "headline": "Merge pull request #3 from TestSprite/ci/trusted-publishing",
          "author_name": "ruili-testsprite",
          "author_login": "ruili-testsprite",
          "committed_at": "2026-06-12T05:04:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1dce20e73d1004b55e03d45d700d64d7d0be25a1",
          "body": "NPM_TOKEN secret was never configured, so tag-triggered releases failed\nwith ENEEDAUTH. Auth now uses npm trusted publishing (configured on\nnpmjs.com for this repo + release.yaml):\n\n- drop NODE_AUTH_TOKEN env (empty token would shadow OIDC auth)\n- upgrade npm to >= 11.5.1 (trusted publishing requirement; Node 22 bundles 10.x)\n- bump checkout/setup-node to v5 ahead of the June 16 Node 20 runner cutoff",
          "is_bot": false,
          "headline": "ci(release): switch npm publish to OIDC trusted publishing",
          "author_name": "Rui Li",
          "author_login": "ruili-testsprite",
          "committed_at": "2026-06-12T04:59:34Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a8c5e2741498571b5a8c8c30391a07ff9e7cf650",
          "body": "- prettier-clean the README video block (fixes CI format:check on main)\n- bump version to 0.1.1\n- CHANGELOG: add [0.1.1] docs-only entry\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(release): v0.1.1 — README launch-video patch (#2)",
          "author_name": "dukeduke2016",
          "author_login": "dukeduke2016",
          "committed_at": "2026-06-12T02:11:05Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "941cc368c22737894dc1d0ed7b454744e8c91064",
          "body": "Updated the README with a new link and added a video description.",
          "is_bot": false,
          "headline": "Update README with new link and video information",
          "author_name": "ruili-testsprite",
          "author_login": "ruili-testsprite",
          "committed_at": "2026-06-12T01:14:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "25aac12d1666df9b7f8501e0b0c5e93f0863847a",
          "body": "The Lint & Format job runs prettier --check over workflow YAML; the\naligned trailing comment failed it on every push.",
          "is_bot": false,
          "headline": "chore(ci): prettier-clean release.yaml comment spacing",
          "author_name": "zeshi-du",
          "author_login": "zeshi-du",
          "committed_at": "2026-06-11T12:01:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2ae63aadc09b7218da865aa95514d47c2b66f961",
          "body": null,
          "is_bot": false,
          "headline": "chore: initial public snapshot v0.1.0",
          "author_name": "zeshi-du",
          "author_login": "zeshi-du",
          "committed_at": "2026-06-11T11:49:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        }
      ],
      "releases_count": 5,
      "commits_last_year": 96,
      "latest_release_at": "2026-07-17T02:41:43Z",
      "latest_release_tag": "v0.4.0",
      "releases_from_tags": false,
      "days_since_last_push": 1,
      "active_weeks_last_year": 6,
      "days_since_latest_release": 4,
      "mean_days_between_releases": 8.8
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": true,
      "health_percentage": 100,
      "has_issue_template": false,
      "has_code_of_conduct": true,
      "has_pull_request_template": true
    },
    "ecosystem": {
      "packages": [
        {
          "name": "@testsprite/testsprite-cli",
          "exists": true,
          "license": "Apache-2.0",
          "keywords": [
            "testsprite",
            "cli",
            "testing",
            "automation"
          ],
          "ecosystem": "npm",
          "matches_repo": true,
          "registry_url": "https://www.npmjs.com/package/@testsprite/testsprite-cli",
          "is_deprecated": false,
          "latest_version": "0.4.0",
          "repository_url": "https://github.com/TestSprite/testsprite-cli",
          "versions_count": 6,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": 4,
          "monthly_downloads": 3374,
          "first_published_at": "2026-06-11T12:07:27.101000Z",
          "latest_published_at": "2026-07-17T01:34:13.879000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 4
        }
      ]
    },
    "popularity": {
      "forks": 98,
      "stars": 2415,
      "watchers": 3,
      "fork_history": {
        "days": [
          {
            "date": "2026-06-12",
            "count": 2
          },
          {
            "date": "2026-06-13",
            "count": 4
          },
          {
            "date": "2026-06-15",
            "count": 2
          },
          {
            "date": "2026-06-16",
            "count": 2
          },
          {
            "date": "2026-06-17",
            "count": 5
          },
          {
            "date": "2026-06-18",
            "count": 1
          },
          {
            "date": "2026-06-19",
            "count": 5
          },
          {
            "date": "2026-06-20",
            "count": 2
          },
          {
            "date": "2026-06-21",
            "count": 4
          },
          {
            "date": "2026-06-22",
            "count": 1
          },
          {
            "date": "2026-06-23",
            "count": 7
          },
          {
            "date": "2026-06-24",
            "count": 4
          },
          {
            "date": "2026-06-25",
            "count": 3
          },
          {
            "date": "2026-06-26",
            "count": 2
          },
          {
            "date": "2026-06-27",
            "count": 3
          },
          {
            "date": "2026-06-28",
            "count": 1
          },
          {
            "date": "2026-06-29",
            "count": 4
          },
          {
            "date": "2026-06-30",
            "count": 1
          },
          {
            "date": "2026-07-01",
            "count": 9
          },
          {
            "date": "2026-07-02",
            "count": 4
          },
          {
            "date": "2026-07-03",
            "count": 2
          },
          {
            "date": "2026-07-04",
            "count": 2
          },
          {
            "date": "2026-07-05",
            "count": 1
          },
          {
            "date": "2026-07-06",
            "count": 1
          },
          {
            "date": "2026-07-07",
            "count": 5
          },
          {
            "date": "2026-07-08",
            "count": 3
          },
          {
            "date": "2026-07-09",
            "count": 2
          },
          {
            "date": "2026-07-10",
            "count": 4
          },
          {
            "date": "2026-07-11",
            "count": 1
          },
          {
            "date": "2026-07-12",
            "count": 1
          },
          {
            "date": "2026-07-13",
            "count": 1
          },
          {
            "date": "2026-07-14",
            "count": 1
          },
          {
            "date": "2026-07-16",
            "count": 2
          },
          {
            "date": "2026-07-18",
            "count": 1
          },
          {
            "date": "2026-07-19",
            "count": 2
          },
          {
            "date": "2026-07-20",
            "count": 1
          },
          {
            "date": "2026-07-21",
            "count": 2
          }
        ],
        "complete": true,
        "collected": 98,
        "total_forks": 98
      },
      "star_history": {
        "days": [
          {
            "date": "2026-07-01",
            "count": 58
          },
          {
            "date": "2026-07-02",
            "count": 78
          },
          {
            "date": "2026-07-03",
            "count": 70
          },
          {
            "date": "2026-07-04",
            "count": 145
          },
          {
            "date": "2026-07-05",
            "count": 177
          },
          {
            "date": "2026-07-06",
            "count": 100
          },
          {
            "date": "2026-07-07",
            "count": 78
          },
          {
            "date": "2026-07-08",
            "count": 70
          },
          {
            "date": "2026-07-09",
            "count": 60
          },
          {
            "date": "2026-07-10",
            "count": 45
          },
          {
            "date": "2026-07-11",
            "count": 18
          },
          {
            "date": "2026-07-12",
            "count": 9
          },
          {
            "date": "2026-07-13",
            "count": 6
          },
          {
            "date": "2026-07-14",
            "count": 4
          },
          {
            "date": "2026-07-15",
            "count": 6
          },
          {
            "date": "2026-07-16",
            "count": 5
          },
          {
            "date": "2026-07-17",
            "count": 14
          },
          {
            "date": "2026-07-18",
            "count": 11
          },
          {
            "date": "2026-07-19",
            "count": 9
          },
          {
            "date": "2026-07-20",
            "count": 10
          },
          {
            "date": "2026-07-21",
            "count": 27
          }
        ],
        "complete": false,
        "collected": 1000,
        "total_stars": 2415
      },
      "open_issues_and_prs": 45
    },
    "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": 441972,
      "source_files_sampled": 115,
      "oversized_source_files": 6,
      "agent_instruction_files": [],
      "agent_instruction_max_bytes": null
    },
    "dependencies": {
      "manifests": [
        "package.json"
      ],
      "advisories": {
        "error": null,
        "scope": null,
        "source": null,
        "findings": [],
        "collected": false,
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 0,
        "assessed_package": null,
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "npm"
      ],
      "dependencies": [
        {
          "name": "commander",
          "manifest": "package.json",
          "ecosystem": "npm",
          "version_constraint": "^12.1.0"
        },
        {
          "name": "undici",
          "manifest": "package.json",
          "ecosystem": "npm",
          "version_constraint": "^7.16.0"
        },
        {
          "name": "valibot",
          "manifest": "package.json",
          "ecosystem": "npm",
          "version_constraint": "^1.4.1"
        }
      ],
      "all_dependencies": {
        "error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
        "source": null,
        "packages": [],
        "collected": false,
        "truncated": false,
        "total_count": null,
        "direct_count": null,
        "indirect_count": null
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 16,
        "merged_prs": 85,
        "open_issues": 29,
        "closed_ratio": 0.701,
        "closed_issues": 68,
        "closed_unmerged_prs": 69
      },
      "bus_factor": 5,
      "bot_contributors": 1,
      "top_contributors": [
        {
          "type": "User",
          "login": "Andy00L",
          "commits": 12,
          "avatar_url": "https://avatars.githubusercontent.com/u/89641810?v=4"
        },
        {
          "type": "User",
          "login": "JerryNee",
          "commits": 12,
          "avatar_url": "https://avatars.githubusercontent.com/u/37407632?v=4"
        },
        {
          "type": "User",
          "login": "lxcario",
          "commits": 11,
          "avatar_url": "https://avatars.githubusercontent.com/u/208051869?v=4"
        },
        {
          "type": "User",
          "login": "Davidson3556",
          "commits": 8,
          "avatar_url": "https://avatars.githubusercontent.com/u/99369614?v=4"
        },
        {
          "type": "User",
          "login": "zeshi-du",
          "commits": 8,
          "avatar_url": "https://avatars.githubusercontent.com/u/257381225?v=4"
        },
        {
          "type": "User",
          "login": "crypticsaiyan",
          "commits": 7,
          "avatar_url": "https://avatars.githubusercontent.com/u/186129212?v=4"
        },
        {
          "type": "User",
          "login": "naufalfx805-source",
          "commits": 7,
          "avatar_url": "https://avatars.githubusercontent.com/u/266911045?v=4"
        },
        {
          "type": "User",
          "login": "SahilRakhaiya05",
          "commits": 4,
          "avatar_url": "https://avatars.githubusercontent.com/u/144577420?v=4"
        },
        {
          "type": "User",
          "login": "ahndohun",
          "commits": 4,
          "avatar_url": "https://avatars.githubusercontent.com/u/19940813?v=4"
        },
        {
          "type": "User",
          "login": "ruili-testsprite",
          "commits": 4,
          "avatar_url": "https://avatars.githubusercontent.com/u/170984446?v=4"
        }
      ],
      "contributors_sampled": 22,
      "top_contributor_share": 0.126
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "backport-dispatch.yml",
        "ci-nudge.yml",
        "ci.yml",
        "issue-triage.yml",
        "pr-triage.yml",
        "release.yaml",
        "stale.yml",
        "test-coverage.yml"
      ],
      "has_docs_dir": true,
      "linter_configs": [
        "eslint.config.mjs"
      ],
      "has_editorconfig": false,
      "has_linter_config": true,
      "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": 5,
            "reason": "branch protection is not maximal on development and all release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 10,
            "reason": "28 out of 28 merged PRs checked by a CI test -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
          },
          {
            "name": "CII-Best-Practices",
            "score": 0,
            "reason": "no effort to earn an OpenSSF best practices badge detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
          },
          {
            "name": "Code-Review",
            "score": 9,
            "reason": "Found 26/27 approved changesets -- score normalized to 9",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 3,
            "reason": "project has 1 contributing companies or organizations -- score normalized to 3",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": 10,
            "reason": "no dangerous workflow patterns detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 10,
            "reason": "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": 9,
            "reason": "dependency not pinned by hash detected -- score normalized to 9",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "SAST tool is not run on all commits -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 10,
            "reason": "security policy file 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": 9,
            "reason": "detected GitHub workflow tokens with excessive permissions",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 1,
            "reason": "9 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "2708a4069fba72822f94906d05001b4d19e66d9c",
        "ran_at": "2026-07-21T18:26:19Z",
        "aggregate_score": 6.3,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": true,
      "has_dependabot_config": true
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/TestSprite/testsprite-cli",
    "host": "github.com",
    "name": "testsprite-cli",
    "owner": "TestSprite"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "good",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 76,
      "inputs": {
        "security": 63,
        "vitality": 75,
        "community": 76,
        "governance": 75,
        "engineering": 90
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 75,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "moderate",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 58,
            "inputs": {
              "commits_last_year": 96,
              "human_commit_share": 0.99,
              "days_since_last_push": 1,
              "active_weeks_last_year": 6
            },
            "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": "6/52 weeks with commits",
                "points": 4.2,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 6
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "96 commits in the last year",
                "points": 17.8,
                "status": "partial",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 96
                    }
                  }
                ],
                "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": 100,
            "inputs": {
              "releases_count": 5,
              "latest_release_tag": "v0.4.0",
              "releases_from_tags": false,
              "days_since_latest_release": 4,
              "mean_days_between_releases": 8.8
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "5 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 5
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 4 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 4
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~8.8 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 8.8
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "unverified",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": "repository_too_young",
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": null,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "maintenance record not established from the collected data",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_unverified",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "good",
        "name": "Community & Adoption",
        "value": 76,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "good",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 73,
            "inputs": {
              "forks": 98,
              "stars": 2415,
              "watchers": 3,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "window_too_short"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "2,415 stars",
                "points": 54.9,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 2415
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "98 forks",
                "points": 16.6,
                "status": "partial",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 98
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "3 watchers",
                "points": 1.7,
                "status": "partial",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 3
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "excellent",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 92,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "has_contributing": true,
              "has_issue_template": false,
              "has_code_of_conduct": true,
              "has_pull_request_template": true
            },
            "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": 13.5,
                "status": "met",
                "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": 6.3,
                "status": "met",
                "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": 59,
            "inputs": {
              "packages": [
                "@testsprite/testsprite-cli"
              ],
              "dependents": null,
              "ecosystems": "npm",
              "total_downloads": null,
              "monthly_downloads": 3374
            },
            "components": [
              {
                "key": "monthly_downloads",
                "name": "Monthly downloads",
                "detail": "3,374 downloads/month across npm",
                "points": 47,
                "status": "partial",
                "details": [
                  {
                    "code": "downloads_monthly",
                    "params": {
                      "count": 3374,
                      "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": "good",
        "name": "Sustainability & Governance",
        "value": 75,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "good",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 82,
            "inputs": {
              "bus_factor": 5,
              "contributors_sampled": 22,
              "top_contributor_share": 0.126
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "5 contributor(s) cover half of all commits",
                "points": 45.9,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 5
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 13% of commits",
                "points": 19.7,
                "status": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 13
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "22 contributors",
                "points": 13.5,
                "status": "met",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 22
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 1 contributing companies or organizations -- score normalized to 3",
                "points": 3,
                "status": "partial",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "moderate",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 67,
            "inputs": {
              "merged_prs": 85,
              "open_issues": 29,
              "closed_issues": 68,
              "issue_closed_ratio": 0.701,
              "closed_unmerged_prs": 69
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "70% of issues closed",
                "points": 32.8,
                "status": "partial",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 70
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "85/154 decided PRs merged",
                "points": 21.1,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 85,
                      "decided": 154
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 26/27 approved changesets -- score normalized to 9",
                "points": 13.5,
                "status": "partial",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "moderate",
            "name": "Ownership & stewardship",
            "note": null,
            "notes": [],
            "value": 53,
            "inputs": {
              "followers": 71,
              "owner_type": "Organization",
              "is_verified": null,
              "owner_login": "TestSprite",
              "public_repos": 4,
              "account_age_days": 784
            },
            "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": "71 followers of TestSprite",
                "points": 13.4,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 71,
                      "login": "TestSprite"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "4 public repos, account ~2 yr old",
                "points": 9.4,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 4
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 2
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "@testsprite/testsprite-cli"
              ],
              "ecosystems": "npm",
              "any_deprecated": false,
              "min_days_since_publish": 4
            },
            "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 4 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 4
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "6 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 6
                    }
                  }
                ],
                "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": "excellent",
        "name": "Engineering Quality",
        "value": 90,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "good",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 84,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": true,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "8 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 8
                    }
                  }
                ],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 24,
                "status": "met",
                "details": [],
                "max_points": 24
              },
              {
                "key": "linter_config",
                "name": "Linter config",
                "detail": "eslint.config.mjs",
                "points": 16,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "eslint.config.mjs"
                    }
                  }
                ],
                "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": "28 out of 28 merged PRs checked by a CI test -- score normalized to 10",
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "excellent",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "topics": [
                "ai",
                "cli",
                "e2e-testing",
                "playwright",
                "qa",
                "test-automation",
                "testing"
              ],
              "has_wiki": true,
              "homepage": "https://www.testsprite.com",
              "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://www.testsprite.com",
                "points": 15,
                "status": "met",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": "7 topics",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "topics_count",
                    "params": {
                      "count": 7
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "moderate",
        "name": "Security",
        "value": 63,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "moderate",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): Packaging, Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "packaging",
                    "signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 63,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 16,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 2,
              "scorecard_aggregate": 6.3
            },
            "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 is not maximal on development and all release branches",
                "points": 3.8,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "28 out of 28 merged PRs checked by a CI test -- score normalized to 10",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "cii_best_practices",
                "name": "CII-Best-Practices",
                "detail": "no effort to earn an OpenSSF best practices badge detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "code_review",
                "name": "Code-Review",
                "detail": "Found 26/27 approved changesets -- score normalized to 9",
                "points": 6.8,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 1 contributing companies or organizations -- score normalized to 3",
                "points": 0.8,
                "status": "partial",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no dangerous workflow patterns detected",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "update tool detected",
                "points": 7.5,
                "status": "met",
                "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 9",
                "points": 4.5,
                "status": "partial",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "SAST tool is not run on all commits -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file detected",
                "points": 5,
                "status": "met",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "detected GitHub workflow tokens with excessive permissions",
                "points": 6.8,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "9 existing vulnerabilities detected",
                "points": 0.8,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "excellent",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "review_only_matches": 0,
              "assessed_self_published_locations": 5
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "moderate",
        "name": "AI Readiness",
        "value": 69,
        "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": 0.989,
              "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": "94 of 95 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 94,
                      "sampled": 95
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "good",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 81,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "package-lock.json"
              ],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": true,
              "typecheck_configs": [
                "tsconfig.json"
              ],
              "agent_commit_share": 0.094,
              "toolchain_manifests": [],
              "dependency_bot_commit_share": 0.01
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": "eslint.config.mjs",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "eslint.config.mjs"
                    }
                  }
                ],
                "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": "9 of the last 96 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 9,
                      "sampled": 96
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "1 of the last 96 commits are automated dependency updates",
                "points": 8,
                "status": "met",
                "details": [
                  {
                    "code": "dependency_bot_commits",
                    "params": {
                      "count": 1,
                      "sampled": 96
                    }
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 9",
                "points": 9,
                "status": "partial",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "excellent",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 97,
            "inputs": {
              "primary_language": "TypeScript",
              "largest_source_bytes": 441972,
              "source_files_sampled": 115,
              "oversized_source_files": 6
            },
            "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": "6/115 source files over 60KB",
                "points": 52.1,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 115,
                      "oversized": 6
                    }
                  }
                ],
                "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": [
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
    "deps.dev does not index npm:@testsprite/testsprite-cli@0.4.0; advisories assessed against the repository dependency graph instead"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-21T18:26:46.106861Z",
  "schema_version": "0.23.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/t/TestSprite/testsprite-cli.svg",
  "full_name": "TestSprite/testsprite-cli",
  "license_state": "standard",
  "license_spdx": "Apache-2.0"
}

Scores are signals, not warranties. They reflect publicly visible practices on GitHub — not a code audit, and not a security guarantee.

Missing data is excluded and weights renormalized, never scored as zero. Methodology is versioned and open: metrics v1.13.0, schema v0.23.0 — full methodology · metrics wiki.

How one result sits in the wider record: aggregate statisticsnpm.