Registro público
Informe de salud del softwareesquema 0.30.0 · métricas 2.3.1 · 2026-08-03 04:51 UTC

OpenRouterTeam / typescript-agent

OpenRouter Agent SDK

TypeScriptSin licencia detectada★ 19 estrellas⑂ 11 forksdesde mar 2026Ver en GitHub ↗
TipoServidor MCPBibliotecacómo se determina

OpenRouterTeam/typescript-agent tiene un índice de salud de 73 sobre 100, lo que lo sitúa en la banda Bueno. Su puntuación más alta es Vitality (85/100) y la más baja, Community & Adoption (44/100). Se actualizó por última vez hace 2 días. Una sola persona concentra la mayor parte del trabajo reciente.

73
global / 100
Bueno

Índice de salud del software

Las métricas se agrupan en categorías ponderadas sobre una escala estandarizada de 1 a 100. El resultado global parte de su media ponderada, calibrada contra la distribución del registro público para que las bandas tengan significado percentil; cuando la evidencia pública activa la Política de Jurisdicciones de Alto Riesgo, la calificación se ajusta y recibe un límite «En riesgo» de 34.

73
Excepcional93-100El nivel más alto del registro (≈ el 5% superior); cumple prácticamente todos los criterios evaluados
Excelente80-92Sólido en todos los frentes; carencias menores
Bueno65-79Saludable; carencias limitadas y manejables
Moderado50-64Aceptable con carencias notables; se recomienda revisión
Débil35-49Debilidades sustanciales en varias áreas
En riesgo20-34Debilidades significativas; su adopción exige cautela
Crítico1-19Problemas graves (proyecto abandonado, un solo mantenedor, sin higiene)
VitalidadComunidad yAdopciónSostenibilidady GobernanzaCalidad deIngenieríaSeguridadPreparaciónpara IA

Perfil de puntuación

Cada eje es una categoría. La forma importa más que la media: un proyecto sano llena toda la figura, mientras que un perfil de picos y cráteres indica que la fortaleza en una dimensión enmascara el riesgo en otra.

El resultado global ponderado 64 se calibra a 73 en la escala publicada del índice (calibración del registro 2026-08-02).

Titularidad

OpenRouterOrganización
3536 seguidores36 repositorios públicosdesde jul 2023

Este repositorio está respaldado por una organización: una custodia compartida y responsable que puede sobrevivir a cualquier mantenedor individual.

Ecosistemas de paquetes

RegistroPaqueteVersiónDescargas / mesVersionesÚltima publicaciónEtiquetas
npm@openrouter/mcp0.0.11331hace 9 díasopenroutermcpmodel-context-protocolagenttypescriptaitoolsllm
npm@openrouter/agent0.8.0382.45413hace 11 díasopenrouteragenttypescriptaitoolsstreamingllm

Métricas por categoría

Vitalidad

¿Está vivo el proyecto: se escribe código y se publican versiones?

85Excelente · 21% del índice global
Cómo se puntúa
36/36Recencia de push — último push hace 2 días
11.1/36Cadencia de commits — 16/52 semanas con commits
18/18Volumen de commits — 152 commits en el último año
10/10OpenSSF Scorecard: Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Datos de entrada utilizados
commits_last_year152
human_commit_share0,94
days_since_last_push2
active_weeks_last_year16
Cómo se puntúa
27/27Publica versiones — 7 versiones publicadas
36/36Recencia de las versiones — última versión hace 11 días
27/27Cadencia de publicación — una versión cada ~13 días
0/10OpenSSF Scorecard: Signed-Releases — sin datos
Datos de entrada utilizados
releases_count7
latest_release_tag@openrouter/agent@0.8.0
releases_from_tagsno
days_since_latest_release11
mean_days_between_releases13
Excluidos de la puntuación (sin datos o no aplicable): OpenSSF Scorecard: Signed-Releases. Los pesos restantes se han renormalizado.

Comunidad y Adopción

¿Tiene el proyecto usuarios, descargas, atención y unas condiciones acogedoras para quienes contribuyen?

44Débil · 17% del índice global
Cómo se puntúa
20.4/60Estrellas — 19 estrellas
8.3/25Forks — 11 forks
0/15Observadores — 0 observadores
Datos de entrada utilizados
forks11
stars19
watchers0
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Cómo se puntúa
22.5/22.5README
0/22.5Licencia — no se detectó ningún archivo de licencia
0/18Guía CONTRIBUTING
0/13.5Código de conducta
0/7.2Plantilla de issues
0/6.3Plantilla de PR
Datos de entrada utilizados
has_readme
has_licenseno
readme_badges0
has_contributingno
has_issue_templateno
has_code_of_conductno
readme_badge_services
has_pull_request_templateno
Cómo se puntúa
74.4/80Descargas mensuales — 382.587 descargas/mes en npm
0/20Dependientes en el registro — no lo informa este ecosistema
Datos de entrada utilizados
packages@openrouter/mcp, @openrouter/agent
dependents
ecosystemsnpm
total_downloads
monthly_downloads382.587
Excluidos de la puntuación (sin datos o no aplicable): Dependientes en el registro. Los pesos restantes se han renormalizado.

Sostenibilidad y Gobernanza

¿Sobrevivirá el proyecto a sus personas: factor bus, capacidad de respuesta, quién lo respalda y mantenimiento del paquete?

60Moderado · 23% del índice global
Cómo se puntúa
9/54Factor bus — la mitad de los commits recae en 1 contribuyente(s)
5.8/22.5Distribución de commits — el principal contribuyente firma el 74% de los commits
12.2/13.5Amplitud de contribuyentes — 9 contribuyentes
10/10OpenSSF Scorecard: Contributors — project has 5 contributing companies or organizations
Datos de entrada utilizados
bus_factor1
contributors_sampled9
top_contributor_share0,743
Cómo se puntúa
6/42Resolución de issues — 14% de issues cerradas
23.8/30Aceptación de PR — 58/73 PR decididos fusionados
7.5/13Newcomer PR acceptance — 15/26 PR de contribuyentes primerizos fusionados en 30 d
6/15OpenSSF Scorecard: Code-Review — Found 8/18 approved changesets -- score normalized to 4
Datos de entrada utilizados
merged_prs58
open_issues6
closed_issues1
prs_merged_7d3
prs_decided_7d3
prs_merged_30d17
prs_decided_30d29
issue_closed_ratio0,143
closed_unmerged_prs15
first_time_authors_30d3
first_time_prs_merged_30d15
first_time_prs_decided_30d26
Cómo se puntúa
30/30Respaldo de la propiedad — propiedad de una organización
0/20Dominio verificado
25/25Alcance del propietario — 3536 seguidores de OpenRouterTeam
17.5/25Trayectoria — 36 repos públicos, cuenta de ~3 años
Datos de entrada utilizados
followers3536
owner_typeOrganization
is_verified
owner_loginOpenRouterTeam
public_repos36
account_age_days1117
Cómo se puntúa
25/25Publicado y resoluble — 2 paquete(s) en npm
35/35Recencia de publicación — última publicación hace 9 días
20/20Historial de versiones — 13 versiones en el registro
20/20No obsoleto — activo, ni obsoleto ni retirado
Datos de entrada utilizados
packages@openrouter/mcp, @openrouter/agent
ecosystemsnpm
any_deprecatedno
min_days_since_publish9

Calidad de Ingeniería

¿Existen unas prácticas mínimas de ingeniería y documentación?

75Bueno · 19% del índice global
Cómo se puntúa
24/24Flujos de trabajo de CI — 3 flujo(s) de trabajo
24/24Pruebas presentes
16/16Configuración de linter — biome.json
0/9.6Hooks de pre-commit
0/6.4.editorconfig
18/20OpenSSF Scorecard: CI-Tests — 18 out of 19 merged PRs checked by a CI test -- score normalized to 9
Datos de entrada utilizados
has_ci
has_tests
has_editorconfigno
has_linter_config
has_precommit_configno
Cómo se puntúa
30/30README
0/25Directorio de documentación
15/15Sitio de documentación / página del proyecto — https://openrouter.ai/docs/sdks/typescript/call-model
10/10Descripción del repositorio
0/10Topics
10/10Wiki
Datos de entrada utilizados
topics
has_wiki
homepagehttps://openrouter.ai/docs/sdks/typescript/call-model
has_readme
has_docs_dirno
has_description

Seguridad

¿Son sólidas las prácticas visibles de seguridad y de cadena de suministro, sin exposición jurisdiccional de alto riesgo sin resolver?

50Moderado · 16% del índice global
Cómo se puntúa
7.5/7.5Binary-Artifacts — no binaries found in the repo
2.2/7.5Branch-Protection — branch protection is not maximal on development and all release branches
2.2/2.5CI-Tests — 18 out of 19 merged PRs checked by a CI test -- score normalized to 9
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
3/7.5Code-Review — Found 8/18 approved changesets -- score normalized to 4
2.5/2.5Contributors — project has 5 contributing companies or organizations
10/10Dangerous-Workflow — no dangerous workflow patterns detected
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
0/2.5Licencia — license file not detected
7.5/7.5Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
0/5Packaging — sin datos
0/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
0/5SAST — SAST tool is not run on all commits -- score normalized to 0
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — sin datos
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
0/7.5Vulnerabilities — 16 existing vulnerabilities detected
Datos de entrada utilizados
sourceopenssf_scorecard
checks_evaluated16
scorecard_versionv5.5.0
checks_inconclusive2
scorecard_aggregate3,8
Excluidos de la puntuación (sin datos o no aplicable): packaging, signed_releases. Los pesos restantes se han renormalizado.
Cómo se puntúa
35/35Dependencias directas libres de avisos conocidos — ninguna dependencia directa tiene un aviso conocido
25/25Dependencias indirectas libres de avisos conocidos — ninguna dependencia indirecta tiene un aviso conocido
0/40Sin avisos pendientes — ningún aviso tiene fecha de publicación
Datos de entrada utilizados
sourceosv
advisories0
affected_packages0
assessed_packages95
unassessed_packages0
affected_by_severitynone
direct_affected_packages0
Excluidos de la puntuación (sin datos o no aplicable): Sin avisos pendientes. Los pesos restantes se han renormalizado. Se cotejó el cierre de dependencias en tiempo de ejecución de npm:@openrouter/mcp@0.0.1 —lo que arrastra la instalación del paquete publicado—: 95 paquetes. No se analiza la alcanzabilidad.

Preparación para IA

¿Hasta qué punto está el repositorio preparado para desarrollarse y mantenerse con agentes de codificación de IA? Tiene un peso deliberadamente pequeño (4%): las herramientas para agentes son una señal real de mantenimiento, pero un repositorio sin ninguna puede alcanzar igualmente 100/100.

