Registro público
Informe de salud del softwareesquema 0.25.0 · métricas 1.13.0 · 2026-07-21 23:00 UTC

LiuTianjie / LinkShell

Remotely view and control local Claude Code / Codex terminal sessions on a mobile device.

TypeScriptMIT★ 34 estrellas⑂ 0 forksdesde abr 2026Ver en GitHub ↗

LiuTianjie/LinkShell tiene un índice de salud de 60 sobre 100, lo que lo sitúa en la banda Moderado. Su puntuación más alta es Vitality (84/100) y la más baja, Security (37/100). Se actualizó por última vez hace 4 días. Una sola persona concentra la mayor parte del trabajo reciente.

60
global / 100
Moderado

Índice de salud del software

Las métricas se agrupan en categorías ponderadas sobre una escala de 1 a 100. El resultado global parte de su media; cuando la evidencia pública activa la Política de Jurisdicciones de Alto Riesgo, la calificación se ajusta y recibe el límite 49 (En riesgo). Preparación para IA queda fuera.

60
Excelente85-100Ejemplar; cumple prácticamente todos los criterios evaluados
Bueno70-84Saludable; carencias menores
Moderado50-69Aceptable con carencias notables; se recomienda revisión
En riesgo30-49Debilidades significativas; su adopción exige cautela
Crítico1-29Problemas 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.

Titularidad

Nickname4thCuenta personal
9 seguidores58 repositorios públicosdesde abr 2018

Este repositorio pertenece a una cuenta personal. Un proyecto con un único propietario conlleva más riesgo de continuidad que uno respaldado por una organización.

Ecosistemas de paquetes

RegistroPaqueteVersiónDescargas / mesVersionesÚltima publicaciónEtiquetas
npmlinkshell-cli0.5.344097209hace 4 díasterminalremoteclaudecodexptybridgemobilewebsocket
npm@linkshell/gateway0.4.493090115hace 4 días
npm@linkshell/protocol0.4.8127961hace 20 días

Métricas por categoría

Vitalidad

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

84Bueno · 22% del índice global
Cómo se puntúa
36/36Recencia de push — último push hace 4 días
9.7/36Cadencia de commits — 14/52 semanas con commits
18/18Volumen de commits — 358 commits en el último año
10/10OpenSSF Scorecard: Maintained — 30 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 10
Datos de entrada utilizados
commits_last_year358
human_commit_share1
days_since_last_push4
active_weeks_last_year14
Cómo se puntúa
27/27Publica versiones — 34 versiones publicadas
36/36Recencia de las versiones — última versión hace 4 días
27/27Cadencia de publicación — una versión cada ~1,8 días
0/10OpenSSF Scorecard: Signed-Releases — sin datos
Datos de entrada utilizados
releases_count34
latest_release_tagcli-v0.5.34
releases_from_tagsno
days_since_latest_release4
mean_days_between_releases1,8
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?

44En riesgo · 18% del índice global
Cómo se puntúa
24.6/60Estrellas — 34 estrellas
0/25Forks — 0 forks
0/15Observadores — 0 observadores
Datos de entrada utilizados
forks0
stars34
watchers0
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonbelow_threshold
Cómo se puntúa
22.5/22.5README
22.5/22.5Licencia — licencia reconocida (MIT)
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_license
has_contributingno
has_issue_templateno
has_code_of_conductno
has_pull_request_templateno
Cómo se puntúa
52.4/80Descargas mensuales — 8466 descargas/mes en npm
0/20Dependientes en el registro — no lo informa este ecosistema
Datos de entrada utilizados
packageslinkshell-cli, @linkshell/gateway, @linkshell/protocol
dependents
ecosystemsnpm
total_downloads
monthly_downloads8466
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?

54Moderado · 24% del índice global
Cómo se puntúa
9/54Factor bus — la mitad de los commits recae en 1 contribuyente(s)
0/22.5Distribución de commits — el principal contribuyente firma el 100% de los commits
1.4/13.5Amplitud de contribuyentes — 1 contribuyentes
0/10OpenSSF Scorecard: Contributors — project has 0 contributing companies or organizations -- score normalized to 0
Datos de entrada utilizados
bus_factor1
contributors_sampled1
top_contributor_share1
Cómo se puntúa
31.2/46.8Resolución de issues — 67% de issues cerradas
38.2/38.3Aceptación de PR — 2/2 PR decididos fusionados
0/15OpenSSF Scorecard: Code-Review — Found 0/30 approved changesets -- score normalized to 0
Datos de entrada utilizados
merged_prs2
open_issues1
closed_issues2
issue_closed_ratio0,667
closed_unmerged_prs0
Cómo se puntúa
10/30Respaldo de la propiedad — cuenta personal (usuario)
0/20Dominio verificado — no aplicable a cuentas de usuario
7.2/25Alcance del propietario — 9 seguidores de LiuTianjie
24.9/25Trayectoria — 58 repos públicos, cuenta de ~8 años
Datos de entrada utilizados
followers9
owner_typeUser
is_verified
owner_loginLiuTianjie
public_repos58
account_age_days3004
Excluidos de la puntuación (sin datos o no aplicable): Dominio verificado. Los pesos restantes se han renormalizado.
Cómo se puntúa
25/25Publicado y resoluble — 3 paquete(s) en npm
35/35Recencia de publicación — última publicación hace 4 días
20/20Historial de versiones — 209 versiones en el registro
20/20No obsoleto — activo, ni obsoleto ni retirado
Datos de entrada utilizados
packageslinkshell-cli, @linkshell/gateway, @linkshell/protocol
ecosystemsnpm
any_deprecatedno
min_days_since_publish4

Calidad de Ingeniería

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

76Bueno · 20% del índice global
Cómo se puntúa
24/24Flujos de trabajo de CI — 5 flujo(s) de trabajo
24/24Pruebas presentes
0/16Configuración de linter
0/9.6Hooks de pre-commit
0/6.4.editorconfig
0/20OpenSSF Scorecard: CI-Tests — sin datos
Datos de entrada utilizados
has_ci
has_tests
has_editorconfigno
has_linter_configno
has_precommit_configno
Excluidos de la puntuación (sin datos o no aplicable): OpenSSF Scorecard: CI-Tests. Los pesos restantes se han renormalizado.

Documentación

100Excelente
Cómo se puntúa
30/30README
25/25Directorio de documentación
15/15Sitio de documentación / página del proyecto — https://liutianjie.github.io/LinkShell/
10/10Descripción del repositorio
10/10Topics — 4 topics
10/10Wiki
Datos de entrada utilizados
topicsclaude-code, codex, remote-control, shell
has_wiki
homepagehttps://liutianjie.github.io/LinkShell/
has_readme
has_docs_dir
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?

37En riesgo · 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
0/2.5CI-Tests — sin datos
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 0/30 approved changesets -- score normalized to 0
0/2.5Contributors — project has 0 contributing companies or organizations -- score normalized to 0
10/10Dangerous-Workflow — no dangerous workflow patterns detected
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5Licencia — license file detected
7.5/7.5Maintained — 30 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 10
5/5Packaging — packaging workflow detected
0/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
0/5SAST — no SAST tool detected
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — sin datos
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
0/7.5Vulnerabilities — 61 existing vulnerabilities detected
Datos de entrada utilizados
sourceopenssf_scorecard
checks_evaluated16
scorecard_versionv5.5.0
checks_inconclusive2
scorecard_aggregate3,7
Excluidos de la puntuación (sin datos o no aplicable): ci_tests, signed_releases. Los pesos restantes se han renormalizado.

Preparación para IA

¿Hasta qué punto está el repositorio preparado para desarrollarse y mantenerse con agentes de codificación de IA? Es una insignia independiente y experimental — peso 0,0, de modo que se presenta por separado y no afecta a la puntuación de salud global.

72Bueno · 0% del índice global
Cómo se puntúa
45/45Instrucciones para agentes — AGENTS.md, CLAUDE.md
0/15Documentación legible por máquinas (llms.txt)
40/40Historial de commits legible — 100 de 100 commits humanos declaran su intención (asunto estructurado o cuerpo explicativo)
Datos de entrada utilizados
has_llms_txtno
legible_history_share1
agent_instruction_filesAGENTS.md, CLAUDE.md
agent_instruction_max_bytes5480
Cómo se puntúa
0/18Arranque con un solo comando
22/22Pruebas automatizadas
0/11Configuración de lint / formato
11/11Verificación estática de tipos — apps/mobile/tsconfig.json, apps/web-dashboard/tsconfig.json, packages/cli/tsconfig.json, packages/gateway/tsconfig.json, packages/shared-protocol/tsconfig.json
10/10Entorno reproducible — Dockerfile, lockfile
10/10Práctica demostrada con agentes — 44 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_dockerfile
typed_language
bootstrap_files
has_devcontainerno
has_linter_configno
typecheck_configsapps/mobile/tsconfig.json, apps/web-dashboard/tsconfig.json, packages/cli/tsconfig.json, packages/gateway/tsconfig.json, packages/shared-protocol/tsconfig.json
agent_commit_share0,44
toolchain_manifests
dependency_bot_commit_share0
Cómo se puntúa
45/45Código verificable por tipos — TypeScript (tipado estático)
52.7/55Tamaños de archivo manejables — 7/168 archivos fuente de más de 60 KB
Datos de entrada utilizados
primary_languageTypeScript
largest_source_bytes203.463
source_files_sampled168
oversized_source_files7

Datos clave

34estrellas de GitHub
1contribuidores
358commits en los últimos 12 meses
4días desde el último push
34versiones publicadas
1factor bus
1issues abiertas
npmecosistemas de paquetes

Advertencias de recopilación de datos

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

Más detalle

Historial de estrellas y forks 34 ★ / 0 ⇿
34Estrellas
32Versiones

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.

01325383442026-042026-052026-07
Mayor 1Menor 0Parche 31
OpenSSF Scorecard 3.7 / 10
3.7agregado

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-07-21 23:00 UTC

