JSON-Rohbericht maschinenlesbar
{
"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"
}