55Moderado · 4% del índice global
Cómo se puntúa
0/45Instrucciones para agentes — sin CLAUDE.md / AGENTS.md / reglas de editor
0/15Documentación legible por máquinas (llms.txt)
40/40Historial de commits legible — 89 de 94 commits humanos declaran su intención (asunto estructurado o cuerpo explicativo)
Datos de entrada utilizados
has_llms_txtno
legible_history_share0,947
agent_instruction_files
agent_instruction_max_bytes
Cómo se puntúa
0/18Arranque con un solo comando
22/22Pruebas automatizadas
11/11Configuración de lint / formato — biome.json
11/11Verificación estática de tipos — packages/agent/tsconfig.json, packages/mcp/tsconfig.json
10/10Entorno reproducible — lockfile
10/10Práctica demostrada con agentes — 12 de los últimos 100 commits con autoría o crédito de agente
0/8Mantenimiento automatizado — no se observan actualizaciones automáticas de dependencias
0/10OpenSSF Scorecard: Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
Datos de entrada utilizados
has_nixno
has_tests
lockfilespnpm-lock.yaml
has_dockerfileno
typed_language
bootstrap_files
has_devcontainerno
has_linter_config
typecheck_configspackages/agent/tsconfig.json, packages/mcp/tsconfig.json
agent_commit_share0,12
toolchain_manifests
dependency_bot_commit_share0
Cómo se puntúa
45/45Código verificable por tipos — TypeScript (tipado estático)
54.1/55Tamaños de archivo manejables — 2/120 archivos fuente de más de 60 KB
Datos de entrada utilizados
primary_languageTypeScript
largest_source_bytes181.323
source_files_sampled120
oversized_source_files2
Cómo se puntúa
0/40Esquema de API (OpenAPI/GraphQL/proto)
20/20Servidor MCP
0/40Ejemplos ejecutables
Datos de entrada utilizados
example_dirs
has_mcp_signal
api_schema_files

Datos clave

19estrellas de GitHub
9contribuidores
152commits en los últimos 12 meses
2días desde el último push
7versiones publicadas
1factor bus
6issues abiertas
npmecosistemas de paquetes

Advertencias de recopilación de datos

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

Más detalle

Historial de estrellas y forks 0 ★ / 11 ⇿
0Estrellas
11Forks
7Versiones

Cuándo se añadió cada estrella y fork, recopilado de GitHub y agrupado por día. El crecimiento acumulado se sitúa justo encima de las adiciones diarias que lo componen, de modo que ambos se leen en conjunto: la acumulación orgánica sostenida no se parece en nada a un pico abrupto y efímero. Cuando esa diferencia es medible, se informa como autenticidad del crecimiento.

0246810121112026-042026-062026-07
Mayor 0Menor 0Parche 1
OpenSSF Scorecard 3.8 / 10
3.8agregado

Evaluación de seguridad independiente y agnóstica en cuanto a herramientas, procedente del proyecto de código abierto OpenSSF Scorecard. Cada comprobación premia una práctica de seguridad, no la herramienta de un proveedor concreto. Las comprobaciones que Scorecard no pudo determinar se marcan como n/d y se excluyen de la puntuación de seguridad (nunca se cuentan como cero).Scorecard v5.5.0 · 2026-08-03 04:51 UTC

10Binary-Artifactsno binaries found in the repo
3Branch-Protectionbranch protection is not maximal on development and all release branches
9CI-Tests18 out of 19 merged PRs checked by a CI test -- score normalized to 9
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
4Code-ReviewFound 8/18 approved changesets -- score normalized to 4
10Contributorsproject has 5 contributing companies or organizations
10Dangerous-Workflowno dangerous workflow patterns detected
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
0Licenselicense file not detected
10Maintained30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
n/dPackagingpackaging workflow not detected
0Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 0
0SASTSAST tool is not run on all commits -- score normalized to 0
0Security-Policysecurity policy file not detected
n/dSigned-Releasesno releases found
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
0Vulnerabilities16 existing vulnerabilities detected
Dependencias directas 5
RegistroPaqueteRestricción de versiónManifiesto
npm@openrouter/sdk^0.13.7packages/agent/package.json
npmzod^4.0.0packages/agent/package.json
npm@modelcontextprotocol/sdk^1.29.0packages/mcp/package.json
npm@openrouter/agentworkspace:*packages/mcp/package.json
npmzod^4.0.0packages/mcp/package.json
Todas las dependencias no recopilado

No fue posible recopilar el conjunto de dependencias resuelto para este informe: GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Avisos de dependencias 0

Instalar npm:@openrouter/mcp@0.0.1 arrastra 95 paquetes, directos y transitivos: 0 tienen avisos conocidos, de los cuales 0 son dependencias directas.

Ningún aviso conocido afecta a las dependencias evaluadas.

Un aviso significa que la versión registrada en el grafo de dependencias cae dentro del rango afectado de un aviso. No se analiza la alcanzabilidad, y el grafo incluye fijaciones de desarrollo y prueba: un hallazgo puede referirse al utillaje y no al software distribuido.