10Binary-Artifactsno binaries found in the repo
3Branch-Protectionbranch protection is not maximal on development and all release branches
n/dCI-Testsno pull request found
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/30 approved changesets -- score normalized to 0
0Contributorsproject has 0 contributing companies or organizations -- score normalized to 0
10Dangerous-Workflowno dangerous workflow patterns detected
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
10Maintained30 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 10
10Packagingpackaging workflow detected
0Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 0
0SASTno SAST tool detected
0Security-Policysecurity policy file not detected
n/dSigned-Releasesno releases found
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
0Vulnerabilities61 existing vulnerabilities detected
Dependencias directas 58
RegistroPaqueteRestricción de versiónManifiesto
npm@expo/vector-icons^15.1.1apps/mobile/package.json
npm@legendapp/list^2.0.19apps/mobile/package.json
npm@linkshell/protocolworkspace:*apps/mobile/package.json
npm@react-native-async-storage/async-storage^2.1.2apps/mobile/package.json
npm@react-native-menu/menu^2.0.0apps/mobile/package.json
npm@react-navigation/bottom-tabs^7.3.10apps/mobile/package.json
npm@react-navigation/native^7.1.6apps/mobile/package.json
npm@xterm/addon-fit0.12.0-beta.197apps/mobile/package.json
npm@xterm/addon-web-links0.13.0-beta.197apps/mobile/package.json
npm@xterm/xterm6.1.0-beta.197apps/mobile/package.json
npmexpo~54.0.0apps/mobile/package.json
npmexpo-blur~15.0.8apps/mobile/package.json
npmexpo-build-properties^55.0.13apps/mobile/package.json
npmexpo-camera~17.0.10apps/mobile/package.json
npmexpo-dev-client~6.0.20apps/mobile/package.json
npmexpo-file-system~19.0.21apps/mobile/package.json
npmexpo-glass-effect~0.1.9apps/mobile/package.json
npmexpo-haptics~15.0.8apps/mobile/package.json
npmexpo-image~3.0.11apps/mobile/package.json
npmexpo-image-picker^55.0.16apps/mobile/package.json
npmexpo-linear-gradient^55.0.13apps/mobile/package.json
npmexpo-linking~7.0.1apps/mobile/package.json
npmexpo-router~6.0.23apps/mobile/package.json
npmexpo-secure-store~15.0.8apps/mobile/package.json
npmexpo-speech-recognition^3.1.2apps/mobile/package.json
npmexpo-status-bar~3.0.9apps/mobile/package.json
npmexpo-symbols^55.0.5apps/mobile/package.json
npmmetro-runtime^0.84.2apps/mobile/package.json
npmreact19.1.0apps/mobile/package.json
npmreact-native0.81.5apps/mobile/package.json
npmreact-native-gesture-handler^2.30.1apps/mobile/package.json
npmreact-native-markdown-display7.0.2apps/mobile/package.json
npmreact-native-reanimated^4.3.0apps/mobile/package.json
npmreact-native-safe-area-context~5.6.2apps/mobile/package.json
npmreact-native-screens~4.16.0apps/mobile/package.json
npmreact-native-webview^13.15.0apps/mobile/package.json
npmreact-native-worklets^0.8.0apps/mobile/package.json
npm@linkshell/protocolworkspace:*apps/web-dashboard/package.json
npm@xterm/addon-fit^0.10.0apps/web-dashboard/package.json
npm@xterm/xterm^5.5.0apps/web-dashboard/package.json
npmreact19.1.0apps/web-dashboard/package.json
npmreact-dom19.1.0apps/web-dashboard/package.json
npmreact-markdown^9.0.1apps/web-dashboard/package.json
npmreact-router-dom^7.5.0apps/web-dashboard/package.json
npmrehype-highlight^7.0.2apps/web-dashboard/package.json
npmremark-gfm^4.0.0apps/web-dashboard/package.json
npmzod^3.24.3apps/web-dashboard/package.json
npm@linkshell/gatewayworkspace:*packages/cli/package.json
npm@linkshell/protocolworkspace:*packages/cli/package.json
npmcommander^13.1.0packages/cli/package.json
npmnode-pty^1.0.0packages/cli/package.json
npmqrcode-terminal^0.12.0packages/cli/package.json
npmws^8.18.1packages/cli/package.json
npmzod^3.24.3packages/cli/package.json
npm@linkshell/protocolworkspace:*packages/gateway/package.json
npmzod^3.24.3packages/gateway/package.json
npmws^8.18.1packages/gateway/package.json
npmzod^3.24.3packages/shared-protocol/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