Informe JSON sin procesar legible por máquina
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 1889,
      "has_wiki": true,
      "homepage": "https://openrouter.ai/docs/sdks/typescript/call-model",
      "languages": {
        "TypeScript": 1376001
      },
      "pushed_at": "2026-07-31T21:54:32Z",
      "created_at": "2026-03-27T18:10:53Z",
      "owner_type": "Organization",
      "updated_at": "2026-07-30T16:01:38Z",
      "description": "OpenRouter Agent SDK",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": null,
      "default_branch": "main",
      "license_spdx_raw": null,
      "primary_language": "TypeScript",
      "significant_languages": [
        "TypeScript"
      ]
    },
    "owner": {
      "blog": "https://openrouter.ai",
      "name": "OpenRouter",
      "type": "Organization",
      "login": "OpenRouterTeam",
      "company": null,
      "location": null,
      "followers": 3536,
      "avatar_url": "https://avatars.githubusercontent.com/u/139423088?v=4",
      "created_at": "2023-07-13T03:37:47Z",
      "is_verified": null,
      "public_repos": 36,
      "account_age_days": 1117
    },
    "license": {
      "state": "absent",
      "spdx_id": null,
      "raw_spdx": null,
      "file_present": false,
      "scorecard_found": false,
      "profile_has_license": false
    },
    "activity": {
      "releases": [
        {
          "tag": "@openrouter/agent@0.8.0",
          "kind": "other",
          "published_at": "2026-07-22T20:50:38Z"
        },
        {
          "tag": "@openrouter/agent@0.7.2",
          "kind": "other",
          "published_at": "2026-06-17T13:50:00Z"
        },
        {
          "tag": "@openrouter/agent@0.7.1",
          "kind": "other",
          "published_at": "2026-06-03T17:10:40Z"
        },
        {
          "tag": "0.7.1",
          "kind": "patch",
          "published_at": "2026-06-03T14:41:39Z"
        },
        {
          "tag": "@openrouter/agent@0.7.0",
          "kind": "other",
          "published_at": "2026-05-18T21:45:22Z"
        },
        {
          "tag": "@openrouter/agent@0.6.0",
          "kind": "other",
          "published_at": "2026-05-14T15:59:51Z"
        },
        {
          "tag": "@openrouter/agent@0.5.0",
          "kind": "other",
          "published_at": "2026-05-06T00:53:03Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "d03060256c4c7d55432e508544d8d35d2f65d4bb",
          "body": "* ci(release): dispatch the Python and Go ports on publish (HOP C)\n\nThe Python and Go ports of @openrouter/agent track this repo as their reference\nspec, but nothing told them when a version shipped. Both were generated by hand\nagainst 0.7.2 and have sat a minor version behind since — missing HooksM\n[…]\nf the port\n  repos cannot resolve, making them fail on checkout instead of degrading.\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>\nCo-authored-by: LukasParke <luke@openrouter.ai>",
          "is_bot": false,
          "headline": "ci(release): dispatch the Python and Go ports on publish (HOP C) (#84)",
          "author_name": "Luke Parke",
          "author_login": "LukasParke",
          "committed_at": "2026-07-30T15:58:38Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "78c562ef53da0edd84dfbcc6d6ee38a095d72b37",
          "body": "* feat(agent): doom-loop detection for the tool-execution loop\n\nOpt-in via doomLoop on callModel. Deterministic detection of runs that\nstop making progress: consecutive identical tool calls (per-tool\nfingerprint streaks over tool-declared loopKey identity, incl. repeated\nempty and invalid-JSON calls\n[…]\n--------\n\nCo-authored-by: cortex-github-agent[bot] <305999463+cortex-github-agent[bot]@users.noreply.github.com>\nCo-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>",
          "is_bot": false,
          "headline": "feat(agent): doom-loop detection for the tool-execution loop (#73)",
          "author_name": "Luke Parke",
          "author_login": "LukasParke",
          "committed_at": "2026-07-29T17:42:53Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "89ae3ff3f5a6b929337ed347b388937bc80339ac",
          "body": "…flow (#82)\n\n* fix(release): use real npm trusted publishing (OIDC) for publish workflow\n\nThe release workflow claimed to use OIDC but never did. changesets/action\nonly checks `process.env.NPM_TOKEN`, and the workflow passed the secret as\n`NODE_AUTH_TOKEN`, so the action logged \"No NPM_TOKEN found, \n[…]\nhat is the primary release path.\n\nSame doc-drift class flagged in review; no behavior change.\n\nCo-Authored-By: Claude <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(release): use real npm trusted publishing (OIDC) for publish work…",
          "author_name": "Luke Parke",
          "author_login": "LukasParke",
          "committed_at": "2026-07-28T20:26:11Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "fc8a7f7298ed3f9fdbb3009fbfbd1d05ec5a0264",
          "body": "…t npm publish (DEV-684) (#80)\n\n* fix(release): mark @openrouter/mcp private until its first npm publish\n\nThe push-to-main publish leg fails on every release because changeset\npublish retries @openrouter/mcp, whose first-ever publish 404s — trusted\npublishing (OIDC) cannot create a brand-new package\n[…]\nrusted publisher\nconfig still has to happen npm-side before the publish leg can pick it up.\n\nCo-authored-by: Cursor <cursoragent@cursor.com>\n\n---------\n\nCo-authored-by: Cursor <cursoragent@cursor.com>",
          "is_bot": false,
          "headline": "fix(release): reset unpublished @openrouter/mcp to 0.0.1 for its firs…",
          "author_name": "Dennis Jeong",
          "author_login": "w0nche0l",
          "committed_at": "2026-07-22T21:41:37Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "680bceb4598f228d3e2ec58e2416e4335cdff059",
          "body": "Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>",
          "is_bot": true,
          "headline": "chore: version packages (#57)",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-07-22T20:49:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "61a2a9ab312f973b599bad886e97a270f798565f",
          "body": "* docs: update README banner to rebrand design system\n\nGenerated from the openrouter-web monorepo banner template\n(scripts/repo-banners/ — see its AGENTS.md for the process).\nInk background, Volt accent, Gordita/Plus Jakarta Sans type, and the\ncanonical brand lockup, per the rebrand DESIGN.md.\n\n* docs: restore README trailing newline",
          "is_bot": false,
          "headline": "docs: rebrand README banner (#71)",
          "author_name": "Luke Parke",
          "author_login": "LukasParke",
          "committed_at": "2026-07-21T21:37:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6807c51d56a35e07a2c549d92ab6d8a0c106ac0a",
          "body": "…e: true (DEV-658) (#68)\n\n* fix(agent): append default final-answer directive for bare allowFinalResponse: true\n\nBare `allowFinalResponse: true` stripped tools on the forced final turn\nbut gave the model no signal that this was its last turn. Models that\nemit tool-call syntax as text (e.g. GLM) woul\n[…]\nl turn.\n\nChangeset bumped to minor: runs that previously ended on a halted\ntool-call turn now make one additional request by default.\n\n* docs(skill): update example for default-on final turn semantics",
          "is_bot": false,
          "headline": "fix(agent): default final-answer directive for bare allowFinalRespons…",
          "author_name": "Luke Parke",
          "author_login": "LukasParke",
          "committed_at": "2026-07-21T19:20:10Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "620a5c8e42fece2b795a60526a4f9dd229c12f11",
          "body": "* testing actions\n\n* testing actions 2\n\n* testing force node24\n\n* testing force node24 2\n\n* force node24 final note: The warning about using node20 will still be present. However, node24 will be used with the environment variable set\n\n* removed comment from readme\n\n* decided against forcing node24, \n[…]\n chore(ci): bump remaining v4 actions to v6 (structural-gate, bump-openrouter-sdk); restore README trailing newline\n\n---------\n\nCo-authored-by: Luke Parke <5702154+LukasParke@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Fix/force node24 (#36)",
          "author_name": "Logan Lyons",
          "author_login": "okacodes",
          "committed_at": "2026-07-21T15:23:13Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e499be1c336b05238cf7479826675c74dc17a0fc",
          "body": "* testing actions\n\n* testing actions 2\n\n* testing force node24\n\n* testing force node24 2\n\n* force node24 final note: The warning about using node20 will still be present. However, node24 will be used with the environment variable set\n\n* implemented vitest coverage and update vitest to most up to dat\n[…]\ntted coverage artifacts, gitignore coverage/, package-relative coverage glob, align coverage-v8 pin, regen lockfile\n\n---------\n\nCo-authored-by: Luke Parke <5702154+LukasParke@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Feat/vitest upgrade (#37)",
          "author_name": "Logan Lyons",
          "author_login": "okacodes",
          "committed_at": "2026-07-21T15:22:49Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "cb83f45209ff66f8c58077f4e0a85d35f884afdb",
          "body": "…#67)\n\n* feat: add HooksManager lifecycle hook system to callModel (rebased onto main)\n\nSquashed rebase of feat/hooks-manager (fe319a2) onto origin/main (8edae63).\nConflicts resolved:\n- async-params/call-model: keep both allowFinalResponse and hooks options\n- model-result: runToolWithHooks now propa\n[…]\n.ts priming the\nmanager with run B's id and asserting run A's tool hooks still see\nrun A's state id.\n\n---------\n\nCo-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>",
          "is_bot": false,
          "headline": "feat(hooks): PostModelCall telemetry hook + SessionEnd usage totals (…",
          "author_name": "Luke Parke",
          "author_login": "LukasParke",
          "committed_at": "2026-07-17T15:58:23Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c83cceb17ec1d66b9a1fd2d46ac8ac9b6e60fa4c",
          "body": "* feat(agent): versioned ConversationState serialization contract (PR-6)\n\n* fix: address review — restore createInitialState JSDoc placement, validate createdAt/updatedAt in deserializer\n\n* style: fix biome formatting\n\nCo-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.githu\n[…]\nn' alongside id/createdAt/updatedAt\n- new test: reshaped version-2 blob still gets the version error\n\n---------\n\nCo-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>",
          "is_bot": false,
          "headline": "feat(agent): versioned ConversationState serialization contract (#66)",
          "author_name": "Luke Parke",
          "author_login": "LukasParke",
          "committed_at": "2026-07-17T15:55:37Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "09a041ea717b384c6c85d7c81ef391b170b0dd8f",
          "body": "* fix(agent): infer tool context types from contextSchema (PR-3)\n\ntool() now preserves the concrete contextSchema type through its\noverloads: execute's ctx.local is typed from the schema, and\ncallModel's context map slots accept/reject the real per-tool shape.\nNo more 'ctx.local as X' or 'context: m\n[…]\ne behavior change (one sanctioned construction-\ntime write cast for the readonly field).\n\n315 tests green; type gates verified red/green.\n\n* refactor: remove no-op WithConcreteContextSchema per review",
          "is_bot": false,
          "headline": "fix(agent): infer tool context types from contextSchema (#65)",
          "author_name": "Luke Parke",
          "author_login": "LukasParke",
          "committed_at": "2026-07-17T15:55:25Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "80ff8a730292aa00a3acfcce6ab1e9f5a6a7f0de",
          "body": "* feat: add HooksManager lifecycle hook system to callModel (rebased onto main)\n\nSquashed rebase of feat/hooks-manager (fe319a2) onto origin/main (8edae63).\nConflicts resolved:\n- async-params/call-model: keep both allowFinalResponse and hooks options\n- model-result: runToolWithHooks now propagates e\n[…]\nsult-hooks.test.ts priming the\nmanager with run B's id and asserting run A's tool hooks still see\nrun A's state id.\n\n---------\n\nCo-authored-by: Luke Parke <5702154+LukasParke@users.noreply.github.com>",
          "is_bot": false,
          "headline": "feat: add HooksManager lifecycle hook system to callModel (#7)",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-07-17T15:22:49Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e4d06e38215d6eafbd5c198e3485f476e65d26f0",
          "body": "…tools (#64)\n\n* feat(agent): persist unresolved manual tool calls as awaiting_client_tools\n\nManual tools (execute: false) stopped the loop without persisting\nanything; getPendingToolCalls() returned [] and cold-start consumers\ncould not see the calls in serialized state. Persist unresolved manual\nca\n[…]\nPR #63 hardened the no-tool exit to reject empty final outputs\n(validateFinalResponse), which this test's mock tripped after rebase.\nA real resumed response carries assistant content; fixture updated.",
          "is_bot": false,
          "headline": "feat(agent): persist unresolved manual tool calls as awaiting_client_…",
          "author_name": "Luke Parke",
          "author_login": "LukasParke",
          "committed_at": "2026-07-15T17:20:20Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d96cd9fc589c27978bcdc2fd1921f754be88e3f0",
          "body": "… (#63)\n\n* fix(agent): tolerate empty final response after completed tool rounds\n\nMini-class models intermittently return an empty final turn when the\ntool call was the answer; the SDK threw away successful runs. Now:\nretry the follow-up once; if still empty, resolve with empty text.\nstrictFinalResp\n[…]\n\npassed validateFinalResponse but was never executed — silently dropped.\nThe retry now strips those fields (mirroring makeFinalResponseRequest)\nto coerce a text turn, with a test pinning the behavior.",
          "is_bot": false,
          "headline": "fix(agent): tolerate empty final response after completed tool rounds…",
          "author_name": "Luke Parke",
          "author_login": "LukasParke",
          "committed_at": "2026-07-15T16:37:40Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c020bc7c86d2f743ecf9158ca3c9ff7b315e43b3",
          "body": "…(#61)\n\nA resumed ConversationState with a bare-string input pushed the raw\nstring into the request input array; OpenResponses rejects that with a\n400. Use normalizeInputToArray in the history+fresh branch, matching\nthe no-history branch. Found battletesting a production agent.\n\n- 3-line fix in ModelResult.initStream history branch\n- regression test: resume-string-input.test.ts (fails without fix)",
          "is_bot": false,
          "headline": "fix(agent): normalize string input when resuming with loaded history …",
          "author_name": "Luke Parke",
          "author_login": "LukasParke",
          "committed_at": "2026-07-15T16:36:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1362232975f0254343f9842f30ec1b35d391f4fe",
          "body": "…semantics (#62)",
          "is_bot": false,
          "headline": "docs(agent): fix README/API drift — ctx.local, StateAccessor, stream …",
          "author_name": "Luke Parke",
          "author_login": "LukasParke",
          "committed_at": "2026-07-15T16:36:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8edae63f4f6fe89e146f3abbf6d24dab7a164681",
          "body": "… sending broken history (#59)\n\nWhen a round mixes auto-executed tools with manual (execute-less) client\ntools, executeToolRound returns no output for the manual calls, yet the\nloop still made a follow-up request whose input carried the manual\nfunction_call with no matching function_call_output. Pro\n[…]\n loop and surface the response when any tool call in the round\nhas no output — mirroring the existing all-manual hasExecutableToolCalls\nguard — so the caller can execute its manual calls and continue.",
          "is_bot": false,
          "headline": "fix(agent): stop tool loop on unresolved manual tool calls instead of…",
          "author_name": "ayush-or",
          "author_login": "ayush-or",
          "committed_at": "2026-07-08T17:00:04Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4e1f98d74902c845a0be5a7e161be832cce3d25f",
          "body": "…ckage\n\nfeat(mcp): add @openrouter/mcp package",
          "is_bot": false,
          "headline": "Merge pull request #56 from OpenRouterTeam/worktree-openrouter-mcp-pa…",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-06-30T17:59:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d3539eea1056e629cd6930d1682f0496d7e98820",
          "body": "Tighten the fallback test to pin Date.now() substitution (before <= cachedAt <=\nnow) rather than mere non-negativity, catching a regression to a hard-coded\nsentinel.",
          "is_bot": false,
          "headline": "test(mcp): assert negative-cachedAt fallback uses a fresh timestamp",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-06-30T15:05:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "209499abacd6783ee5c98155bb2a676e3932c3f4",
          "body": "…'t untype client tools\n\nAdds a `source: 'client' | 'mcp'` discriminant to ToolExecutionResult and the\nstreaming ToolResultEvent. An MCP tool's `unknown` output no longer collapses the\nwhole result union — narrowing on source keeps client-tool results precise and\nisolates MCP results as unknown.\n\n- \n[…]\n.\n\nVerified: full monorepo build/typecheck/lint/test green (295 agent + 39 mcp tests,\nincl. type-level tests); sentrux structural gate passes (cycles 1->1, quality up,\nno complex-function regression).",
          "is_bot": false,
          "headline": "feat(agent,mcp): discriminate tool results by source so MCP tools don…",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-06-30T15:03:40Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "38bf22d2b7d3a0c12e7bce70465ed68602500e5a",
          "body": "isFiniteEpoch's value>=0 tightening means serializeServer now substitutes\nDate.now() for a negative cachedAt; assert that branch produces a valid,\nnon-negative epoch that passes the read validator.",
          "is_bot": false,
          "headline": "test(mcp): cover serializeServer's negative-cachedAt write-side fallback",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-06-26T18:28:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1eb518475b25823a609327344daf21e0d43c6e99",
          "body": "An epoch (ms) is non-negative by definition; rejecting negatives validates\nthe invariant at the snapshot boundary instead of relying on downstream\nmaxAge arithmetic to fail-safe on a clock-skewed/garbage value.",
          "is_bot": false,
          "headline": "fix(mcp): reject negative cachedAt in isFiniteEpoch",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-06-26T17:57:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c638f43c486244028d2ec57c9556ba60ba3ef726",
          "body": "…ializer\n\nExtract the 'valid cachedAt' predicate into a single exported isFiniteEpoch\nin cache-types.ts, consumed by both the read-side isSerializedMCPServer\nvalidator and the write-side serializer, so the two can't drift if the rule\nis later tightened. No behavior change.",
          "is_bot": false,
          "headline": "refactor(mcp): share isFiniteEpoch between snapshot validator and ser…",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-06-26T17:45:30Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "43ed315256dd5e8ab6177fddd77dddb5ddefea06",
          "body": "A poisoned snapshot with NaN/Infinity cachedAt passed isSerializedMCPServer\n(typeof NaN === 'number'), making tryCacheHit's staleness comparison always\nfalse so the entry never expired. Mirror serialize.ts's isExpiry guard with a\nNumber.isFinite check. Also document that includeTools/excludeTools apply to\ndiscovered MCP tools only; resource tools are gated by the resources option.",
          "is_bot": false,
          "headline": "fix(mcp): reject non-finite cachedAt in snapshot validator",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-06-26T17:31:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "37e420566e5692563f430c6ed596649924a6f2ef",
          "body": "Extract the buildTools-args and serializeServer-input assembly out of\nmakeHandle into buildToolsArgs/serializeArgs helpers, dropping makeHandle\nfrom cc=17 to under the gate's threshold of 15. No behavior change.",
          "is_bot": false,
          "headline": "fix(mcp): drop makeHandle below max cyclomatic complexity",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-06-26T16:41:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "60a0ae76fc8053076c383bc291dbd49161c3f98a",
          "body": "The sentrux structural gate failed on cycle + quality + complexity\nregressions. Resolved without weakening the baseline:\n\n- extract makeHandle/freshConnect/listToolDefs into a leaf handle.ts so\n  create-mcp-tools and rehydrate no longer form a cycle\n- move MCPTransportKind to a leaf transport-types.\n[…]\nd into)\n- collapse tryCacheHit's option forwarding into a data-driven helper to\n  drop it back under the max-cyclomatic-complexity threshold\n\nGate now: cycles 1->1, quality 0.51->0.52, no degradation.",
          "is_bot": false,
          "headline": "fix(mcp): pass structural-gate by eliminating import-cycle regressions",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-06-26T16:37:55Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a94f9c4c25357cd63afb66d81b192186033b08c7",
          "body": "… thread clientInfo\n\nAddresses remaining Perry review threads:\n- freshConnect tears down the connection if listToolDefs or the initial\n  writeCache throws, so a failed setup never leaks the open transport\n- the tools/list_changed auto-refresh now .catch()es, so a failed refresh\n  cannot escape as an unhandled rejection; listeners keep the last good set\n- thread clientInfo through the cache-hit/rehydrate path so a warm handle\n  initializes with the same client identity as a cold one",
          "is_bot": false,
          "headline": "fix(mcp): close connection on setup failure, guard refresh rejection,…",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-06-26T16:15:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c2a376c4db2084a4f5991c2cbcc23eb8524b92e6",
          "body": "…pagination\n\n- freshConnect breaks the recursive cache-fallback loop (no-auth/expired\n  snapshots no longer re-read their own cache and re-enter rehydrate)\n- reconstruct MCPAuth from a credential-bearing snapshot so reconnects\n  authenticate when no explicit auth is passed\n- thread toolNamePrefix/in\n[…]\nde/exclude/resources/emitProgress/\n  autoRefresh/cacheCredentials through cache hits so filters and prefixes\n  survive rehydration\n- follow nextCursor in tools/list, resources/list, and templates/list",
          "is_bot": false,
          "headline": "fix(mcp): correct cache/rehydrate option loss, credential reuse, and …",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-06-26T16:12:58Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "26336b5c44e5591b380ca4c41bf93b05f0ccdfe2",
          "body": "Expose remote MCP server tools (Streamable HTTP / SSE) as callModel tools,\nwith pluggable auth, faithful JSON-Schema->Zod conversion, and a\nserializable, rehydratable cache.",
          "is_bot": false,
          "headline": "feat(mcp): add @openrouter/mcp package",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-06-26T15:24:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "adc7939f4b7ed85b1a060d13433b8be6063cff73",
          "body": "chore: version packages",
          "is_bot": false,
          "headline": "Merge pull request #35 from OpenRouterTeam/changeset-release/main",
          "author_name": "Ben",
          "author_login": "Cybourgeoisie",
          "committed_at": "2026-06-17T13:49:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "21c2268117882ed291829fee1456b8adbf4d5135",
          "body": null,
          "is_bot": true,
          "headline": "chore: version packages",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-06-17T12:55:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4d79d358cfe7945a35f2ad4a4d7d9ff605a43dfc",
          "body": "…0.13.7\n\nchore: bump @openrouter/sdk to 0.13.7",
          "is_bot": false,
          "headline": "Merge pull request #53 from OpenRouterTeam/chore/bump-openrouter-sdk-…",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-06-17T12:55:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a5341f21555b5d2d982484c199d7d9c3093eabe6",
          "body": "Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: bump @openrouter/sdk to 0.13.7",
          "author_name": "Ben Heidorn",
          "author_login": "Cybourgeoisie",
          "committed_at": "2026-06-17T12:47:49Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "839b3819869cb944c00077159fc49bb209cb45a6",
          "body": "…-gh-token\n\nci: use GH_TOKEN for release-chain workflows",
          "is_bot": false,
          "headline": "Merge pull request #51 from OpenRouterTeam/sdk-bot/release-automation…",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-06-03T17:50:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "168da4755a64b8cdcf1677fb2a3edeb1e3c2f359",
          "body": "Switch the release-chain workflows from SUBTREE_PUSH_PAT to the dedicated\nGH_TOKEN PAT now configured on this repo. Follows up the merged #49, which\nlanded before this rewire.",
          "is_bot": false,
          "headline": "ci: use GH_TOKEN secret for PR open/merge and monorepo dispatch",
          "author_name": "OpenRouter SDK Bot",
          "author_login": null,
          "committed_at": "2026-06-03T17:44:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b7ceb298dab6b1b72233bbbf3630fdc9354b7a9e",
          "body": "…-bump\n\nci: auto-bump @openrouter/sdk and dispatch monorepo on release",
          "is_bot": false,
          "headline": "Merge pull request #49 from OpenRouterTeam/sdk-bot/release-automation…",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-06-03T16:33:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8917615dd47bbf9b9da7240b70921c18aaa5ada8",
          "body": "Drop the GitHub App (AGENT_BUMP_APP_*) and WEB_DISPATCH_PAT in favor of the\norg's existing SUBTREE_PUSH_PAT for opening/merging the bump PR and for the\nmonorepo dispatch. Slack alerts use the org-level CI_RELEASE_ALERT_SLACK_*\nsecrets, so no new secrets are required on this repo.",
          "is_bot": false,
          "headline": "ci: reuse SUBTREE_PUSH_PAT instead of new App/PAT secrets",
          "author_name": "OpenRouter SDK Bot",
          "author_login": null,
          "committed_at": "2026-06-03T14:39:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "aa4f6b525fc518c7f29f259f2b872b73dcaff30a",
          "body": "chore(agent): bump version to 0.7.1",
          "is_bot": false,
          "headline": "Merge pull request #50 from OpenRouterTeam/release/v0.7.1",
          "author_name": "Ben",
          "author_login": "Cybourgeoisie",
          "committed_at": "2026-06-03T14:35:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "33a807abc07ecde1b7a4fb0f7fdf853ca7c2a4a9",
          "body": "Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(agent): bump version to 0.7.1",
          "author_name": "Ben Heidorn",
          "author_login": "Cybourgeoisie",
          "committed_at": "2026-06-03T14:32:45Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "faaf82cf0cf69b32719db403370cdd19686b83e3",
          "body": "fix(agent): update OutputInputImage re-export for SDK compat and persist user input",
          "is_bot": false,
          "headline": "Merge pull request #48 from OpenRouterTeam/cyb/user-input-persistence",
          "author_name": "Ben",
          "author_login": "Cybourgeoisie",
          "committed_at": "2026-06-03T14:13:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8c1196c700b2e8a835703ab229e4a098193215f3",
          "body": "HOP A + HOP B of the SDK release chain:\n\n- bump-openrouter-sdk.yaml: receives openrouter-sdk-published dispatch (or\n  manual workflow_dispatch), opens a PR bumping @openrouter/sdk in\n  packages/agent (caret floor + relock + changeset) via an App token so Perry\n  and CI run, then self-polls Perry + C\n[…]\non a real @openrouter/agent publish (changesets published\n  output, or npm version diff on manual publish), dispatch\n  openrouter-agent-published to openrouter-web to kick off the server-tools\n  bump.",
          "is_bot": false,
          "headline": "ci: auto-bump @openrouter/sdk and dispatch monorepo on release",
          "author_name": "OpenRouter SDK Bot",
          "author_login": null,
          "committed_at": "2026-06-03T14:08:37Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "7b6704ae792df992df15dcf56c04a0afffe412fe",
          "body": "Add assistant-item assertion to the streaming-failure regression test,\nmaking the atomicity invariant explicit: after a successful retry, both\nexactly one user turn and one assistant turn are present in state.\n\nCo-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(agent): assert assistant message lands atomically with user input",
          "author_name": "Ben Heidorn",
          "author_login": "Cybourgeoisie",
          "committed_at": "2026-06-02T15:39:31Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ce00bf9bede9a68d1b38d798c906c72356cc97a2",
          "body": "Move fresh user-item persistence from initStream (after ok:true) to\nsaveResponseToState (after stream consumption). Previously, an ok:true\nresponse followed by a mid-stream failure would leave the user turn in\nstate with no assistant reply — on retry the same input was appended\nagain, producing dupl\n[…]\n a\nretry starts clean.\n\nAdds a streaming-failure regression test (ok:true + stream error + retry)\nto user-input-persistence.test.ts.\n\nCo-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(agent): persist user input atomically with assistant output",
          "author_name": "Ben Heidorn",
          "author_login": "Cybourgeoisie",
          "committed_at": "2026-06-02T15:14:06Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "76876339a98105b868cf80e1a978d16e29e48e78",
          "body": "…ist user input\n\n- Replace removed `OutputInputImage` with `OutputImage` + backward-compat\n  alias (`OutputImage as OutputInputImage`) after @openrouter/sdk dropped\n  the old export name.\n- Persist fresh user input items to state only after the API call succeeds,\n  preventing duplicates on transient retries.\n\nCo-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(agent): update OutputInputImage re-export for SDK compat and pers…",
          "author_name": "Ben Heidorn",
          "author_login": "Cybourgeoisie",
          "committed_at": "2026-06-02T11:46:19Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d8a8f659187994cca917f6d1e7dfef140c9e4e25",
          "body": "…ponse-470ET\n\nfeat(agent): add allowFinalResponse option to callModel",
          "is_bot": false,
          "headline": "Merge pull request #44 from OpenRouterTeam/claude/add-allow-final-res…",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-05-18T21:44:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7a404a4d633b562abbde4aebe1931cb7ea24084c",
          "body": "Bumps @openrouter/agent to 0.7.0 and consumes the\nallowFinalResponse changeset into the CHANGELOG.\n\nhttps://claude.ai/code/session_01Up1UhjF9mQBDq4rFwULovN",
          "is_bot": false,
          "headline": "chore: version packages (0.7.0)",
          "author_name": "Claude",
          "author_login": "claude",
          "committed_at": "2026-05-18T21:41:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8057b775f48e7db6d71aaef6c434e85a9495e2e4",
          "body": "- Save real tool outputs to state BEFORE the HITL pause check so a\n  mixed batch (HITL + regular tools) doesn't drop the regular tool's\n  output from state on resume. Matches the in-loop ordering.\n- Apply nextTurnParams from executed tools so tools that mutate\n  request params (model, temperature, e\n[…]\nath that the\n  non-streaming fixtures didn't cover).\n- Add a unit test asserting that stubs land in the request but never\n  in persisted state.\n\nhttps://claude.ai/code/session_01Up1UhjF9mQBDq4rFwULovN",
          "is_bot": false,
          "headline": "fix(agent): address adversarial review of allowFinalResponse",
          "author_name": "Claude",
          "author_login": "claude",
          "committed_at": "2026-05-18T21:37:54Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ad789c80235777bc65765bc7cf49bbd07b4995d4",
          "body": "…ow-up\n\nAddress review feedback on the allowFinalResponse implementation:\n\n- Execute pending tool calls when the trigger fires so they have real\n  matching outputs in the input, rather than always synthesizing stubs.\n  Stubs now only cover any manual (non-executable) tool calls in the\n  halted turn \n[…]\nbled by the falsy check).\n- Add 6 unit tests that mock betaResponsesSend and assert the second\n  request shape, tool execution, and edge cases.\n\nhttps://claude.ai/code/session_01Up1UhjF9mQBDq4rFwULovN",
          "is_bot": false,
          "headline": "fix(agent): execute pending tool calls before allowFinalResponse foll…",
          "author_name": "Claude",
          "author_login": "claude",
          "committed_at": "2026-05-18T21:25:03Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c33195cf89e10316fc9ddbf222d6717e831db04c",
          "body": "Sibling of stopWhen. When the loop is halted by stopWhen while the last\nresponse still contains tool calls, set allowFinalResponse: true (or a\nstring) to make one more no-tools request so the loop ends with a\nnatural-language summary instead of an unfinished tool call. A string\nvalue is appended as a final user message. The full accumulated input\narray and the original instructions are sent.\n\nhttps://claude.ai/code/session_01Up1UhjF9mQBDq4rFwULovN",
          "is_bot": false,
          "headline": "feat(agent): add allowFinalResponse option to callModel",
          "author_name": "Claude",
          "author_login": "claude",
          "committed_at": "2026-05-18T21:05:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7222108ee9bc2de1e382d4f25c4ec517029e97bf",
          "body": "chore: version packages (0.6.0)",
          "is_bot": false,
          "headline": "Merge pull request #43 from OpenRouterTeam/changeset-release-0.6.0",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-05-14T15:36:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "660731ecd645c28fad40f0eefed9deae857adefd",
          "body": "The 0.5.0 → 0.6.0 work (notably the HITL tooling that landed earlier)\nshifted the structural metrics far enough that the gate flags a drop\nagainst the stale baseline even on no-source-change PRs. Re-baselining\ncaptures the current state so subsequent PRs are measured from here.\n\n  quality_signal: 0.5195 → 0.5094\n  coupling_score: 0.4173 → 0.4286\n  total_import_edges: 127 → 133\n  cross_module_edges: 55 → 59",
          "is_bot": false,
          "headline": "chore: refresh sentrux baseline for 0.6.0 release",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-05-14T15:34:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "101f7f71d4a78a4e65c21c80e446541a9c57ba62",
          "body": "Consumes the changeset from #42 (remove implicit 5-step cap in\ncallModel). Bumps @openrouter/agent from 0.5.0 to 0.6.0 and updates\nthe CHANGELOG.",
          "is_bot": false,
          "headline": "chore: version packages (0.6.0)",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-05-14T15:27:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "06501a9116deb90761c6af1bce5c28f0849333ea",
          "body": "feat(agent): remove implicit 5-step cap in callModel",
          "is_bot": false,
          "headline": "Merge pull request #42 from OpenRouterTeam/remove-implicit-max-steps",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-05-14T15:26:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8e71f06024f41e60ccdc68577016637a31912779",
          "body": "When `stopWhen` is omitted, the tool-execution loop now runs until the\nmodel produces a turn with no tool calls instead of being silently\ncapped at 5 steps. Callers who want a bound must pass an explicit\n`stopWhen` (e.g. `stepCountIs(n)`, `maxCost(...)`).",
          "is_bot": false,
          "headline": "feat(agent): remove implicit 5-step cap in callModel",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-05-14T15:24:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3e5ef28746ede546293ee0b96a4143262294a0bf",
          "body": "chore(release): @openrouter/agent 0.5.0 (HITL tools)",
          "is_bot": false,
          "headline": "Merge pull request #40 from OpenRouterTeam/changeset/hitl-tools-release",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-05-06T00:52:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4cb0c3b4ff1f9534674cfd602213b2eddf80a0e0",
          "body": "Consumes the pre-existing `curvy-streams-watch` patch changeset (stream\ndetection regression coverage from #34) and adds a new minor changeset\ncovering the human-in-the-loop tool type merged in #38.",
          "is_bot": false,
          "headline": "chore: version packages for HITL tools release (0.5.0)",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-05-06T00:50:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c649c9cc99521ae9e3fbb42d109146f31f040ce1",
          "body": "feat(tools): add human-in-the-loop tool type",
          "is_bot": false,
          "headline": "Merge pull request #38 from OpenRouterTeam/feat/hitl-tools",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-05-06T00:48:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "396d44b3371df99ddf660288a8d53cd4fc810728",
          "body": "applyOnResponseReceivedHooks and executeToolRound grew cyclomatic\ncomplexity above 15 when HITL logic landed, tripping sentrux gate\n(complex functions 9 -> 11). Extract per-item helpers so the gate\nmatches baseline again:\n\n- applyOnResponseReceivedHooks: move per-item hook/validate logic into\n  comp\n[…]\nutForModel; describeNonRecord factors out the nested\n  typeof/Array.isArray ternary.\n\nPure refactor — no behavior change. All 280 unit tests still pass;\nsentrux gate reports \"No degradation detected\".",
          "is_bot": false,
          "headline": "refactor(tools): extract helpers to keep cc under structural gate",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-05-06T00:34:12Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "51a983d256d3594060283e6a95b3c2fac0e9cfff",
          "body": "- Preserve content-array FunctionCallOutputItem shapes in the HITL\n  onResponseReceived pipeline instead of JSON.stringify'ing them; export\n  isContentArray from conversation-state for reuse.\n- Require outputSchema on HITL tool configs and use it to validate\n  caller-supplied responses. Validation f\n[…]\nooksToFreshItems.\n- Drop the onResponseReceived call on SDK-generated outputs in\n  continueWithUnsentResults. The hook is now strictly for caller-supplied\n  outputs, matching its documented semantics.",
          "is_bot": false,
          "headline": "fix(tools): address HITL review feedback",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-05-06T00:19:13Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8ac64b5b1b9046ee3e3db9b42e19432452ccb4c5",
          "body": "chore: add sentrux architectural gating",
          "is_bot": false,
          "headline": "Merge pull request #39 from OpenRouterTeam/chore/sentrux-setup",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-05-06T00:16:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "74493d8889dd1b94d9b4533e803e99f0c02dd28a",
          "body": "Wire up sentrux via .mcp.json for Claude Code MCP integration and add\n.sentrux/rules.toml encoding the inner-loop -> lib -> api-shape-helpers\nlayering. CI gains a structural-gate job that installs sentrux v0.5.7 and\nruns `sentrux gate` against the saved baseline on every PR, blocking merges\nthat regress structural metrics (coupling, cycles, god files, complexity).",
          "is_bot": false,
          "headline": "chore: add sentrux architectural gating",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-05-06T00:14:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "dc2ba48b88662be93c0ccd3e1e17ced61a2a30b8",
          "body": "- Route auto-resolvable checks through isAutoResolvableTool so pure-HITL\n  turns actually enter the execution loop and invoke onToolCalled.\n- Propagate HITL pauses out of executeToolRound; the outer loop now\n  persists pending calls under a new awaiting_hitl status and returns\n  before issuing a fol\n[…]\nput alongside error when onResponseReceived throws,\n  so the model can distinguish hook failure from tool-reported error.\n- Replace unsafe InputsUnion cast with a structurally-typed rewritten\n  array.",
          "is_bot": false,
          "headline": "fix(tools): close HITL execution gaps surfaced in review",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-05-05T23:47:31Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5155f4456ee3e0aed8734ad15a6949dbb068ee68",
          "body": null,
          "is_bot": false,
          "headline": "style: apply biome formatting and optional-chain suggestion",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-05-05T22:55:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8faf9bb846887c01a6d526ffc19526dfe30822d1",
          "body": "Adds a fourth client tool kind that extends manual-tool semantics with two\nasync hooks. `onToolCalled` runs when the model invokes the tool — returning\na value short-circuits like `execute`, returning `null` pauses the loop like\na manual tool. `onResponseReceived` runs on a later turn when an incomi\n[…]\non_call.name) a HITL\ntool, letting the tool post-process caller-supplied results before the\nmodel sees them.\n\nKeeps HITL control flow local to the tool definition instead of smeared\nacross the caller.",
          "is_bot": false,
          "headline": "feat(tools): add human-in-the-loop tool type",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-05-05T22:54:32Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ac3f82f8871caf7edb0aa0c38b2f892b73039014",
          "body": "Use getReader for stream shape checks",
          "is_bot": false,
          "headline": "Merge pull request #34 from w0nche0l/codex/getreader-stream-shape-check",
          "author_name": "robert-j-y",
          "author_login": "robert-j-y",
          "committed_at": "2026-05-01T22:38:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "61aca10fd9434fe69fbe1e069e4b1858613a7da7",
          "body": null,
          "is_bot": false,
          "headline": "Add stream detection regression coverage",
          "author_name": "Dennis",
          "author_login": "w0nche0l",
          "committed_at": "2026-05-01T20:24:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "596726ca44d338ac4a8e916e3b28c50071ae1410",
          "body": null,
          "is_bot": false,
          "headline": "Use getReader for stream shape checks",
          "author_name": "Dennis",
          "author_login": "w0nche0l",
          "committed_at": "2026-05-01T08:28:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e3a868cfcc68eee699473e034f09d4efb7d6d41c",
          "body": "chore: convert to Turborepo monorepo (v2.9.6)",
          "is_bot": false,
          "headline": "Merge pull request #26 from OpenRouterTeam/turborepo-migration",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-20T18:59:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "232f6c50411eb8bce000f127a0f7655964844d74",
          "body": "# Conflicts:\n#\tpackage.json",
          "is_bot": false,
          "headline": "Merge remote-tracking branch 'origin/main' into turborepo-migration",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-20T18:59:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c3404cb0a37698590afb4bd37dbe7aa62a33a770",
          "body": "chore: version packages",
          "is_bot": false,
          "headline": "Merge pull request #29 from OpenRouterTeam/changeset-release/main",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-20T18:57:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "dc6f77e83543163a0a4802853e8e7ac6cdccc42a",
          "body": "# Conflicts:\n#\tpackages/agent/tests/unit/has-approval-tools.test-d.ts\n#\tpackages/agent/tests/unit/server-tool-stream-narrowing.test-d.ts\n#\tpackages/agent/tests/unit/server-tool.test.ts",
          "is_bot": false,
          "headline": "Merge remote-tracking branch 'origin/main' into turborepo-migration",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-20T18:57:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "469aff365862127ee1460c4468b130dc9665c6ba",
          "body": null,
          "is_bot": true,
          "headline": "chore: version packages",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-04-20T18:55:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ffa0ae4b1d9bfa5f779303070c070b1da8aa494a",
          "body": "feat: add OpenRouter server tools to callModel",
          "is_bot": false,
          "headline": "Merge pull request #30 from OpenRouterTeam/add-server-tools",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-20T18:55:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "46a45f2ddd87a15669c82abb8946f67b8b10c4d9",
          "body": "Previously fell through to the default branch, which widened the runtime\nfilter by setting acceptGenericServerItem=true. The type-level\nKnownServerToolOutputs map already narrows this tool's output to the\n'openrouter:datetime' literal, so the runtime allow-list should match.",
          "is_bot": false,
          "headline": "fix: add explicit openrouter:datetime case to item stream scope",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-20T18:54:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e4e3ed5e0a4f132e8cae1c33d7831f65aa46c211",
          "body": null,
          "is_bot": false,
          "headline": "chore: add changeset for serverTool feature",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-20T18:26:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5e1db17d3c1a97316cc16efef25d4bd84366c948",
          "body": "- Defensively accept both `web_search_call` and `openrouter:web_search`\n  item literals for the `openrouter:web_search` request variant (runtime\n  filter + KnownServerToolOutputs type) so items aren't silently dropped\n  when the provider wraps results in OutputServerToolItem.\n- Replace the deny-list\n[…]\nem` / `isFileSearchCallOutputItem`\n  / `isImageGenerationCallOutputItem` branches in `handleOutputItemAdded`\n  and `handleOutputItemDone`; the `isServerToolResultItem` catch-all\n  already covers them.",
          "is_bot": false,
          "headline": "fix: tighten server tool output routing and filter correctness",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-20T18:12:11Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5965684ec15e2a8a4b9620e0eb933663132d8ad9",
          "body": "Adds first-class support for OpenRouter's server-executed tools\n(web_search, openrouter:datetime, image_generation, mcp, file_search,\ncode_interpreter, etc.) through a new `serverTool()` factory that lives\nalongside the existing `tool()`. Server tools are passed through to the\nAPI via the SDK's `Res\n[…]\ntions, proper typeguards\nthroughout. The `getItemsStream` scope filter is backed by a real\nruntime allow-list derived from `TTools`, so the type-level narrowing\ncorresponds to actual runtime behavior.",
          "is_bot": false,
          "headline": "feat: add OpenRouter server tools to callModel",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-20T18:09:02Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "54475e856547b690a175ecd36b6bb58c3e166097",
          "body": "# Conflicts:\n#\tpackage.json\n#\tpnpm-lock.yaml",
          "is_bot": false,
          "headline": "Merge remote-tracking branch 'origin/main' into turborepo-migration",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-20T17:52:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3baff61ca7e90871ccb65c7a826be64fc800e570",
          "body": "chore: version packages",
          "is_bot": false,
          "headline": "Merge pull request #28 from OpenRouterTeam/changeset-release/main",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-20T17:39:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ec4ff3f4d97c576aec4669ec8271b1d39cbd8a85",
          "body": "chore: bump @openrouter/sdk from 0.11.2 to 0.12.12",
          "is_bot": false,
          "headline": "Merge pull request #25 from OpenRouterTeam/chore/bump-sdk-0.12.12",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-20T17:39:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e23eb4256098b3ed21e9a13fbf8145e3691eb936",
          "body": null,
          "is_bot": false,
          "headline": "Merge remote-tracking branch 'origin/main' into turborepo-migration",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-20T17:36:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d3cff5f023d3c19a44083baa40c7e14a924f39cc",
          "body": "- Remove dead \"Check for pending changesets\" step in publish.yaml;\n  nothing reads steps.changesets.outputs.pending anymore.\n- Add \"globalDependencies\": [\"tsconfig.base.json\"] to turbo.json so\n  edits to the shared base tsconfig invalidate build/typecheck/test\n  caches instead of serving stale output.",
          "is_bot": false,
          "headline": "chore: address review feedback",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-20T17:35:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c41af68aa9c42103aa342c4787a68e5724a5e066",
          "body": null,
          "is_bot": true,
          "headline": "chore: version packages",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-04-20T17:28:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8e516726cad9139975e572c0ac448e012d6672d7",
          "body": "fix(openrouter): normalize hooks constructor option so shorthand input isn't silently dropped",
          "is_bot": false,
          "headline": "Merge pull request #27 from OpenRouterTeam/fix-e2e-tests",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-20T17:28:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ef157612ca213d23ef1bfbfec012db09144315bf",
          "body": "The underlying SDK only wires `hooks` into the request pipeline when it's an\n`SDKHooks` instance; passing a plain hook object (e.g. `{ beforeRequest }`) was\nsilently ignored, causing `hooks` to no-op for every caller who used the\nnatural shorthand.\n\n`new OpenRouter({ hooks })` now accepts an `SDKHoo\n[…]\nng from `@openrouter/sdk`, which hit the SDK's older `ModelResult` that\ndoesn't yield manual-tool `function_call` items from `finalResponse`) and\nbumps a 6s timeout on a Sonnet-with-tools test to 20s.",
          "is_bot": false,
          "headline": "fix(openrouter): normalize hooks constructor option",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-20T17:27:16Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b5743a1c3a25a7c815bae969bdcebb9bacf02248",
          "body": "Move @openrouter/agent into packages/agent/ under a pnpm workspace with\nTurborepo managing build/test/lint/typecheck task graphs at the root.\n\nRelease flow now uses `changeset publish`, which walks the workspace and\npublishes only packages whose on-disk version differs from npm — the\npipeline genera\n[…]\nEADME, CHANGELOG,\n.npmignore, vitest.config.ts, and tsconfig move into packages/agent/.\nBiome + grit plugins stay at the root; scope globs widened to cover\npackages/*. Vitest loads a shared root .env.",
          "is_bot": false,
          "headline": "chore: convert to Turborepo monorepo (v2.9.6)",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-20T17:01:37Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e2e61ceb20c248bfd5615abd35c9c38236a72f51",
          "body": "ci: split CI into parallel jobs",
          "is_bot": false,
          "headline": "Merge pull request #9 from OpenRouterTeam/ci-parallel-checks",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-17T14:26:34Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "36eda074cb0616122892f9e79c60c06977d94750",
          "body": "- Apply Biome formatter to tests/unit/conversation-state.test.ts to\n  break long array literals across multiple lines.\n- Have the e2e-tests job short-circuit with a warning when\n  OPENROUTER_API_KEY is not set instead of hard-failing, so the check\n  passes in contexts where the secret is unavailable (e.g. forks).",
          "is_bot": false,
          "headline": "ci: fix lint formatting and skip e2e tests when API key is absent",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-16T21:03:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "66f85cf1a54ff188c2eb11d333aa2020e82a2a8b",
          "body": "Combines the parallel-job split from this branch with the named-step\nstyle added on main. Also passes the OPENROUTER_API_KEY secret into\nthe e2e-tests job so it can actually run.",
          "is_bot": false,
          "headline": "ci: resolve merge conflict and wire OPENROUTER_API_KEY for e2e job",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-16T20:48:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8faa32c4d1069dfbdbf590ee73f78823bb024fdb",
          "body": null,
          "is_bot": false,
          "headline": "style: fix biome formatting in conversation-state test",
          "author_name": "Jakob Castro",
          "author_login": "jakobdylanc",
          "committed_at": "2026-04-16T17:05:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ec94de8c16fa114ba1e6369db25b4a2cd4ebc359",
          "body": "Co-Authored-By: jakob <jakob.castro@openrouter.ai>",
          "is_bot": true,
          "headline": "chore: bump @openrouter/sdk from 0.11.2 to 0.12.12",
          "author_name": "Devin AI",
          "author_login": "devin-ai-integration[bot]",
          "committed_at": "2026-04-16T16:45:08Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "bc686d2249e577efb0f47b8e92d8574d66467e4a",
          "body": "Add support for passing input_text, input_image, and input_file content\nblocks directly as tool output without JSON.stringify. This enables tools\nthat produce rich outputs like images to pass them through efficiently.\n\nBump version to 0.3.2.",
          "is_bot": false,
          "headline": "feat: support content arrays in tool outputs",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-14T20:25:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "358253d5d3b6b36465afbf1c76f5445e963cdf2b",
          "body": "feat(tools): add toModelOutput for custom tool result formatting",
          "is_bot": false,
          "headline": "Merge pull request #24 from OpenRouterTeam/feature/to-model-output",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-14T20:21:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1e43375cc85a774afdd3faad92ec4be4f8ca73cc",
          "body": "Adds optional toModelOutput function to tool definitions that converts\nexecution output to model-facing content blocks (Responses API format).\nThis decouples what calling code receives from what the model sees.",
          "is_bot": false,
          "headline": "feat(tools): add toModelOutput for custom tool result formatting",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-14T19:52:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1572b88ba8c2f2b4bcb38a2526a894a3ea193917",
          "body": "chore: version packages",
          "is_bot": false,
          "headline": "Merge pull request #23 from OpenRouterTeam/changeset-release/main",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-12T14:43:34Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f7a90634fb25ccfb0794dd50c77aa1e6ea61d567",
          "body": null,
          "is_bot": true,
          "headline": "chore: version packages",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-04-12T12:10:48Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f697969678f86da1ef04952d78625bca659eb043",
          "body": "chore: add changeset for type fixes (patch)",
          "is_bot": false,
          "headline": "Merge pull request #22 from OpenRouterTeam/changelog/fix-types-patch",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-12T12:10:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8535b77d462fc82c8c52019948cb9de7852688f0",
          "body": "Ensures code quality checks run before pushing to remote.",
          "is_bot": false,
          "headline": "feat: add husky pre-push hooks for lint and typecheck",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-12T12:08:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5d947e6ad5ba291d43322168b11782c19b71b8e2",
          "body": "- Use `import type` for Item import in async-params.ts\n- Organize imports per biome rules\n- Remove extra blank line in item-types.ts",
          "is_bot": false,
          "headline": "fix: resolve biome lint errors",
          "author_name": "Matt Apperson",
          "author_login": "mattapperson",
          "committed_at": "2026-04-12T12:07:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        }
      ],
      "releases_count": 7,
      "commits_last_year": 152,
      "latest_release_at": "2026-07-22T20:50:38Z",
      "latest_release_tag": "@openrouter/agent@0.8.0",
      "releases_from_tags": false,
      "days_since_last_push": 2,
      "active_weeks_last_year": 16,
      "days_since_latest_release": 11,
      "mean_days_between_releases": 13
    },
    "artifacts": {
      "collected": true,
      "structure": [],
      "declarations": [
        {
          "name": null,
          "path": "package.json",
          "tokens": [
            "npm.private"
          ],
          "ecosystem": "npm"
        },
        {
          "name": "@openrouter/agent",
          "path": "packages/agent/package.json",
          "tokens": [
            "npm.entry"
          ],
          "ecosystem": "npm"
        },
        {
          "name": "@openrouter/mcp",
          "path": "packages/mcp/package.json",
          "tokens": [
            "npm.entry"
          ],
          "ecosystem": "npm"
        }
      ]
    },
    "community": {
      "has_readme": true,
      "has_license": false,
      "readme_badges": {
        "hosts": [],
        "total": 0,
        "header": 0,
        "collected": true,
        "has_inspect_badge": false
      },
      "has_description": true,
      "has_contributing": false,
      "health_percentage": 25,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "@openrouter/mcp",
          "exists": true,
          "license": "Apache-2.0",
          "keywords": [
            "openrouter",
            "mcp",
            "model-context-protocol",
            "agent",
            "typescript",
            "ai",
            "tools",
            "llm"
          ],
          "ecosystem": "npm",
          "categories": [],
          "matches_repo": true,
          "registry_url": "https://www.npmjs.com/package/@openrouter/mcp",
          "declared_type": null,
          "is_deprecated": false,
          "latest_version": "0.0.1",
          "repository_url": "https://github.com/OpenRouterTeam/typescript-agent",
          "versions_count": 1,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": 8,
          "monthly_downloads": 133,
          "first_published_at": "2026-07-24T20:05:28.313000Z",
          "latest_published_at": "2026-07-24T20:05:28.695000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 9
        },
        {
          "name": "@openrouter/agent",
          "exists": true,
          "license": "Apache-2.0",
          "keywords": [
            "openrouter",
            "agent",
            "typescript",
            "ai",
            "tools",
            "streaming",
            "llm"
          ],
          "ecosystem": "npm",
          "categories": [],
          "matches_repo": true,
          "registry_url": "https://www.npmjs.com/package/@openrouter/agent",
          "declared_type": null,
          "is_deprecated": false,
          "latest_version": "0.8.0",
          "repository_url": "https://github.com/OpenRouterTeam/typescript-agent",
          "versions_count": 13,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": 8,
          "monthly_downloads": 382454,
          "first_published_at": "2026-04-01T16:43:16.521000Z",
          "latest_published_at": "2026-07-22T20:50:29.987000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 11
        }
      ]
    },
    "popularity": {
      "forks": 11,
      "stars": 19,
      "watchers": 0,
      "fork_history": {
        "days": [
          {
            "date": "2026-04-10",
            "count": 1
          },
          {
            "date": "2026-05-01",
            "count": 1
          },
          {
            "date": "2026-05-02",
            "count": 1
          },
          {
            "date": "2026-05-10",
            "count": 1
          },
          {
            "date": "2026-05-25",
            "count": 1
          },
          {
            "date": "2026-05-30",
            "count": 1
          },
          {
            "date": "2026-06-15",
            "count": 1
          },
          {
            "date": "2026-06-17",
            "count": 1
          },
          {
            "date": "2026-06-26",
            "count": 1
          },
          {
            "date": "2026-07-16",
            "count": 1
          },
          {
            "date": "2026-07-29",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 11,
        "total_forks": 11
      },
      "star_history": null,
      "open_issues_and_prs": 17
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": true,
      "bootstrap_files": [],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [
        "packages/agent/tsconfig.json",
        "packages/mcp/tsconfig.json"
      ],
      "toolchain_manifests": [],
      "largest_source_bytes": 181323,
      "source_files_sampled": 120,
      "oversized_source_files": 2,
      "agent_instruction_files": [],
      "agent_instruction_max_bytes": null
    },
    "dependencies": {
      "manifests": [
        "package.json"
      ],
      "advisories": {
        "error": null,
        "scope": "published_package",
        "source": "osv",
        "findings": [],
        "collected": true,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 95,
        "malicious_count": 0,
        "assessed_package": "npm:@openrouter/mcp@0.0.1",
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "npm"
      ],
      "dependencies": [
        {
          "name": "@openrouter/sdk",
          "manifest": "packages/agent/package.json",
          "ecosystem": "npm",
          "version_constraint": "^0.13.7"
        },
        {
          "name": "zod",
          "manifest": "packages/agent/package.json",
          "ecosystem": "npm",
          "version_constraint": "^4.0.0"
        },
        {
          "name": "@modelcontextprotocol/sdk",
          "manifest": "packages/mcp/package.json",
          "ecosystem": "npm",
          "version_constraint": "^1.29.0"
        },
        {
          "name": "@openrouter/agent",
          "manifest": "packages/mcp/package.json",
          "ecosystem": "npm",
          "version_constraint": "workspace:*"
        },
        {
          "name": "zod",
          "manifest": "packages/mcp/package.json",
          "ecosystem": "npm",
          "version_constraint": "^4.0.0"
        }
      ],
      "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": 11,
        "merged_prs": 58,
        "open_issues": 6,
        "closed_ratio": 0.143,
        "closed_issues": 1,
        "closed_unmerged_prs": 15
      },
      "bus_factor": 1,
      "bot_contributors": 2,
      "top_contributors": [
        {
          "type": "User",
          "login": "mattapperson",
          "commits": 101,
          "avatar_url": "https://avatars.githubusercontent.com/u/192433?v=4"
        },
        {
          "type": "User",
          "login": "LukasParke",
          "commits": 12,
          "avatar_url": "https://avatars.githubusercontent.com/u/5702154?v=4"
        },
        {
          "type": "User",
          "login": "Cybourgeoisie",
          "commits": 8,
          "avatar_url": "https://avatars.githubusercontent.com/u/301326?v=4"
        },
        {
          "type": "User",
          "login": "claude",
          "commits": 4,
          "avatar_url": "https://avatars.githubusercontent.com/u/81847?v=4"
        },
        {
          "type": "User",
          "login": "robert-j-y",
          "commits": 4,
          "avatar_url": "https://avatars.githubusercontent.com/u/212159665?v=4"
        },
        {
          "type": "User",
          "login": "w0nche0l",
          "commits": 3,
          "avatar_url": "https://avatars.githubusercontent.com/u/3719829?v=4"
        },
        {
          "type": "User",
          "login": "okacodes",
          "commits": 2,
          "avatar_url": "https://avatars.githubusercontent.com/u/193345390?v=4"
        },
        {
          "type": "User",
          "login": "jakobdylanc",
          "commits": 1,
          "avatar_url": "https://avatars.githubusercontent.com/u/38699060?v=4"
        },
        {
          "type": "User",
          "login": "ayush-or",
          "commits": 1,
          "avatar_url": "https://avatars.githubusercontent.com/u/291842981?v=4"
        }
      ],
      "contributors_sampled": 9,
      "top_contributor_share": 0.743
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "bump-openrouter-sdk.yaml",
        "ci.yaml",
        "publish.yaml"
      ],
      "has_docs_dir": false,
      "linter_configs": [
        "biome.json"
      ],
      "has_editorconfig": false,
      "has_linter_config": true,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [
        "pnpm-lock.yaml"
      ],
      "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": 3,
            "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": 9,
            "reason": "18 out of 19 merged PRs checked by a CI test -- score normalized to 9",
            "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": 4,
            "reason": "Found 8/18 approved changesets -- score normalized to 4",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 10,
            "reason": "project has 5 contributing companies or organizations",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": 10,
            "reason": "no dangerous workflow patterns detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 0,
            "reason": "no update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 0,
            "reason": "license file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 10,
            "reason": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": null,
            "reason": "packaging workflow not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": 0,
            "reason": "dependency not pinned by hash detected -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "SAST tool is not run on all commits -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 0,
            "reason": "security policy file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": null,
            "reason": "no releases found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": 0,
            "reason": "detected GitHub workflow tokens with excessive permissions",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 0,
            "reason": "16 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "d03060256c4c7d55432e508544d8d35d2f65d4bb",
        "ran_at": "2026-08-03T04:51:18Z",
        "aggregate_score": 3.8,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "recent_prs": {
        "merged_7d": 3,
        "decided_7d": 3,
        "merged_30d": 17,
        "authors_30d": 6,
        "decided_30d": 29,
        "sample_size": 60,
        "window_days": 30,
        "sample_exhausted": false,
        "authors_probed_30d": 6,
        "newcomer_merged_30d": 15,
        "bot_prs_excluded_30d": 1,
        "newcomer_authors_30d": 3,
        "newcomer_decided_30d": 26
      },
      "ci_last_run_at": "2026-07-30T15:59:39Z",
      "oldest_open_prs": [
        {
          "number": 31,
          "created_at": "2026-04-20T18:44:41Z",
          "last_comment_at": "2026-07-29T19:17:56Z",
          "last_comment_author": "cortex-github-agent"
        },
        {
          "number": 32,
          "created_at": "2026-04-21T16:45:08Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 55,
          "created_at": "2026-06-26T02:55:58Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 74,
          "created_at": "2026-07-22T01:49:06Z",
          "last_comment_at": "2026-07-29T19:40:38Z",
          "last_comment_author": "devin-ai-integration"
        },
        {
          "number": 85,
          "created_at": "2026-07-28T19:31:30Z",
          "last_comment_at": "2026-07-29T19:40:37Z",
          "last_comment_author": "devin-ai-integration"
        },
        {
          "number": 86,
          "created_at": "2026-07-28T19:53:53Z",
          "last_comment_at": "2026-07-30T18:48:38Z",
          "last_comment_author": "LukasParke"
        },
        {
          "number": 88,
          "created_at": "2026-07-29T17:44:01Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 89,
          "created_at": "2026-07-29T19:59:32Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 90,
          "created_at": "2026-07-31T02:45:53Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 91,
          "created_at": "2026-07-31T05:03:44Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 92,
          "created_at": "2026-07-31T21:05:35Z",
          "last_comment_at": null,
          "last_comment_author": null
        }
      ],
      "last_merged_pr_at": "2026-07-30T15:58:38Z",
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": [
        {
          "number": 10,
          "created_at": "2026-04-03T21:18:01Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 11,
          "created_at": "2026-04-03T21:21:09Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 41,
          "created_at": "2026-05-10T20:13:12Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 45,
          "created_at": "2026-05-27T17:40:50Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 54,
          "created_at": "2026-06-26T02:55:21Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 58,
          "created_at": "2026-07-08T04:30:26Z",
          "last_comment_at": null,
          "last_comment_author": null
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/OpenRouterTeam/typescript-agent",
    "host": "github.com",
    "name": "typescript-agent",
    "owner": "OpenRouterTeam"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "good",
      "name": "Overall health",
      "note": "The weighted overall 64 is calibrated to 73 on the published index scale (record calibration 2026-08-02).",
      "notes": [
        {
          "code": "overall_calibration",
          "params": {
            "raw": 64,
            "calibrated": 73,
            "calibration": "2026-08-02"
          }
        }
      ],
      "value": 73,
      "inputs": {
        "security": 50,
        "vitality": 85,
        "community": 44,
        "governance": 60,
        "calibration": "2026-08-02",
        "engineering": 75,
        "ai_readiness": 55,
        "weighted_overall_raw": 64
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "excellent",
        "name": "Vitality",
        "value": 85,
        "weight": 0.21,
        "metrics": [
          {
            "key": "development_activity",
            "band": "good",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 75,
            "inputs": {
              "commits_last_year": 152,
              "human_commit_share": 0.94,
              "days_since_last_push": 2,
              "active_weeks_last_year": 16
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 2 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 2
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "16/52 weeks with commits",
                "points": 11.1,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 16
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "152 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 152
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "exceptional",
            "name": "Release discipline",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "releases_count": 7,
              "latest_release_tag": "@openrouter/agent@0.8.0",
              "releases_from_tags": false,
              "days_since_latest_release": 11,
              "mean_days_between_releases": 13
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "7 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 7
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 11 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 11
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~13 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 13
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "exceptional",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "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": "weak",
        "name": "Community & Adoption",
        "value": 44,
        "weight": 0.17,
        "metrics": [
          {
            "key": "popularity",
            "band": "at_risk",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 29,
            "inputs": {
              "forks": 11,
              "stars": 19,
              "watchers": 0,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "19 stars",
                "points": 20.4,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 19
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "11 forks",
                "points": 8.3,
                "status": "partial",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 11
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "0 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "at_risk",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 25,
            "inputs": {
              "has_readme": true,
              "has_license": false,
              "readme_badges": 0,
              "has_contributing": false,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "readme_badge_services": [],
              "has_pull_request_template": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "no license file detected",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "license_absent",
                    "params": {}
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "code_of_conduct",
                "name": "Code of conduct",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 13.5
              },
              {
                "key": "issue_template",
                "name": "Issue template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.2
              },
              {
                "key": "pr_template",
                "name": "PR template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.3
              }
            ]
          },
          {
            "key": "ecosystem_adoption",
            "band": "exceptional",
            "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": 93,
            "inputs": {
              "packages": [
                "@openrouter/mcp",
                "@openrouter/agent"
              ],
              "dependents": null,
              "ecosystems": "npm",
              "total_downloads": null,
              "monthly_downloads": 382587
            },
            "components": [
              {
                "key": "monthly_downloads",
                "name": "Monthly downloads",
                "detail": "382,587 downloads/month across npm",
                "points": 74.4,
                "status": "partial",
                "details": [
                  {
                    "code": "downloads_monthly",
                    "params": {
                      "count": 382587,
                      "ecosystems": "npm"
                    }
                  }
                ],
                "max_points": 80
              },
              {
                "key": "registry_dependents",
                "name": "Registry dependents",
                "detail": "not reported by this ecosystem",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_reported_by_this_ecosystem",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "moderate",
        "name": "Sustainability & Governance",
        "value": 60,
        "weight": 0.23,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "weak",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 37,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 9,
              "top_contributor_share": 0.743
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "1 contributor(s) cover half of all commits",
                "points": 9,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 74% of commits",
                "points": 5.8,
                "status": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 74
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "9 contributors",
                "points": 12.2,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 9
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 5 contributing companies or organizations",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "weak",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 43,
            "inputs": {
              "merged_prs": 58,
              "open_issues": 6,
              "closed_issues": 1,
              "prs_merged_7d": 3,
              "prs_decided_7d": 3,
              "prs_merged_30d": 17,
              "prs_decided_30d": 29,
              "issue_closed_ratio": 0.143,
              "closed_unmerged_prs": 15,
              "first_time_authors_30d": 3,
              "first_time_prs_merged_30d": 15,
              "first_time_prs_decided_30d": 26
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "14% of issues closed",
                "points": 6,
                "status": "partial",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 14
                    }
                  }
                ],
                "max_points": 42
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "58/73 decided PRs merged",
                "points": 23.8,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 58,
                      "decided": 73
                    }
                  }
                ],
                "max_points": 30
              },
              {
                "key": "newcomer_pr_acceptance",
                "name": "Newcomer PR acceptance",
                "detail": "15/26 first-time contributors' PRs merged in 30d",
                "points": 7.5,
                "status": "partial",
                "details": [
                  {
                    "code": "newcomer_prs_merged",
                    "params": {
                      "days": 30,
                      "merged": 15,
                      "decided": 26
                    }
                  }
                ],
                "max_points": 13
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 8/18 approved changesets -- score normalized to 4",
                "points": 6,
                "status": "partial",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "good",
            "name": "Ownership & stewardship",
            "note": null,
            "notes": [],
            "value": 72,
            "inputs": {
              "followers": 3536,
              "owner_type": "Organization",
              "is_verified": null,
              "owner_login": "OpenRouterTeam",
              "public_repos": 36,
              "account_age_days": 1117
            },
            "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": "3,536 followers of OpenRouterTeam",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 3536,
                      "login": "OpenRouterTeam"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "36 public repos, account ~3 yr old",
                "points": 17.5,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 36
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 3
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "exceptional",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "@openrouter/mcp",
                "@openrouter/agent"
              ],
              "ecosystems": "npm",
              "any_deprecated": false,
              "min_days_since_publish": 9
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "2 package(s) on npm",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 2,
                      "ecosystems": "npm"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 9 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 9
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "13 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 13
                    }
                  }
                ],
                "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": "good",
        "name": "Engineering Quality",
        "value": 75,
        "weight": 0.19,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "excellent",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 82,
            "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": "3 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 3
                    }
                  }
                ],
                "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": "biome.json",
                "points": 16,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "biome.json"
                    }
                  }
                ],
                "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": "18 out of 19 merged PRs checked by a CI test -- score normalized to 9",
                "points": 18,
                "status": "partial",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "good",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 65,
            "inputs": {
              "topics": [],
              "has_wiki": true,
              "homepage": "https://openrouter.ai/docs/sdks/typescript/call-model",
              "has_readme": true,
              "has_docs_dir": false,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": "https://openrouter.ai/docs/sdks/typescript/call-model",
                "points": 15,
                "status": "met",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "moderate",
        "name": "Security",
        "value": 50,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "weak",
            "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": 38,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 16,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 2,
              "scorecard_aggregate": 3.8
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection is not maximal on development and all release branches",
                "points": 2.2,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "18 out of 19 merged PRs checked by a CI test -- score normalized to 9",
                "points": 2.2,
                "status": "partial",
                "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 8/18 approved changesets -- score normalized to 4",
                "points": 3,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 5 contributing companies or organizations",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no dangerous workflow patterns detected",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "no update tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow not detected",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "SAST tool is not run on all commits -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "detected GitHub workflow tokens with excessive permissions",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "16 existing vulnerabilities detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "dependency_advisories",
            "band": "exceptional",
            "name": "Dependency advisories",
            "note": "Excluded from scoring (no data or not applicable): No advisories left outstanding. Remaining weights renormalized. Matched the npm:@openrouter/mcp@0.0.1 runtime dependency closure — what installing the published package pulls in — 95 packages. Reachability is not analyzed.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "no_advisories_left_outstanding"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              },
              {
                "code": "advisories_scope_published",
                "params": {
                  "package": "npm:@openrouter/mcp@0.0.1",
                  "assessed": 95
                }
              },
              {
                "code": "advisories_reachability",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "source": "osv",
              "advisories": 0,
              "affected_packages": 0,
              "assessed_packages": 95,
              "unassessed_packages": 0,
              "affected_by_severity": "none",
              "direct_affected_packages": 0
            },
            "components": [
              {
                "key": "direct_dependencies_free_of_known_advisories",
                "name": "Direct dependencies free of known advisories",
                "detail": "no direct dependency carries a known advisory",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "no_direct_advisories",
                    "params": {}
                  }
                ],
                "max_points": 35
              },
              {
                "key": "indirect_dependencies_free_of_known_advisories",
                "name": "Indirect dependencies free of known advisories",
                "detail": "no indirect dependency carries a known advisory",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "no_indirect_advisories",
                    "params": {}
                  }
                ],
                "max_points": 25
              },
              {
                "key": "no_advisories_left_outstanding",
                "name": "No advisories left outstanding",
                "detail": "no advisory carries a publication date",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "advisories_no_publication_date",
                    "params": {}
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "malicious_dependencies",
            "band": "exceptional",
            "name": "Malicious dependencies",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "source": "osv",
              "meaning": "reported as a malicious package by the OpenSSF corpus; the remedy is removal or moving off the compromised name, never an upgrade of the same artifact. Versions the registry has since pulled are listed but not scored",
              "packages": [],
              "red_flag": false,
              "assessed_packages": 95,
              "malicious_packages": 0,
              "direct_malicious_packages": 0,
              "withdrawn_malicious_packages": 0,
              "installable_malicious_packages": 0
            },
            "components": [
              {
                "key": "no_dependency_reported_as_a_malicious_package",
                "name": "No dependency reported as a malicious package",
                "detail": "no dependency is reported as a malicious package",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "no_malicious_dependencies",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "exceptional",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "commit_weight_rule": {
                "min_commits": 50,
                "min_commit_share": 0.1
              },
              "review_only_matches": 0,
              "below_threshold_exposures": [],
              "assessed_self_published_locations": 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": 55,
        "weight": 0.04,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "weak",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 0.947,
              "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": "89 of 94 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 89,
                      "sampled": 94
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "moderate",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 64,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "pnpm-lock.yaml"
              ],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": true,
              "typecheck_configs": [
                "packages/agent/tsconfig.json",
                "packages/mcp/tsconfig.json"
              ],
              "agent_commit_share": 0.12,
              "toolchain_manifests": [],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": "biome.json",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "biome.json"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": "packages/agent/tsconfig.json, packages/mcp/tsconfig.json",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "packages/agent/tsconfig.json, packages/mcp/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": "12 of the last 100 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 12,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "no automated dependency updates observed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_dependency_automation",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "exceptional",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 99,
            "inputs": {
              "primary_language": "TypeScript",
              "largest_source_bytes": 181323,
              "source_files_sampled": 120,
              "oversized_source_files": 2
            },
            "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": "2/120 source files over 60KB",
                "points": 54.1,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 120,
                      "oversized": 2
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          },
          {
            "key": "ai_interfaces",
            "band": "at_risk",
            "name": "Machine-readable interfaces",
            "note": null,
            "notes": [],
            "value": 20,
            "inputs": {
              "example_dirs": [],
              "has_mcp_signal": true,
              "api_schema_files": []
            },
            "components": [
              {
                "key": "api_schema_openapi_graphql_proto",
                "name": "API schema (OpenAPI/GraphQL/proto)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 40
              },
              {
                "key": "mcp_server",
                "name": "MCP server",
                "detail": null,
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              },
              {
                "key": "runnable_examples",
                "name": "Runnable examples",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 40
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? Carries a deliberately small weight: agent tooling is a real maintenance signal, but its absence must never gate the top of the scale (calibration saturates at raw 91, so 100/100 remains reachable with AI Readiness at zero)."
      }
    ],
    "classification": {
      "labels": [
        "mcp-server",
        "library"
      ],
      "scores": {
        "sdk": 2,
        "library": 4.8,
        "mcp-server": 7
      },
      "primary": "mcp-server",
      "evidence": [
        {
          "tier": "declared",
          "label": "library",
          "source": "npm.private",
          "weight": -6
        },
        {
          "tier": "distribution",
          "label": "library",
          "source": "registry:npm",
          "weight": 6
        },
        {
          "tier": "declared",
          "label": "library",
          "source": "npm.entry",
          "weight": 4.8
        },
        {
          "tier": "dependencies",
          "label": "mcp-server",
          "source": "dep:@modelcontextprotocol/sdk",
          "weight": 4
        },
        {
          "tier": "structure",
          "label": "mcp-server",
          "source": "mcp_signal",
          "weight": 3
        },
        {
          "tier": "description",
          "label": "sdk",
          "source": "description:sdk",
          "weight": 2
        }
      ],
      "artifacts": [
        {
          "path": "package.json",
          "labels": [],
          "ecosystem": "npm"
        },
        {
          "path": "packages/agent/package.json",
          "labels": [
            "library"
          ],
          "ecosystem": "npm"
        },
        {
          "path": "packages/mcp/package.json",
          "labels": [
            "library"
          ],
          "ecosystem": "npm"
        }
      ],
      "confidence": "medium",
      "host_extension": false,
      "runs_as_process": true,
      "consumed_by_code": true
    },
    "metrics_version": "2.3.1"
  },
  "warnings": [
    "Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository"
  ],
  "report_type": "repository",
  "generated_at": "2026-08-03T04:51:38.340415Z",
  "schema_version": "0.30.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/o/OpenRouterTeam/typescript-agent.svg",
  "full_name": "OpenRouterTeam/typescript-agent",
  "license_state": "absent",
  "license_spdx": null
}

Las puntuaciones son señales, no garantías. Reflejan prácticas públicamente visibles en GitHub; no son una auditoría de código ni una garantía de seguridad.

Los datos ausentes se excluyen y los pesos se renormalizan; nunca se puntúan como cero. La metodología es versionada y abierta: métricas v2.3.1, esquema v0.30.0 — metodología completa · wiki de métricas.

Cómo se sitúa un resultado dentro del registro general: estadísticas agregadasnpm.