Informe JSON sin procesar legible por máquina
{
  "data": {
    "repo": {
      "topics": [
        "claude-code",
        "codex",
        "remote-control",
        "shell"
      ],
      "is_fork": false,
      "size_kb": 11622,
      "has_wiki": true,
      "homepage": "https://liutianjie.github.io/LinkShell/",
      "languages": {
        "CSS": 8359,
        "HTML": 1288,
        "Shell": 6896,
        "Swift": 33240,
        "Dockerfile": 2296,
        "JavaScript": 80513,
        "TypeScript": 2288408,
        "Objective-C": 1007
      },
      "pushed_at": "2026-07-17T05:08:33Z",
      "created_at": "2026-04-01T02:20:25Z",
      "owner_type": "User",
      "updated_at": "2026-07-17T05:08:36Z",
      "description": "Remotely view and control local Claude Code / Codex terminal sessions on a mobile device.",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "MIT",
      "default_branch": "main",
      "license_spdx_raw": "MIT",
      "primary_language": "TypeScript",
      "significant_languages": [
        "TypeScript"
      ]
    },
    "owner": {
      "blog": "https://LiuTianjie.github.io",
      "name": "Nickname4th",
      "type": "User",
      "login": "LiuTianjie",
      "company": null,
      "location": "Beijing",
      "followers": 9,
      "avatar_url": "https://avatars.githubusercontent.com/u/38846322?v=4",
      "created_at": "2018-04-30T01:40:41Z",
      "is_verified": null,
      "public_repos": 58,
      "account_age_days": 3004
    },
    "license": {
      "state": "standard",
      "spdx_id": "MIT",
      "raw_spdx": "MIT",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "cli-v0.5.34",
          "kind": "other",
          "published_at": "2026-07-17T05:09:25Z"
        },
        {
          "tag": "cli-v0.5.33",
          "kind": "other",
          "published_at": "2026-07-16T13:27:43Z"
        },
        {
          "tag": "v0.5.50",
          "kind": "patch",
          "published_at": "2026-07-01T08:32:22Z"
        },
        {
          "tag": "v0.5.49",
          "kind": "patch",
          "published_at": "2026-07-01T07:26:57Z"
        },
        {
          "tag": "v0.5.48",
          "kind": "patch",
          "published_at": "2026-07-01T04:36:11Z"
        },
        {
          "tag": "v0.5.47",
          "kind": "patch",
          "published_at": "2026-07-01T04:16:31Z"
        },
        {
          "tag": "v0.5.46",
          "kind": "patch",
          "published_at": "2026-07-01T04:09:39Z"
        },
        {
          "tag": "v0.5.45",
          "kind": "patch",
          "published_at": "2026-06-30T16:56:11Z"
        },
        {
          "tag": "v0.5.44",
          "kind": "patch",
          "published_at": "2026-06-30T16:38:18Z"
        },
        {
          "tag": "v0.5.43",
          "kind": "patch",
          "published_at": "2026-06-30T15:52:46Z"
        },
        {
          "tag": "v0.5.42",
          "kind": "patch",
          "published_at": "2026-06-30T14:40:09Z"
        },
        {
          "tag": "v0.5.41",
          "kind": "patch",
          "published_at": "2026-06-30T13:41:20Z"
        },
        {
          "tag": "v0.5.40",
          "kind": "patch",
          "published_at": "2026-06-29T05:59:19Z"
        },
        {
          "tag": "v0.5.39",
          "kind": "patch",
          "published_at": "2026-06-29T04:51:26Z"
        },
        {
          "tag": "v0.5.38",
          "kind": "patch",
          "published_at": "2026-06-18T09:52:11Z"
        },
        {
          "tag": "v0.5.37",
          "kind": "patch",
          "published_at": "2026-06-18T09:09:13Z"
        },
        {
          "tag": "v0.5.36",
          "kind": "patch",
          "published_at": "2026-06-17T16:07:01Z"
        },
        {
          "tag": "v0.5.35",
          "kind": "patch",
          "published_at": "2026-06-17T15:54:10Z"
        },
        {
          "tag": "v0.5.34",
          "kind": "patch",
          "published_at": "2026-06-17T15:42:30Z"
        },
        {
          "tag": "v0.5.33",
          "kind": "patch",
          "published_at": "2026-06-17T13:59:44Z"
        },
        {
          "tag": "v0.5.32",
          "kind": "patch",
          "published_at": "2026-06-17T13:04:54Z"
        },
        {
          "tag": "v0.5.31",
          "kind": "patch",
          "published_at": "2026-06-17T12:36:49Z"
        },
        {
          "tag": "v0.5.30",
          "kind": "patch",
          "published_at": "2026-06-15T07:24:48Z"
        },
        {
          "tag": "v1.1.5",
          "kind": "patch",
          "published_at": "2026-06-10T10:47:23Z"
        },
        {
          "tag": "v0.5.2",
          "kind": "patch",
          "published_at": "2026-05-26T08:54:39Z"
        },
        {
          "tag": "v1.1.3",
          "kind": "patch",
          "published_at": "2026-05-10T15:42:32Z"
        },
        {
          "tag": "v0.2.123",
          "kind": "patch",
          "published_at": "2026-05-07T12:40:27Z"
        },
        {
          "tag": "v0.2.122",
          "kind": "patch",
          "published_at": "2026-05-05T16:56:48Z"
        },
        {
          "tag": "v1.1.2",
          "kind": "patch",
          "published_at": "2026-04-15T07:51:08Z"
        },
        {
          "tag": "v1.1.1",
          "kind": "patch",
          "published_at": "2026-04-14T10:41:39Z"
        },
        {
          "tag": "v1.0.4",
          "kind": "patch",
          "published_at": "2026-04-13T11:21:26Z"
        },
        {
          "tag": "v1.0.3",
          "kind": "patch",
          "published_at": "2026-04-11T05:21:15Z"
        },
        {
          "tag": "v1.0.2",
          "kind": "patch",
          "published_at": "2026-04-10T17:31:31Z"
        },
        {
          "tag": "v1.0.0",
          "kind": "major",
          "published_at": "2026-04-09T19:17:54Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "522702dd0221a3428d5c5721dcc93afb9e7d35a7",
          "body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: deploy gateway v0.4.49",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-07-17T05:08:28Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "619ab681895d1e77ae7b2a834b3d7677ea696219",
          "body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: v0.5.52",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-07-17T05:08:27Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ffe875821f7f1bbd03fd2df2ec4d9c02417880c6",
          "body": "Web (workspace-store + console page):\n- conversation.opened now unconditionally clears history loading/syncing\n  (was seeded only when absent, so loading stuck true forever and blocked\n  scroll-up pagination)\n- cached timelines render instantly but still sync: first selection per\n  session sends con\n[…]\nnd full scan\n\nTests: 7 new (transcript cache incl. LRU/invalidation, client-start dedup\n+ failure retry); 91/91 pass, workspace typecheck clean.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(web,cli): conversation switch — loading states + open latency",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-07-17T04:03:14Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3d2e379c0227aa3278a349adf3467c9e90b7ed69",
          "body": "xterm 6.1.0-beta.197's Gesture._inertia synthesizes momentum CHANGE events\nwithout clientX/clientY; with SGR mouse tracking active (TUI running),\ngetMouseReportCoords computes undefined - rect.left = NaN, the NaN passes\nthe col/row bounds check (NaN comparisons are all false), and the SGR\nencoder em\n[…]\nnly\n  CSI sequences that contain a NaN parameter — user-typed \"NaN\" text,\n  pastes, arrow keys, and healthy mouse reports pass through unchanged\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(app): stop terminal typing literal NaN during touch-scroll fling",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-07-16T17:04:44Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8bdb76f86067a3c05606ef0120a9b268852fe158",
          "body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: deploy gateway v0.4.48",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-07-16T13:28:56Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "5e38938f98b579fc9e956b97baef914df807d006",
          "body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: v0.5.51",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-07-16T13:20:57Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "38e9acf516fd0299fd536a75d91de2c01558cd59",
          "body": "- Autoscroll follows streaming text (ResizeObserver); floating jump-to-latest\n- Global Esc interrupts running turn; Web Notifications + title badge on\n  turn-finish / waiting-permission while tab unfocused\n- Edit/Write/MultiEdit tool cards + permission cards render inline diffs;\n  Bash permissions s\n[…]\niewport outside embed\n- Sessions: offline hosts stay visible + activity sort; storage GC on forget;\n  gateway URL commit-on-blur with validation\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(web): P0 UX + reliability batch for the agent console",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-07-16T13:10:00Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5e8053a3161c405b6bfd78b0c4f710ca88905760",
          "body": "- cli 0.5.32, gateway 0.4.47 (protocol unchanged at 0.4.8)\n- ships command-palette description + arg-hint (fc047fd)\n- bump luma-gateway.yml image tag to 0.4.47 for cloud redeploy",
          "is_bot": false,
          "headline": "release: v0.5.50",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-07-01T08:31:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fc047fd1b50439f964304b71a5f932b683da215e",
          "body": "The slash palette only rendered /name + title. Claude Code's palette also\nsurfaces the command description and signals whether a command takes an\nargument. Both fields already flow to the web (agentCommandDescriptorSchema\ncarries description + argsMode) — just weren't rendered.\n\n- Second line shows description when it adds info beyond the title.\n- '需要参数'/'可选参数' badge from argsMode so users aren't surprised mid-type.\nWeb-only, build clean.",
          "is_bot": false,
          "headline": "feat(web): show command description + arg hint in slash palette",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-07-01T07:38:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "914c0c58061b36eb3683c0cc81a55954e8761d6c",
          "body": "- protocol 0.4.8, gateway 0.4.46, cli 0.5.31\n- MCP server status visibility + fork conversation (Claude)\n- fs-watch scan-storm + map-leak perf fixes",
          "is_bot": false,
          "headline": "release: v0.5.49",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-07-01T07:26:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "06dc34b85934093e36b27f4fd84f1c8ad68582ab",
          "body": "Read the installed @anthropic-ai/claude-agent-sdk types (sdk.d.ts:968,2110)\nas ground truth instead of guessing:\n- mcpServerStatus(): Promise<McpServerStatus[]> DOES exist on the Query — the\n  Source-B seed path is real, not speculative.\n- status enum is 'connected'|'failed'|'needs-auth'|'pending'|'\n[…]\n(already handled; now locked).\n\nNew unit test asserts the real shape (needs-auth→needs_auth, disabled, tools[]).\nClears the MCP half of the runtime-verification caveat. typecheck clean, 84 tests pass.",
          "is_bot": false,
          "headline": "fix(agent): align MCP status with real SDK McpServerStatus shape",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-07-01T07:15:28Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "78cb5ac53ba3980d1938850ee06b4e5f9ed1864f",
          "body": "Two feature-parity gaps with Claude Code / Codex, both additive.\n\nMCP server status:\n- protocol: agentMcpServer{Status,Descriptor}Schema + optional mcpServers on\n  the per-provider capability (rides agent.v2.capabilities, no new message).\n- CLI: stop dropping mcpServer/startupStatus/*; handleMcpStar\n[…]\n on turns (claude only) → store.forkConversation\n  sends conversation.open with fork fields; auto-switches on opened.\n\n5 new MCP unit tests. typecheck + build clean across all packages, 83 tests pass.",
          "is_bot": false,
          "headline": "feat(agent): surface MCP server status + fork conversation from a turn",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-07-01T07:10:56Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "581e6e79bfc81746088ed734c2819b825017462c",
          "body": "The live-refresh feature re-ran syncProviderSessions every ~1.5s while any\nsession was active, and listSessions read+fully-parsed every transcript in\n~/.claude/projects on each call — a full-disk scan storm on every keystroke\nof an active turn.\n\n- ClaudeSdkClient/ClaudeStreamJsonClient.listSessions:\n[…]\nnc, so\n  a store dir created after startup (first `codex` run) gets watched lazily.\n\nCodex disk status derivation already stat-gates before reading; left as-is.\ntypecheck + build clean, 78 tests pass.",
          "is_bot": false,
          "headline": "perf(cli): kill fs-watch scan storm + prune unbounded maps",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-07-01T06:36:47Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ecc8092f7a0c72eea7aad39d2b6076102446902e",
          "body": "Probed which harness slash commands actually execute via the Agent SDK query()\nin headless mode: /context and /cost return real output, /clear and /compact\nreally run, but /help, /status (and /model, already hidden) return\n\"isn't available in this environment\" — dead in the palette, giving the user\nonly a useless error on tap. /status is also redundant with the web console's\nown status display. Add both to CLAUDE_REMOTE_HIDDEN_COMMANDS.",
          "is_bot": false,
          "headline": "fix(cli): hide /help and /status — dead commands in headless",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-07-01T04:40:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "547b2ee0a27191dc8709655837df9300aea7ef71",
          "body": "- fix(cli): external permission requests now map to the correct provider by disk lookup (~/.claude vs ~/.codex), so an external Codex session's permission card lands on its real session card, not a phantom agent-remote-claude-<codexId>\n\ncli 0.5.29→0.5.30, root 0.5.47→0.5.48. Gateway unchanged (CLI-only — bridge-only fix).",
          "is_bot": false,
          "headline": "release: v0.5.48",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-07-01T04:35:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7e396f4af2fb60b56e798a0b7d650f391cd62fba",
          "body": "…sk lookup\n\nThe external-session permission relay built the v2 conversationId from the\nspawned PTY's provider, but the same curl hook is written to BOTH ~/.claude and\n~/.codex while the hook HTTP server has a single provider. So an external Codex\nsession's PermissionRequest arriving on a \"claude\" se\n[…]\nare, human-in-loop). Falls back to the PTY provider if not\nfound.\n\nVerified: providerForExternalSession returns codex/claude/undefined correctly\nfor real on-disk ids; all 22 bridge-session tests pass.",
          "is_bot": false,
          "headline": "fix(cli): map external permission request to the right provider by di…",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-07-01T04:33:23Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "442fafdce54868951c5a0821b129a463f50b0817",
          "body": "…oval\n\nAdds real-HTTP integration tests for the layer the earlier unit tests skipped —\nthe endpoint claude's curl hook actually hits. With config-writers stubbed (so\nit never touches the real global ~/.claude/settings.json), it verifies:\n\n- a PermissionRequest POST holds the connection, and resolveP\n[…]\nvery layer of the relay I control is now\ncovered. The only remaining unverifiable step is claude honoring the returned\ndecision — its own hook contract, not our code. All 22 bridge-session tests pass.",
          "is_bot": false,
          "headline": "test(cli): cover the hook HTTP-server layer for external-session appr…",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-07-01T04:24:06Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "af22177f43b5506175aebf3905b38ecf190ee386",
          "body": "Automated verification of the v0.5.46/0.5.47 external-session permission relay —\nevery layer I control, without needing a live claude process:\n\n- sendHookPermissionRequest emits a v2 request whose conversationId matches how\n  the session tree builds ids (agent-remote-claude-<session_id>), carries a\n\n[…]\nch to the workspace; a non-hook response falls through to the\n  workspace as before.\n\nOnly the real claude-process hook trigger itself is out of scope for unit tests.\nAll 19 bridge-session tests pass.",
          "is_bot": false,
          "headline": "test(cli): cover external-session permission relay end-to-end",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-07-01T04:20:21Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "91fcb9ccfaca8422699d90ba9b654859b58d0987",
          "body": "- fix(cli): external-session permission requests now include the timeline item so the web console renders a clickable allow/deny card (v0.5.46 flipped the status badge but showed no actionable card — half-dead)\n\ncli 0.5.28→0.5.29, root 0.5.46→0.5.47. Gateway unchanged (CLI-only — bridge-only fix; web render was already correct).",
          "is_bot": false,
          "headline": "release: v0.5.47",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-07-01T04:15:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6eb94908d195b3cc139319ddca98e5abeda8413d",
          "body": "…uest\n\nThe web store only renders a clickable allow/deny card when\nagent.v2.permission.request carries a timeline `item` (otherwise it just flips\nthe conversation's status badge to waiting_permission). The external-session\nrelay added in 9c72d69 emitted the request WITHOUT an item, so an external\nse\n[…]\nission → agent.v2.permission.respond (intercepted back to the\npending hook HTTP connection).\n\nFound by static tracing of the store's `if (p.item)` gate against the render\npath — not by a live session.",
          "is_bot": false,
          "headline": "fix(cli): include timeline item in external-session v2 permission req…",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-07-01T04:13:50Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3099742c275adafeea65ba01d7f9b5ee9ca28bca",
          "body": null,
          "is_bot": false,
          "headline": "release: deploy gateway v0.4.45",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-07-01T04:09:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2d57dd66f9038dc856bb600d52f3f08e6dd88b00",
          "body": "- feat(cli): external claude/codex session permission requests now surface on the v2 web console (mapped to the right session card) and can be approved/denied remotely — previously only LinkShell-driven sessions worked\n- fix(web): drop home usage-dashboard block; hide offline sessions from the list\n\ncli 0.5.27→0.5.28, gateway 0.4.44→0.4.45 (web fixes ride the gateway Docker redeploy), root 0.5.45→0.5.46",
          "is_bot": false,
          "headline": "release: v0.5.46",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-07-01T04:06:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9c72d691a6ce63ae33f54d4e221e07ea881fa9f6",
          "body": "…onsole\n\nExternal claude/codex sessions already hit the existing hook HTTP server (the\nPreToolUse/PermissionRequest hooks are written to global settings.json and fire\nfor any session), and the server already holds the connection waiting for a\ndecision. But sendHookPermissionRequest only emitted the \n[…]\n the client_write\nset so the interceptor is reachable; id mapping is consistent. End-to-end with a\nreal external permission prompt still needs a live non-full-access session to\nconfirm the whole loop.",
          "is_bot": false,
          "headline": "feat(cli): route external-session permission requests to the v2 web c…",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-07-01T04:03:08Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a096dc7decf04130885e889213fe345d16413a59",
          "body": "… the list\n\n- Remove the host-wide usage-dashboard block at the top of the session list\n  (it also got stuck spinning on \"正在扫描本机会话记录…\" when no report was\n  available). The full usage view is still reachable from the console.\n- Only show online sessions (hasHost). Offline (host-gone) sessions are hidden\n  from the list and count via a derived visibleSessions; the underlying state is\n  kept intact so cache reconciliation across refreshes still works.",
          "is_bot": false,
          "headline": "fix(web): drop home usage-dashboard block; hide offline sessions from…",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-07-01T03:27:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8db0c84410f2a3c0f4672e640d058a070a572aa6",
          "body": "- feat(cli): toolbar shows a session's real reasoning-effort / permission / plan-mode read from the on-disk transcript (Codex turn_context, Claude permissionMode), instead of falling back to a fake first-option default. One file read on open only; no per-list CPU cost.\n\ncli 0.5.26→0.5.27, root 0.5.44→0.5.45. Gateway unchanged (CLI-only — web pill rendering already shipped in 0.5.44; gateway only relays).",
          "is_bot": false,
          "headline": "release: v0.5.45",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-30T16:55:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9cd3dc34e5a79d652aaa73e0602874247eba3548",
          "body": "The toolbar pills fell back to \"默认\" for sessions LinkShell didn't drive\nbecause their reasoning-effort/permission/plan settings were never extracted —\nonly the model was. Read the real config from the on-disk transcript at open\ntime (one file read, only for the opened conversation — never per-list, \n[…]\n The \"默认\" placeholder\nremains the correct fallback when a setting genuinely isn't recorded. Verified\nend to end against real transcripts (Codex: effort xhigh/default/full_access;\nClaude: full_access).",
          "is_bot": false,
          "headline": "feat(cli): show a session's real effort/permission/mode in the toolbar",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-30T16:52:50Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "7591430f9665298270efccde14633ac62c9dc17c",
          "body": null,
          "is_bot": false,
          "headline": "release: deploy gateway v0.4.44",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-30T16:37:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2378c3878df02106f75eb4694c8a903c13f03a85",
          "body": "- fix(web): control pills (思考强度/权限) show \"默认\" when a session carries no explicit value instead of misreporting the first option (低/只读)\n- fix(web): switching conversations jumps to the latest message instead of inheriting the previous conversation's scrolled-up position\n\ncli 0.5.25→0.5.26, gateway 0.4.43→0.4.44 (web fixes ride the gateway Docker redeploy), root 0.5.43→0.5.44",
          "is_bot": false,
          "headline": "release: v0.5.44",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-30T16:35:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7f95fccabbc03221ac990a9e037a05b36e6ea10e",
          "body": "atBottomRef is shared across conversations, so after scrolling up to read\nhistory in one conversation, switching to another inherited that scrolled-up\nstate and landed mid-history instead of at the newest message. Track the last\nscrolled conversation id: on a switch, force scroll to bottom and reset\natBottomRef; within the same conversation keep the existing prepend-pin /\nstick-to-bottom behavior.",
          "is_bot": false,
          "headline": "fix(web): jump to latest message when switching conversations",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-30T16:32:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f501a5dbf3e2f69b3f8b019db570b7d023277945",
          "body": "…first option\n\nThe reasoning-effort and permission pills read conversation.reasoningEffort /\npermissionMode, but a session discovered off disk (not driven by LinkShell)\ncarries neither — so PillSelect's `value ?? options[0]` displayed the first\noption (\"低\" / \"只读\") as if it were the selected setting,\n[…]\n are unset,\nso show a neutral \"默认\" placeholder instead and don't highlight any option as\nselected until the user picks one. The model pill is unchanged (its value is\nparsed from disk and is accurate).",
          "is_bot": false,
          "headline": "fix(web): control pills show \"默认\" when no explicit value, not a fake …",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-30T16:32:07Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "317f8c6ac6a085536c250a6268118a6d5c120e55",
          "body": null,
          "is_bot": false,
          "headline": "release: deploy gateway v0.4.43",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-30T15:52:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "65eaca1fdd5ad5275517594704e04ba8d14d84bc",
          "body": "- feat(cli): watch ~/.claude/projects and ~/.codex/sessions so externally-started sessions and status changes surface live in the console (was frozen at connect time) — the gap vs CodeIsland\n- fix(web): declutter mobile console header (was overlapping)\n\ncli 0.5.24→0.5.25, gateway 0.4.42→0.4.43 (mobile header fix rides the gateway Docker redeploy), root 0.5.42→0.5.43",
          "is_bot": false,
          "headline": "release: v0.5.43",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-30T15:49:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "31b85febbc80d71d95dc7942cca198932914a27e",
          "body": "Root cause of \"can't see other processes' sessions\": the console requested the\nsession list only once, at connect (requestConversationList has zero call\nsites; requestSnapshot fires only on connect). syncProviderSessions — the only\nfunction that scans disk — therefore ran once and the tree froze at \n[…]\nist.result is host_to_client (gateway forwards it) and the web\nhandler merges it unconditionally; mergeConversations uses >= on lastActivityAt\n(bumped by mtime) so a running→idle update isn't dropped.",
          "is_bot": false,
          "headline": "feat(cli): watch session stores so external sessions surface live",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-30T15:47:56Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6a89f6a356dfcd5f6c109acc0cd58fac3c989961",
          "body": "On phone widths the header crammed every element into one non-shrinking row,\nso the icons and chips overlapped into an unreadable strip. Hide the three\nfixed-width, secondary items on mobile: the context-usage chip, the host-wide\ntoken chip (both available in the usage panel), and the port-preview button\n(its right drawer is awkward on phones anyway). Nav / status / search / files /\nterminal / usage remain.",
          "is_bot": false,
          "headline": "fix(web): declutter mobile console header (was overlapping)",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-30T14:48:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ee725566b6c50e83cdab61f2a080a1fb1cb2a314",
          "body": null,
          "is_bot": false,
          "headline": "release: deploy gateway v0.4.42",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-30T14:39:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "484556825251e8bec95594debb7185a0848d9b06",
          "body": "- fix(web): single-select question cards no longer accept multiple picks (+ 可多选 hint)\n- feat(cli): surface running status for externally-driven Codex sessions — external `codex` turns now show 运行中, enter the active-session area, and click-opens the conversation instead of a terminal\n- fix(cli): hydrate externally-driven sessions on open (no longer stuck on \"加载对话记录…\")\n\ncli 0.5.23→0.5.24, gateway 0.4.41→0.4.42 (web card fix rides the gateway Docker redeploy), root 0.5.41→0.5.42",
          "is_bot": false,
          "headline": "release: v0.5.42",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-30T14:37:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0776f827b776f4c6022a3f12177a36f85a8804a7",
          "body": "Codex sessions always showed \"idle\" in the tree, so an externally-run `codex`\nturn never entered the active-session area — and the active card fell back to\nopening a terminal instead of the conversation. Root cause: Codex's app-server\nthread/list reports no live status and only knows threads this pr\n[…]\nrunning Codex\nsession shows \"运行中\", enters the active area, and clicking opens the\nconversation.\n\nVerified against real rollouts: running/idle branches, fresh/stale gating, and\nfork dual-id extraction.",
          "is_bot": false,
          "headline": "feat(cli): surface running status for externally-driven Codex sessions",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-30T14:33:59Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9e7ccc18adb4094bd85481fb61a3834e8e08d499",
          "body": "askUserQuestion sends selectionLimit only for multi-select, so a single-select\nquestion arrives with selectionLimit undefined. The toggle handler only treated\nlimit===1 as single-select and fell through to unbounded multi-select for\nundefined — letting a single-select question accept multiple answer\n[…]\n limit>1, an inconsistency). Treat\nabsent/≤1 limit as single-select, matching the CLI's mapping. Also add a\n\"可多选\" hint to genuinely multi-select cards, which otherwise look identical\nto single-select.",
          "is_bot": false,
          "headline": "fix(web): single-select question cards no longer accept multiple picks",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-30T14:33:44Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2390eaaa13b06f01f52ce74f8b170fa0ee71ace9",
          "body": "Regression from the live running/idle status feature (v0.5.39). The\nopen-conversation hydration guard skipped loading the transcript when\nstatus === \"running\", on the assumption that a running conversation is being\ndriven by LinkShell and its event stream fills the timeline. But an externally-\ndrive\n[…]\non hydrates from disk on open, while a LinkShell-driven\nturn still skips redundant re-hydration. Verified with a 6-case truth table.\n\nrelease: v0.5.41 (cli 0.5.22→0.5.23). Gateway/CLI-relay untouched.",
          "is_bot": false,
          "headline": "fix(cli): hydrate externally-driven sessions on open (stuck \"加载对话记录…\")",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-30T13:39:35Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "bc06ca8a76a805fb0d0c42edee173fd48e123fbf",
          "body": "perf(cli): deriveTranscriptStatus short-circuits stale transcripts + backward\ntail scan instead of full split — avoids parsing most sessions on listSessions.\nGateway untouched (CLI-only patch). cli 0.5.21→0.5.22, root 0.5.39→0.5.40.",
          "is_bot": false,
          "headline": "release: v0.5.40",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-29T05:58:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9fac6e7a0a1e364c8f70f76018488ddf7013be87",
          "body": "listSessions() derives running/idle for every session in ~/.claude/projects on\neach list call. Two cheap wins, both behavior-equivalent (verified against the\nprior implementation across 13 fixtures incl. CRLF, no-trailing-newline,\nhalf-written tail, empty file):\n\n- Stale-file short-circuit: every no\n[…]\nuge\n  (100k-line) transcript just to inspect its tail.\n\nGateway is unaffected — it never runs this code (transparent relay + in-memory\nstatus cache only); all transcript parsing lives in the CLI host.",
          "is_bot": false,
          "headline": "perf(cli): avoid parsing stale transcripts in deriveTranscriptStatus",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-29T05:51:57Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "7703c5ec9522757b1556d436cc4c724badbc8070",
          "body": null,
          "is_bot": false,
          "headline": "release: deploy gateway v0.4.41",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-29T05:26:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0a54ea41c809bb7ed77da90d0340bdcfdc9e2579",
          "body": "Cloud premium gateway logs were flooding with\n\"token store save failed: SyntaxError: Unexpected end of JSON input\".\nThe state-store request() helper called res.json() on every non-204 response,\nbut PostgREST upserts (saveToken/savePairing, Prefer: resolution=merge-duplicates)\nreturn 2xx with an EMPT\n[…]\nEST replies 204 (cleaner, less bandwidth).\n\nOnly affects the cloud gateway (Supabase-backed store); embedded/LAN gateways\nhave no store and were unaffected, so CLI is unchanged. gateway 0.4.40→0.4.41.",
          "is_bot": false,
          "headline": "fix(gateway): tolerate empty response body in Supabase state store",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-29T05:23:38Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "eaa1711a0d25030310ca27fd1c8108d77db0cc86",
          "body": null,
          "is_bot": false,
          "headline": "release: deploy gateway v0.4.40",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-29T04:51:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "723df993271ae02d3cc00f189272bf6d7470b1d0",
          "body": "- discover Claude slash commands + skills via SDK (/goal + ~48 skills now visible in web palette; replaces drifting hardcoded list)\n- paginate Claude conversation history (scroll-back parity with Codex on >200-turn sessions)\n- surface live running/idle status for externally-driven Claude sessions\n- \n[…]\nn status when its turn finishes\n- fix: usage dashboard card wrap + sessions-section margin\n\ncli 0.5.20→0.5.21, gateway 0.4.39→0.4.40 (web UI fixes ride the gateway Docker redeploy), root 0.5.38→0.5.39",
          "is_bot": false,
          "headline": "release: v0.5.39",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-29T04:46:45Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "871264b0c2a09eba1d5cb801df598e4223869d00",
          "body": "…rnal-session live status\n\n- discover Claude slash commands + skills via SDK (replaces hardcoded list; /goal + ~48 skills now visible)\n- usage dashboard layout fixes (card wrap, section margin)\n- paginate Claude conversation history (scroll-back parity with Codex)\n- surface live running/idle status for externally-driven Claude sessions\n- fix: clear external session status when its turn finishes (review-found high bug)",
          "is_bot": false,
          "headline": "Merge: Claude slash-command/skill discovery, history pagination, exte…",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-29T04:42:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "56f9e5c048e317c4de6e24aab4bf2bad3f5fdb18",
          "body": "The status-precedence block let an externally-derived \"running\" stick forever.\nFor a session LinkShell never drives, the sync block is the only status writer:\nonce a fresh mid-turn transcript set the conversation \"running\", the next sync\n(transcript now idle) fell through to `existing?.status ?? \"id\n[…]\nrsarial review of the merge diff (three independent\nreview dimensions converged on this). Verified with a full precedence truth\ntable (10/10), covering the running→idle clear and Codex non-regression.",
          "is_bot": false,
          "headline": "fix: clear external Claude session status when its turn finishes",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-29T04:41:00Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0fcbeff27717a8578548a6c3ef7041fa1657e001",
          "body": "…essions\n\nA Claude session being actively driven by another process (the user's own\n`claude` terminal, not LinkShell) previously always showed as \"idle\" in the\nsession list — the workspace hardcoded idle for discovered sessions and never\ninspected the transcript for liveness.\n\nAdd deriveTranscriptSt\n[…]\nrobe time\n(age 1s); all others idle. Pure-function branches (mid-turn+fresh→running,\nmid-turn+stale→idle, end_turn+fresh→idle, half-written-line+fresh→running)\neach confirmed against real transcripts.",
          "is_bot": false,
          "headline": "feat: surface live running/idle status for externally-driven Claude s…",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-29T03:39:44Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4140baff22d80dd62874cafacda96f058f2143e9",
          "body": "…odex)\n\nClaude sessions with more than MAX_TIMELINE_ITEMS turns previously couldn't\nscroll back — readSession loads the whole transcript but the timeline keeps\nonly the last 200 items, and Claude had no listTurns, so loadOlderHistory\nreturned empty (Codex could already page).\n\nAdd ClaudeSdkClient.li\n[…]\nses an opaque string cursor\nthat an integer index would corrupt.\n\nVerified end-to-end against a real 144-turn transcript: full paginated walk\ncovers every turn with zero gaps and terminates correctly.",
          "is_bot": false,
          "headline": "feat: paginate Claude conversation history (scroll-back parity with C…",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-29T02:26:05Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "11d3a24df6141add612f8f3c2f1ac6c8219d48b0",
          "body": "…board layout\n\nCLI: query the Agent SDK's supportedCommands() at capability time so the\nreal installed command/skill set (incl. /goal and ~48 user skills that were\npreviously invisible in web) reaches clients, instead of a hardcoded list\nthat drifts. Flows through the existing parseModelListCapabili\n[…]\nt spans ~80 entries.\n\nweb: fix usage dashboard — drop spaces in formatDuration + whitespace-nowrap on\nStatCard so \"11小时48分\" no longer wraps and inflates the card; add mt-10 above\nthe sessions section.",
          "is_bot": false,
          "headline": "feat: discover Claude slash commands + skills via SDK; fix usage dash…",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-29T02:09:38Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2c58dd3d71017b545d047bc435fd264b188a06bf",
          "body": "Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: deploy gateway v0.4.39",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-18T09:51:57Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "af3650e05d5abaf62ed0f5c04baf18678aa9bdfc",
          "body": "- fix: heatmap gap 3px→4px, cell 10px→12px, corner 2px→3px\n- fix: heatmap tooltip includes mode label (当日/本周/累计)\n- fix: session list cards: usage moved to separate line below cwd\n- fix: control header usage chip now shows host-wide aggregate\n- fix: click external-terminal → jump to matching conversation\n\nCo-Authored-By: Claude Opus 4 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: v0.5.38",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-18T09:51:33Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "cf52dd0e717713d72733b9f4167b465a36ecef79",
          "body": "Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: deploy gateway v0.4.38",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-18T09:08:59Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ededf5ca3543cbfd553ce17c569ad9c9b22d0fd6",
          "body": "- fix: console header shows host-wide usage chip (not just session list page)\n- fix: hide <synthetic> model conversations from \"最近会话\" (unusable internal entries)\n- fix: external-terminal click → open matching agent conversation, not blank terminal\n- fix: add useCallback import to ConversationTree.tsx\n\nCo-Authored-By: Claude Opus 4 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: v0.5.37",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-18T09:08:35Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "3d14ef4ed8d69be83d2de4e55aa0c19ba8322e6d",
          "body": "Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: deploy gateway v0.4.37",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-17T16:06:41Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "0e2b0177068cfdbe41f6782e54d7e6efda6fa598",
          "body": "- fix: render the complete UsageDashboard (cards + heatmap + breakdown bars)\n  on the session list page — not a crippled stat-card subset\n- refactor: extract UsageDashboardContent for sharing between overlay and inline\n\nCo-Authored-By: Claude Opus 4 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: v0.5.36 — full usage dashboard on session list",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-17T16:06:17Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "be9191eadae9ba478ad10d2a42b61be92aa02a19",
          "body": "Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: deploy gateway v0.4.36",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-17T15:53:49Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "c4c1a7e210fb56b44e393056338f22f647512371",
          "body": "- feat: CLI auto-sends usage report on connect (fire-and-forget, 60s cache)\n  so the session list page shows summary cards without opening the console\n- feat: gateway caches usage.report per session + exposes via /sessions HTTP\n- feat: session list page shows cumulative tokens / peak / longest task /\n  streaks cards at the top\n- fix: usage-report aggregates have 60s in-memory cache\n\nCo-Authored-By: Claude Opus 4 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: v0.5.35 — usage cards on session list",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-17T15:53:14Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ed11c5dba2b3d91f46fef617c181f9f5b6a0909f",
          "body": "Bump cloud gateway image to 0.4.35 so the usage-dashboard aggregation\n(agent.v2.usage.request/usage.report) reaches gateway.itool.tech.\n\nCo-Authored-By: Claude Opus 4 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: deploy gateway v0.4.35",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-17T15:42:07Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "808c4857742649d5db17c9812339f632833f9ade",
          "body": "- feat: host-side cross-provider usage aggregator (Claude + Codex transcripts\n  on disk, decoupled from live turns — history + externally-started sessions all\n  count), verified on 241M real corpus: 69.3B tokens, 530 sessions, 36 active\n  days, 11h48m longest continuous task, 12-day streak\n- feat: G\n[…]\noutes via\n  existing client_read/host_to_client classification)\n- No pricing (user preference); no charting library (heatmap is CSS grid squares)\n\nCo-Authored-By: Claude Opus 4 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: v0.5.34 — usage dashboard",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-17T15:41:08Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "13fcfbd52912a7ddbfab6bf6cdb614181557c57a",
          "body": "Bump cloud gateway image to 0.4.34 so disk-decoupled usage relay + recency\nordering reach gateway.itool.tech.\n\nCo-Authored-By: Claude Opus 4 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: deploy gateway v0.4.34",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-17T13:57:55Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "63fd93ecfa09a44d4c585754fda83731793c13da",
          "body": "- fix: decouple token/usage collection from live LinkShell turns — read it\n  straight from the on-disk transcript (message.usage per assistant line) in\n  parseClaudeJsonlSession, so history + externally-started sessions all carry a\n  context meter, not just sessions LinkShell is actively driving\n- f\n[…]\nat to\n  the top instead of being buried\n- refactor: share usage field-normalization between the live-turn and on-disk\n  paths so they can't drift\n\nCo-Authored-By: Claude Opus 4 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: v0.5.33",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-17T13:53:37Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e2dc4f5d5a1b246eb4023db470d0e0ba1fac49c5",
          "body": "Bump cloud gateway image to 0.4.33 so the session-list usage extraction\n(agentUsage in /sessions + /sessions/mine) reaches gateway.itool.tech.\n\nCo-Authored-By: Claude Opus 4 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: deploy gateway v0.4.33",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-17T13:08:59Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "1fab2b740f905332f83e488c4d3ba7021755522c",
          "body": "- feat: show token/context usage + cost on the session list cards (no need to open the console) — gateway extracts usage from agent events into the session summary, served over /sessions + /sessions/mine\n- fix: top-bar status badge no longer overflows / crushes the toolbar on mobile (prefix truncates, dot/status/timer stay intact; hide connection text on mobile)\n\nCo-Authored-By: Claude Opus 4 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: v0.5.32",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-17T13:02:10Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "1899915fd4cb289dfd0c3afa1c6206c7fa96288a",
          "body": "Agent console parity work (web + protocol + CLI):\n- feat: semantic tool cards (WebSearch/WebFetch/Grep/Glob/Read/...) with icon + label + arg summary\n- feat: turn elapsed timer in status badge + completed-turn duration\n- feat: surface token/context usage + cost (protocol usage field; capture Claude \n[…]\nt.usage + Codex tokenUsage that were previously dropped)\n- chore: remove orphaned native mobile agent UI (web console is now canonical), ~12k LOC\n\nCo-Authored-By: Claude Opus 4 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: v0.5.31",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-17T12:33:55Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "72a052b76d515d710d21de73703d4da429b18afe",
          "body": null,
          "is_bot": false,
          "headline": "release: deploy gateway v0.4.31",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-16T08:01:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b30689052ea4d62f0d8c449d182d17b19d9c7f1b",
          "body": null,
          "is_bot": false,
          "headline": "fix: seed embedded web session history",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-16T07:58:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6674bee7e1b56719e5c8bd06657c1051c5fcdccd",
          "body": null,
          "is_bot": false,
          "headline": "fix: persist mobile recent sessions",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-16T07:54:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6cd06a2a055ae735c25d6e8c956d707f1a943f5b",
          "body": null,
          "is_bot": false,
          "headline": "feat: deploy workflow",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-16T04:11:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "90e9663c13a7913af0487400e2da7598ee25316e",
          "body": null,
          "is_bot": false,
          "headline": "release: v0.5.30",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-15T07:22:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9c1020ded72f1baf04cc986f546d55910d69ca85",
          "body": null,
          "is_bot": false,
          "headline": "feat: show agent status in web sessions",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-15T06:36:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f43805717ca544ba5ed04b85d96817d6fcdfbaf0",
          "body": null,
          "is_bot": false,
          "headline": "docs: update",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-10T12:58:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e01b8f698712c2c1a96f987a012e8f3ec112cbbb",
          "body": null,
          "is_bot": false,
          "headline": "perf: release sop",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-10T11:03:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "24dd5cb29a93de8cb167d06fe20be2d064e755fd",
          "body": "…web canvas\n\nSessionScreen already uses theme.bgTerminal (#000000) internally, but\nthe route returned a Fragment — the Stack navigator's default background\npeeked through at the top safe-area / status-bar region, making it look\ndisconnected (割裂) from the terminal content below.\n\nSame for agent-console + agent/[conversationId] which now inherit the\nweb canvas dark color (#0b0d0f).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: iOS status-bar color mismatch — route-level bg matches terminal/…",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-07T18:28:59Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "af23b9d12039f8c66d3ac63ec239c46b99a44773",
          "body": "RN WebSocket doesn't reliably reply to server ping control frames, so\nthe liveness check (added in 3edf40e) was mistakenly terminating healthy\nnative sockets every ~40s. terminal.input keystrokes land when socket is\nclosed → queued in pendingOutbound → flushed only on reconnect onopen,\nmatching the \n[…]\nent half-open sockets are\nterminated, preserving the security fix's intent.\n\nBump: gateway 0.4.27→0.4.28, cli 0.5.9→0.5.10 (cli embeds gateway)\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: gateway ping/pong terminates native WS that doesn't auto-pong",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-07T17:42:45Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "21f78f338a11a180863967b85dbf8bd5eca3003e",
          "body": "…way cleanup\n\n- Move the embedded web console to a full-screen route (app/agent-console)\n  OUTSIDE the (tabs) group so the bottom tab bar is hidden while it's open;\n  the Agent tab is now a pure host picker that pushes into it (no auto-jump,\n  which would trap back navigation).\n- AgentWebScreen nati\n[…]\nmoveServerWithHistory), since it's persisted as a normal server on\n  connect and would otherwise linger after the /sessions/mine listing is gone.\n\nCo-Authored-By: Claude Opus 4 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: agent console full-screen route, web-canvas frame, sign-out gate…",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-07T06:06:48Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "63f6e16294a20703fad4aa28713e49a5e7712854",
          "body": "Bundles the web SPA into the CLI's embedded gateway so LAN / self-hosted users\nget the in-app console; protocol unchanged (not republished). New version (not\n0.4.26) because the v0.4.26 Docker image predates the embedded.ts change.\n\nCo-Authored-By: Claude Opus 4 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: gateway v0.4.27 / cli v0.5.9 (cross-gateway in-app web console)",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-07T05:27:25Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d21d240772030444cb06e4aa952f509e805d3fc6",
          "body": "A single WebView is same-origin to one gateway, but a user's hosts can live on\ndifferent gateways at once. Fixes the resulting gaps:\n\n- gateway/embedded: the embedded gateway (used by `linkshell` on LAN/self-host)\n  now serves the bundled web SPA (serveWebAsset before tunnel-cookie fallback,\n  serve\n[…]\nway; back\n  returns to the picker. Auto-skips into the console when a host is already\n  active. Fixes \"已连接主机却显示没有可用主机\" for Pro/unconnected hosts.\n\nCo-Authored-By: Claude Opus 4 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: in-app web console works across LAN / self-hosted / Pro gateways",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-07T05:11:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "191161613e0a24d0648fe2600fb37bdf2f2fdb4d",
          "body": "…list)\n\n- (tabs)/agent: render AgentWebScreen driven by the active/connected host\n  session instead of the native AgentWorkspaceScreen list; conversation\n  switching/creation now happens in the web console's own drawer. Web \"back\"\n  (requestClose) switches to the Home tab. Native \"connect a host\" fa\n[…]\nfect now keys on stable url/id strings.\n\nAgentWorkspaceScreen is now orphaned (kept for rollback). Mobile-only — no\ngateway image rebuild needed.\n\nCo-Authored-By: Claude Opus 4 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: Agent tab opens the web console directly in WebView (no native …",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-07T04:17:28Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "295e109293db9f6ecb66adc6f4b94d37636c7a82",
          "body": "Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: gateway v0.4.26 (embed-aware web console)",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-06T18:52:19Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "896b470c3e8e0b45d6b30e9fdbcfc46391e635ab",
          "body": "…ity)\n\n- features/agent-web/AgentWebScreen: full-screen WebView host loading the\n  gateway-served web console; injects Supabase session (plan reshaped to web's\n  top-level shape) + device token + theme into localStorage before load, so the\n  embedded app boots genuinely logged-in; theme/back/error b\n[…]\nlineById Map (same-pass streaming commits) +\n  history pagination with 12s timeout\n- useComposerDictation: extracted press-to-talk dictation hook\n\nCo-Authored-By: Claude Opus 4 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: in-app agent console via WebView embedding the web app (1:1 par…",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-06T18:50:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6b9caf9d91ad9c27474b851dcff3a9a04e53a8a6",
          "body": "- embed.ts: headless bootstrap (gateway/token/theme via query+localStorage),\n  isEmbedded() reads a persisted flag so reloads stay embed-aware\n- main.tsx: boot straight to console when embedded, register\n  window.__linkshellSetTheme for native theme sync, back -> requestClose\n- AgentConsolePage: hid\n[…]\nTimelineItemView: render context_compaction / review kinds (were empty)\n- index.css: prefers-reduced-motion reset + reveal hover actions on touch\n\nCo-Authored-By: Claude Opus 4 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: embed-aware web console for in-app WebView + render/a11y polish",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-06T18:50:21Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "900af62198102eeebe3cada577e6b3ca6a2b6430",
          "body": null,
          "is_bot": false,
          "headline": "fix: healthz",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-02T16:57:48Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "669a296bb38555c6907bf66bf29900ed1ef415bf",
          "body": "- tokens: add ownsFresh() that reloads token records from persistent\n  store on a local cache miss (fixes token binding across\n  multi-replica gateway deployments where the bind happened on a\n  different instance)\n- tunnel: use ownsFresh() instead of owns() for both HTTP and WS\n  tunnel auth paths\n-\n[…]\n_check_failed, host_not_connected\n- tunnel: WS close reasons include the same diagnostics\n- test: add tokens.test.ts for TokenManager ownsFresh\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: token refresh from store, tunnel auth diagnostics",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-01T19:11:37Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a854db31ae65c12c00a9d8e845c12a56a5161edf",
          "body": "- tunnel: add stripGatewayCookies() to filter lsh_tunnel/lsh_token\n  from forwarded requests so previewed apps never see gateway auth\n- tunnel: add forwardedUrl() to strip token/auth_token query params\n  from forwarded URLs (avoids credential leak + cache key poisoning)\n- tunnel: add rewriteTunnelLo\n[…]\n the URL query params\n- web/PortPreview: relax authReady guard for device-token paths\n  (only wait for auth when initialAuthToken was provided)\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: tunnel cookie fallback guard, merge upstream set-cookie",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-01T19:02:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2fc7bf790445f355f2ca56fe77f6ab0011c5f8fb",
          "body": "- tunnel: add bindExplicitDeviceToken() — after JWT ownership is\n  proven, bind the browser's explicit device token from the tunnel URL\n  query param to the session so it appears in the tunnel cookie for\n  subsequent subresource requests\n- tunnel: apply token binding to both HTTP (handleTunnelRequest) and\n  WS (handleTunnelWsUpgrade) paths\n- test: add tunnel-auth-binding.test.ts covering device token bind\n  after JWT auth\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: bind device token after JWT auth, tunnel cookie persistence",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-01T18:47:55Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "441f32dcdf52732e1cea896af5ae205ca8674d92",
          "body": "- tunnel: add cache-control:no-store+cdn-cache-control+surrogate-control\n  +vary headers to error responses and tunnel proxy responses to\n  prevent CDN/browser caching of preview content\n- web/device-token: add ensureDeviceToken() that auto-generates a\n  device token when none exists (fixes missing \n[…]\n browser sessions that need tunnel auth)\n- web/PortPreview + bridge-client: switch from getDeviceToken (may\n  return null) to ensureDeviceToken\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: tunnel cache headers, web ensureDeviceToken",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-01T18:31:25Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "bd00898602b8481fdb77bed8e0458744c91e9374",
          "body": "- tunnel: add tokenFromTunnelCookie() to extract auth from the\n  lsh_tunnel cookie matching sessionId+port, used as fallback in\n  handleTunnelRequest when neither query param token nor JWT present\n- tunnel: handleTunnelWsUpgrade accepts optional preAuthToken, wired\n  from the lsh_tunnel cookie on the upgrade path\n- embedded + index: pass cookie token through WS upgrade for HMR\n  subresource WebSocket connections inside previewed apps\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: embedded tunnel cookie fallback guard, merge upstream set-cookie",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-01T18:13:34Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "6e020f91aec0dfa235e1fdb1b4fe0f4693932ae0",
          "body": "- static-web: clear lsh_tunnel cookie (Max-Age=0) on index.html\n  responses so stale tunnel cookies don't leak into the app shell\n- tunnel: allow all non-document subresource dests through cookie\n  fallback since the app shell now clears the cookie proactively\n- test: update tunnel fallback test for new subresource behavior\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: cookie hijack root domain, session expiry cleanup",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-01T18:01:10Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "4b76f36ac616747799fec0666a1ad79e1866726d",
          "body": "- embedded: apply shouldUseTunnelCookieFallback for HTTP + WS tunnel\n  cookie routing (was missing in the embedded gateway path)\n- tunnel: tighten cookie fallback to only allow requests with tunnel\n  referer, missing Sec-Fetch-Dest, or iframe dest (no longer allows\n  arbitrary style/script subresour\n[…]\ntunnel cookie\n  alongside upstream Set-Cookie headers instead of overwriting them\n- tunnel: set Max-Age=600 on tunnel cookie so it auto-expires\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: embedded tunnel cookie fallback guard, merge upstream set-cookie",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-01T17:49:03Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b4be0c9b5a392b4d37610a22d9675a8710ecdb93",
          "body": "- web/PortPreview: accept initialAuthToken from parent so tunnel URL is\n  available immediately, eliminating the 401 flash on first load\n- web/AgentConsolePage: pass session.accessToken as initialAuthToken;\n  move terminal bottom panel below composer so input stays accessible\n- web/TerminalPanel: te\n[…]\nrminalList sends explicit terminals array\n- gateway/tunnel: Set-Cookie Secure flag only on encrypted connections\n  (fixes plain-HTTP local dev)\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: preview 401 auth race, terminal theme, tunnel cookie secure",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-01T17:19:39Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a0bbf2dfec629aac538549760ad1d1b1bc31e981",
          "body": null,
          "is_bot": false,
          "headline": "feat: luma",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-01T17:17:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ff855f7a203e027b66d49dde1d80a658d87aa6ce",
          "body": null,
          "is_bot": false,
          "headline": "fix: 401",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-01T17:06:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "96a90dc59ea2c439ac8fe8ba9b46c5e08e96b5b2",
          "body": "…condition\n\n- gateway/tunnel: add shouldUseTunnelCookieFallback() to prevent stale\n  tunnel cookies from hijacking normal top-level web visits\n- gateway/static-web: refactor serveWebAsset() so tunnel cookie check\n  doesn't steal concrete web app assets like /assets/*.js\n- gateway/index: tunnel fallb\n[…]\nh on first load)\n- Add tunnel-fallback.test.ts covering cookie parse, top-level document\n  guard, iframe fallback, and tunnel referer allowlist\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: tunnel cookie fallback not hijack web assets, preview auth race …",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-01T16:12:41Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "804806e0a8ec2b5802e3a3bb99b1683d9b61a8c3",
          "body": null,
          "is_bot": false,
          "headline": "feat: upgrade mobile",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-01T16:02:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8a7b47e0c56de904876a8e59cb272ba2951e2bc8",
          "body": null,
          "is_bot": false,
          "headline": "perf: depoly",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-01T14:31:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ff379eccf4ba03bdde3d67e0e4b794482bd01be5",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: gateway 0.4.16, root 0.5.17",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-01T14:14:14Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "5c3762b5b59e4e711fda6d88cc587942d1879a72",
          "body": "…ng state\n\n- gateway: fix cookie fallback regression — move back before serveWeb but\n  guard / and /assets/* so tunnel sub-resources still route correctly while\n  the LinkShell root is never hijacked.\n- web: replace fixed bottom-panel annotate UI with a Codex-style floating\n  card positioned near th\n[…]\nto agent.\n- web: show loading spinner when entering a conversation whose history is\n  still loading, even if lastMessagePreview is not yet set.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: cookie regression, annotate floating card UX, conversation loadi…",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-01T14:14:05Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1c638856515c3026199a9a20f4ea1bc147d2433d",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: gateway 0.4.15, cli 0.5.8, root 0.5.16",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-01T13:55:55Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "06cfb34abeefe6c03dd9442bda41f37b0308b93f",
          "body": "…e model discovery\n\n- gateway: move tunnel cookie fallback after serveWeb so lsh_tunnel cookie\n  never hijacks the LinkShell root domain or SPA routes on subsequent visits.\n- web: refreshSession clears session + fires onAuthExpired on definitive 4xx;\n  App validates stored session at startup via get\n[…]\ntedModels() for dynamic\n  model discovery per API key; both clients respect availableModels from\n  settings.json. Added missing opus[1m] alias.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: cookie hijack root domain, session expiry cleanup, dynamic claud…",
          "author_name": "Nickname4th",
          "author_login": "LiuTianjie",
          "committed_at": "2026-06-01T13:55:35Z",
          "body_truncated": true,
          "is_coding_agent": true
        }
      ],
      "releases_count": 34,
      "commits_last_year": 358,
      "latest_release_at": "2026-07-17T05:09:25Z",
      "latest_release_tag": "cli-v0.5.34",
      "releases_from_tags": false,
      "days_since_last_push": 4,
      "active_weeks_last_year": 14,
      "days_since_latest_release": 4,
      "mean_days_between_releases": 1.8
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": false,
      "health_percentage": 42,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "linkshell-cli",
          "exists": true,
          "license": "MIT",
          "keywords": [
            "terminal",
            "remote",
            "claude",
            "codex",
            "pty",
            "bridge",
            "mobile",
            "websocket"
          ],
          "ecosystem": "npm",
          "matches_repo": true,
          "registry_url": "https://www.npmjs.com/package/linkshell-cli",
          "is_deprecated": false,
          "latest_version": "0.5.34",
          "repository_url": "https://github.com/LiuTianjie/LinkShell",
          "versions_count": 209,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": 1,
          "monthly_downloads": 4097,
          "first_published_at": "2026-04-01T05:22:41.498000Z",
          "latest_published_at": "2026-07-17T05:07:36.848000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 4
        },
        {
          "name": "@linkshell/gateway",
          "exists": true,
          "license": null,
          "keywords": [],
          "ecosystem": "npm",
          "matches_repo": null,
          "registry_url": "https://www.npmjs.com/package/@linkshell/gateway",
          "is_deprecated": false,
          "latest_version": "0.4.49",
          "repository_url": null,
          "versions_count": 115,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": 1,
          "monthly_downloads": 3090,
          "first_published_at": "2026-04-01T05:22:38.169000Z",
          "latest_published_at": "2026-07-17T05:07:27.855000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 4
        },
        {
          "name": "@linkshell/protocol",
          "exists": true,
          "license": null,
          "keywords": [],
          "ecosystem": "npm",
          "matches_repo": null,
          "registry_url": "https://www.npmjs.com/package/@linkshell/protocol",
          "is_deprecated": false,
          "latest_version": "0.4.8",
          "repository_url": null,
          "versions_count": 61,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": 1,
          "monthly_downloads": 1279,
          "first_published_at": "2026-04-01T05:22:20.389000Z",
          "latest_published_at": "2026-07-01T07:23:03.216000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 20
        }
      ]
    },
    "popularity": {
      "forks": 0,
      "stars": 34,
      "watchers": 0,
      "fork_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_forks": 0
      },
      "star_history": {
        "days": [
          {
            "date": "2026-04-03",
            "count": 1
          },
          {
            "date": "2026-04-10",
            "count": 4
          },
          {
            "date": "2026-04-11",
            "count": 3
          },
          {
            "date": "2026-04-12",
            "count": 3
          },
          {
            "date": "2026-04-13",
            "count": 3
          },
          {
            "date": "2026-04-14",
            "count": 1
          },
          {
            "date": "2026-04-15",
            "count": 3
          },
          {
            "date": "2026-04-16",
            "count": 3
          },
          {
            "date": "2026-04-20",
            "count": 1
          },
          {
            "date": "2026-04-27",
            "count": 1
          },
          {
            "date": "2026-05-03",
            "count": 1
          },
          {
            "date": "2026-05-04",
            "count": 1
          },
          {
            "date": "2026-05-12",
            "count": 2
          },
          {
            "date": "2026-06-02",
            "count": 1
          },
          {
            "date": "2026-06-07",
            "count": 1
          },
          {
            "date": "2026-06-09",
            "count": 1
          },
          {
            "date": "2026-06-18",
            "count": 1
          },
          {
            "date": "2026-06-19",
            "count": 1
          },
          {
            "date": "2026-06-25",
            "count": 1
          },
          {
            "date": "2026-07-12",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 34,
        "total_stars": 34
      },
      "open_issues_and_prs": 1
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": true,
      "has_mcp_signal": false,
      "bootstrap_files": [],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [
        "apps/mobile/tsconfig.json",
        "apps/web-dashboard/tsconfig.json",
        "packages/cli/tsconfig.json",
        "packages/gateway/tsconfig.json",
        "packages/shared-protocol/tsconfig.json"
      ],
      "toolchain_manifests": [],
      "largest_source_bytes": 203463,
      "source_files_sampled": 168,
      "oversized_source_files": 7,
      "agent_instruction_files": [
        "AGENTS.md",
        "CLAUDE.md"
      ],
      "agent_instruction_max_bytes": 5480
    },
    "dependencies": {
      "manifests": [
        "package.json"
      ],
      "advisories": {
        "error": null,
        "scope": null,
        "source": null,
        "findings": [],
        "collected": false,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 0,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "npm"
      ],
      "dependencies": [
        {
          "name": "@expo/vector-icons",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "^15.1.1"
        },
        {
          "name": "@legendapp/list",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "^2.0.19"
        },
        {
          "name": "@linkshell/protocol",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "workspace:*"
        },
        {
          "name": "@react-native-async-storage/async-storage",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "^2.1.2"
        },
        {
          "name": "@react-native-menu/menu",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "^2.0.0"
        },
        {
          "name": "@react-navigation/bottom-tabs",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "^7.3.10"
        },
        {
          "name": "@react-navigation/native",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "^7.1.6"
        },
        {
          "name": "@xterm/addon-fit",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "0.12.0-beta.197"
        },
        {
          "name": "@xterm/addon-web-links",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "0.13.0-beta.197"
        },
        {
          "name": "@xterm/xterm",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "6.1.0-beta.197"
        },
        {
          "name": "expo",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "~54.0.0"
        },
        {
          "name": "expo-blur",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "~15.0.8"
        },
        {
          "name": "expo-build-properties",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "^55.0.13"
        },
        {
          "name": "expo-camera",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "~17.0.10"
        },
        {
          "name": "expo-dev-client",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "~6.0.20"
        },
        {
          "name": "expo-file-system",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "~19.0.21"
        },
        {
          "name": "expo-glass-effect",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "~0.1.9"
        },
        {
          "name": "expo-haptics",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "~15.0.8"
        },
        {
          "name": "expo-image",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "~3.0.11"
        },
        {
          "name": "expo-image-picker",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "^55.0.16"
        },
        {
          "name": "expo-linear-gradient",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "^55.0.13"
        },
        {
          "name": "expo-linking",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "~7.0.1"
        },
        {
          "name": "expo-router",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "~6.0.23"
        },
        {
          "name": "expo-secure-store",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "~15.0.8"
        },
        {
          "name": "expo-speech-recognition",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "^3.1.2"
        },
        {
          "name": "expo-status-bar",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "~3.0.9"
        },
        {
          "name": "expo-symbols",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "^55.0.5"
        },
        {
          "name": "metro-runtime",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "^0.84.2"
        },
        {
          "name": "react",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "19.1.0"
        },
        {
          "name": "react-native",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "0.81.5"
        },
        {
          "name": "react-native-gesture-handler",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "^2.30.1"
        },
        {
          "name": "react-native-markdown-display",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "7.0.2"
        },
        {
          "name": "react-native-reanimated",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "^4.3.0"
        },
        {
          "name": "react-native-safe-area-context",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "~5.6.2"
        },
        {
          "name": "react-native-screens",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "~4.16.0"
        },
        {
          "name": "react-native-webview",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "^13.15.0"
        },
        {
          "name": "react-native-worklets",
          "manifest": "apps/mobile/package.json",
          "ecosystem": "npm",
          "version_constraint": "^0.8.0"
        },
        {
          "name": "@linkshell/protocol",
          "manifest": "apps/web-dashboard/package.json",
          "ecosystem": "npm",
          "version_constraint": "workspace:*"
        },
        {
          "name": "@xterm/addon-fit",
          "manifest": "apps/web-dashboard/package.json",
          "ecosystem": "npm",
          "version_constraint": "^0.10.0"
        },
        {
          "name": "@xterm/xterm",
          "manifest": "apps/web-dashboard/package.json",
          "ecosystem": "npm",
          "version_constraint": "^5.5.0"
        },
        {
          "name": "react",
          "manifest": "apps/web-dashboard/package.json",
          "ecosystem": "npm",
          "version_constraint": "19.1.0"
        },
        {
          "name": "react-dom",
          "manifest": "apps/web-dashboard/package.json",
          "ecosystem": "npm",
          "version_constraint": "19.1.0"
        },
        {
          "name": "react-markdown",
          "manifest": "apps/web-dashboard/package.json",
          "ecosystem": "npm",
          "version_constraint": "^9.0.1"
        },
        {
          "name": "react-router-dom",
          "manifest": "apps/web-dashboard/package.json",
          "ecosystem": "npm",
          "version_constraint": "^7.5.0"
        },
        {
          "name": "rehype-highlight",
          "manifest": "apps/web-dashboard/package.json",
          "ecosystem": "npm",
          "version_constraint": "^7.0.2"
        },
        {
          "name": "remark-gfm",
          "manifest": "apps/web-dashboard/package.json",
          "ecosystem": "npm",
          "version_constraint": "^4.0.0"
        },
        {
          "name": "zod",
          "manifest": "apps/web-dashboard/package.json",
          "ecosystem": "npm",
          "version_constraint": "^3.24.3"
        },
        {
          "name": "@linkshell/gateway",
          "manifest": "packages/cli/package.json",
          "ecosystem": "npm",
          "version_constraint": "workspace:*"
        },
        {
          "name": "@linkshell/protocol",
          "manifest": "packages/cli/package.json",
          "ecosystem": "npm",
          "version_constraint": "workspace:*"
        },
        {
          "name": "commander",
          "manifest": "packages/cli/package.json",
          "ecosystem": "npm",
          "version_constraint": "^13.1.0"
        },
        {
          "name": "node-pty",
          "manifest": "packages/cli/package.json",
          "ecosystem": "npm",
          "version_constraint": "^1.0.0"
        },
        {
          "name": "qrcode-terminal",
          "manifest": "packages/cli/package.json",
          "ecosystem": "npm",
          "version_constraint": "^0.12.0"
        },
        {
          "name": "ws",
          "manifest": "packages/cli/package.json",
          "ecosystem": "npm",
          "version_constraint": "^8.18.1"
        },
        {
          "name": "zod",
          "manifest": "packages/cli/package.json",
          "ecosystem": "npm",
          "version_constraint": "^3.24.3"
        },
        {
          "name": "@linkshell/protocol",
          "manifest": "packages/gateway/package.json",
          "ecosystem": "npm",
          "version_constraint": "workspace:*"
        },
        {
          "name": "zod",
          "manifest": "packages/gateway/package.json",
          "ecosystem": "npm",
          "version_constraint": "^3.24.3"
        },
        {
          "name": "ws",
          "manifest": "packages/gateway/package.json",
          "ecosystem": "npm",
          "version_constraint": "^8.18.1"
        },
        {
          "name": "zod",
          "manifest": "packages/shared-protocol/package.json",
          "ecosystem": "npm",
          "version_constraint": "^3.24.3"
        }
      ],
      "all_dependencies": {
        "error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
        "source": null,
        "packages": [],
        "collected": false,
        "truncated": false,
        "total_count": null,
        "direct_count": null,
        "indirect_count": null
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 2,
        "open_issues": 1,
        "closed_ratio": 0.667,
        "closed_issues": 2,
        "closed_unmerged_prs": 0
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "LiuTianjie",
          "commits": 358,
          "avatar_url": "https://avatars.githubusercontent.com/u/38846322?v=4"
        }
      ],
      "contributors_sampled": 1,
      "top_contributor_share": 1
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "android-build.yml",
        "docker-publish.yml",
        "ios-build.yml",
        "pages.yml",
        "test.yml"
      ],
      "has_docs_dir": true,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": false,
      "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": null,
            "reason": "no pull request found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
          },
          {
            "name": "CII-Best-Practices",
            "score": 0,
            "reason": "no effort to earn an OpenSSF best practices badge detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
          },
          {
            "name": "Code-Review",
            "score": 0,
            "reason": "Found 0/30 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 0,
            "reason": "project has 0 contributing companies or organizations -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": 10,
            "reason": "no dangerous workflow patterns detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 0,
            "reason": "no update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 10,
            "reason": "license file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 10,
            "reason": "30 commit(s) and 2 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": 10,
            "reason": "packaging workflow detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": 0,
            "reason": "dependency not pinned by hash detected -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "no SAST tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 0,
            "reason": "security policy file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": null,
            "reason": "no releases found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": 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": "61 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "522702dd0221a3428d5c5721dcc93afb9e7d35a7",
        "ran_at": "2026-07-21T23:00:48Z",
        "aggregate_score": 3.7,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-07-17T05:09:15Z",
      "oldest_open_prs": [],
      "last_merged_pr_at": "2026-04-14T10:03:59Z",
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": [
        {
          "number": 4,
          "created_at": "2026-04-30T21:43:40Z",
          "last_comment_at": "2026-05-03T03:49:34Z",
          "last_comment_author": "LiuTianjie"
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/LiuTianjie/LinkShell",
    "host": "github.com",
    "name": "LinkShell",
    "owner": "LiuTianjie"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 60,
      "inputs": {
        "security": 37,
        "vitality": 84,
        "community": 44,
        "governance": 54,
        "engineering": 76
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 84,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "good",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 74,
            "inputs": {
              "commits_last_year": 358,
              "human_commit_share": 1,
              "days_since_last_push": 4,
              "active_weeks_last_year": 14
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 4 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 4
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "14/52 weeks with commits",
                "points": 9.7,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 14
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "358 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 358
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "30 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 10",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "excellent",
            "name": "Release discipline",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "releases_count": 34,
              "latest_release_tag": "cli-v0.5.34",
              "releases_from_tags": false,
              "days_since_latest_release": 4,
              "mean_days_between_releases": 1.8
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "34 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 34
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 4 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 4
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~1.8 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 1.8
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "unverified",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": "repository_too_young",
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": null,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "maintenance record not established from the collected data",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_unverified",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "at_risk",
        "name": "Community & Adoption",
        "value": 44,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 25,
            "inputs": {
              "forks": 0,
              "stars": 34,
              "watchers": 0,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "below_threshold"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "34 stars",
                "points": 24.6,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 34
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "0 forks",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "0 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "moderate",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "has_contributing": false,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "has_pull_request_template": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "recognized license (MIT)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "MIT"
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 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": "moderate",
            "name": "Ecosystem adoption (downloads)",
            "note": "Excluded from scoring (no data or not applicable): Registry dependents. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "registry_dependents"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 66,
            "inputs": {
              "packages": [
                "linkshell-cli",
                "@linkshell/gateway",
                "@linkshell/protocol"
              ],
              "dependents": null,
              "ecosystems": "npm",
              "total_downloads": null,
              "monthly_downloads": 8466
            },
            "components": [
              {
                "key": "monthly_downloads",
                "name": "Monthly downloads",
                "detail": "8,466 downloads/month across npm",
                "points": 52.4,
                "status": "partial",
                "details": [
                  {
                    "code": "downloads_monthly",
                    "params": {
                      "count": 8466,
                      "ecosystems": "npm"
                    }
                  }
                ],
                "max_points": 80
              },
              {
                "key": "registry_dependents",
                "name": "Registry dependents",
                "detail": "not reported by this ecosystem",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_reported_by_this_ecosystem",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "moderate",
        "name": "Sustainability & Governance",
        "value": 54,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 10,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 1,
              "top_contributor_share": 1
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "1 contributor(s) cover half of all commits",
                "points": 9,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 100% of commits",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 100
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "1 contributors",
                "points": 1.4,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 0 contributing companies or organizations -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "moderate",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 69,
            "inputs": {
              "merged_prs": 2,
              "open_issues": 1,
              "closed_issues": 2,
              "issue_closed_ratio": 0.667,
              "closed_unmerged_prs": 0
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "67% of issues closed",
                "points": 31.2,
                "status": "partial",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 67
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "2/2 decided PRs merged",
                "points": 38.2,
                "status": "met",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 2,
                      "decided": 2
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "moderate",
            "name": "Ownership & stewardship",
            "note": "Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "verified_domain"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 53,
            "inputs": {
              "followers": 9,
              "owner_type": "User",
              "is_verified": null,
              "owner_login": "LiuTianjie",
              "public_repos": 58,
              "account_age_days": 3004
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "personal (user) account",
                "points": 10,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_personal",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": "not applicable to user accounts",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_applicable_to_user_accounts",
                    "params": {}
                  }
                ],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "9 followers of LiuTianjie",
                "points": 7.2,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 9,
                      "login": "LiuTianjie"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "58 public repos, account ~8 yr old",
                "points": 24.9,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 58
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 8
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "linkshell-cli",
                "@linkshell/gateway",
                "@linkshell/protocol"
              ],
              "ecosystems": "npm",
              "any_deprecated": false,
              "min_days_since_publish": 4
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "3 package(s) on npm",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 3,
                      "ecosystems": "npm"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 4 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 4
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "209 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 209
                    }
                  }
                ],
                "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": 76,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "moderate",
            "name": "Engineering practices",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: CI-Tests. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_ci_tests"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 60,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "5 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 5
                    }
                  }
                ],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 24,
                "status": "met",
                "details": [],
                "max_points": 24
              },
              {
                "key": "linter_config",
                "name": "Linter config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 9.6
              },
              {
                "key": "editorconfig",
                "name": ".editorconfig",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "no pull request found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "excellent",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "topics": [
                "claude-code",
                "codex",
                "remote-control",
                "shell"
              ],
              "has_wiki": true,
              "homepage": "https://liutianjie.github.io/LinkShell/",
              "has_readme": true,
              "has_docs_dir": true,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 25,
                "status": "met",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": "https://liutianjie.github.io/LinkShell/",
                "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": "4 topics",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "topics_count",
                    "params": {
                      "count": 4
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "at_risk",
        "name": "Security",
        "value": 37,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "at_risk",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): CI-Tests, Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "ci_tests",
                    "signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 37,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 16,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 2,
              "scorecard_aggregate": 3.7
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection 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": "no pull request found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 2.5
              },
              {
                "key": "cii_best_practices",
                "name": "CII-Best-Practices",
                "detail": "no effort to earn an OpenSSF best practices badge detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "code_review",
                "name": "Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 0 contributing companies or organizations -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no dangerous workflow patterns detected",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "no update tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file detected",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "30 commit(s) and 2 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 detected",
                "points": 5,
                "status": "met",
                "details": [],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "no SAST tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "detected GitHub workflow tokens with excessive permissions",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "61 existing vulnerabilities detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "excellent",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "review_only_matches": 0,
              "assessed_self_published_locations": 2
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "good",
        "name": "AI Readiness",
        "value": 72,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "excellent",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 85,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 1,
              "agent_instruction_files": [
                "AGENTS.md",
                "CLAUDE.md"
              ],
              "agent_instruction_max_bytes": 5480
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "AGENTS.md, CLAUDE.md",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "AGENTS.md, CLAUDE.md"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "100 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 100,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "moderate",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 53,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "pnpm-lock.yaml"
              ],
              "has_dockerfile": true,
              "typed_language": true,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [
                "apps/mobile/tsconfig.json",
                "apps/web-dashboard/tsconfig.json",
                "packages/cli/tsconfig.json",
                "packages/gateway/tsconfig.json",
                "packages/shared-protocol/tsconfig.json"
              ],
              "agent_commit_share": 0.44,
              "toolchain_manifests": [],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": "apps/mobile/tsconfig.json, apps/web-dashboard/tsconfig.json, packages/cli/tsconfig.json, packages/gateway/tsconfig.json, packages/shared-protocol/tsconfig.json",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "apps/mobile/tsconfig.json, apps/web-dashboard/tsconfig.json, packages/cli/tsconfig.json, packages/gateway/tsconfig.json, packages/shared-protocol/tsconfig.json"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": "Dockerfile, lockfile",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "Dockerfile, lockfile"
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "44 of the last 100 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 44,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "no automated dependency updates observed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_dependency_automation",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "excellent",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 98,
            "inputs": {
              "primary_language": "TypeScript",
              "largest_source_bytes": 203463,
              "source_files_sampled": 168,
              "oversized_source_files": 7
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "TypeScript (statically typed)",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "TypeScript"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "7/168 source files over 60KB",
                "points": 52.7,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 168,
                      "oversized": 7
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
      }
    ],
    "metrics_version": "1.13.0"
  },
  "warnings": [
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
    "deps.dev does not index npm:linkshell-cli@0.5.34; advisories assessed against the repository dependency graph instead"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-21T23:00:55.029198Z",
  "schema_version": "0.25.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/l/LiuTianjie/LinkShell.svg",
  "full_name": "LiuTianjie/LinkShell",
  "license_state": "standard",
  "license_spdx": "MIT"
}

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 v1.13.0, esquema v0.25.0 — metodología completa · wiki de métricas.

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