JSON-Rohbericht maschinenlesbar
{
"data": {
"repo": {
"topics": [],
"is_fork": false,
"size_kb": 28824,
"has_wiki": true,
"homepage": null,
"languages": {
"Go": 1696343,
"CSS": 146918,
"HTML": 3230,
"Java": 14633,
"Shell": 15932,
"Kotlin": 4305,
"Python": 8716,
"Makefile": 2016,
"JavaScript": 46401,
"TypeScript": 370255
},
"pushed_at": "2026-07-13T05:17:23Z",
"created_at": "2026-05-19T12:44:19Z",
"owner_type": "User",
"updated_at": "2026-07-13T05:17:28Z",
"description": "Pi Agent Go 实现 - 纯服务端 Agent 框架",
"is_archived": false,
"is_disabled": false,
"license_spdx": null,
"default_branch": "main",
"license_spdx_raw": null,
"primary_language": "Go",
"significant_languages": [
"Go",
"TypeScript"
]
},
"owner": {
"blog": null,
"name": "WJ Huang",
"type": "User",
"login": "hwj123hwj",
"company": null,
"location": "China",
"followers": 2,
"avatar_url": "https://avatars.githubusercontent.com/u/130386673?v=4",
"created_at": "2023-04-10T15:53:21Z",
"is_verified": null,
"public_repos": 18,
"account_age_days": 1204
},
"license": {
"state": "absent",
"spdx_id": null,
"raw_spdx": null,
"file_present": false,
"scorecard_found": false,
"profile_has_license": false
},
"activity": {
"releases": [
{
"tag": "v0.10.12",
"kind": "patch",
"published_at": "2026-07-13T05:19:04Z"
},
{
"tag": "v0.10.11",
"kind": "patch",
"published_at": "2026-07-12T11:15:25Z"
},
{
"tag": "v0.10.10",
"kind": "patch",
"published_at": "2026-07-12T11:02:41Z"
},
{
"tag": "v0.10.9",
"kind": "patch",
"published_at": "2026-07-12T10:56:32Z"
},
{
"tag": "v0.10.8",
"kind": "patch",
"published_at": "2026-07-12T10:46:47Z"
},
{
"tag": "v0.10.7",
"kind": "patch",
"published_at": "2026-07-12T10:29:21Z"
},
{
"tag": "v0.10.6",
"kind": "patch",
"published_at": "2026-07-12T10:04:34Z"
},
{
"tag": "v0.10.5",
"kind": "patch",
"published_at": "2026-07-12T07:43:29Z"
},
{
"tag": "v0.10.4",
"kind": "patch",
"published_at": "2026-07-12T04:51:22Z"
},
{
"tag": "v0.10.3",
"kind": "patch",
"published_at": "2026-07-12T03:20:17Z"
},
{
"tag": "v0.10.2",
"kind": "patch",
"published_at": "2026-07-11T17:32:57Z"
},
{
"tag": "v0.10.1",
"kind": "patch",
"published_at": "2026-07-11T17:05:02Z"
},
{
"tag": "v0.10.0",
"kind": "minor",
"published_at": "2026-07-11T16:53:37Z"
},
{
"tag": "v0.9.3",
"kind": "patch",
"published_at": "2026-06-30T09:08:17Z"
},
{
"tag": "v0.9.2",
"kind": "patch",
"published_at": "2026-06-30T05:02:10Z"
},
{
"tag": "v0.9.1",
"kind": "patch",
"published_at": "2026-06-30T01:09:45Z"
},
{
"tag": "v0.9.0",
"kind": "minor",
"published_at": "2026-06-29T18:20:21Z"
},
{
"tag": "v0.8.7",
"kind": "patch",
"published_at": "2026-06-28T11:25:55Z"
},
{
"tag": "v0.8.6",
"kind": "patch",
"published_at": "2026-06-28T09:29:09Z"
},
{
"tag": "v0.8.5",
"kind": "patch",
"published_at": "2026-06-28T08:56:58Z"
},
{
"tag": "v0.8.4",
"kind": "patch",
"published_at": "2026-06-28T04:38:21Z"
},
{
"tag": "v0.8.3",
"kind": "patch",
"published_at": "2026-06-28T04:13:29Z"
},
{
"tag": "v0.8.2",
"kind": "patch",
"published_at": "2026-06-28T04:07:05Z"
},
{
"tag": "v0.8.1",
"kind": "patch",
"published_at": "2026-06-28T04:00:12Z"
},
{
"tag": "v0.8.0",
"kind": "minor",
"published_at": "2026-06-28T03:42:42Z"
},
{
"tag": "v0.7.0",
"kind": "minor",
"published_at": "2026-06-27T11:07:26Z"
},
{
"tag": "v0.6.0",
"kind": "minor",
"published_at": "2026-06-27T08:42:42Z"
},
{
"tag": "v0.5.0",
"kind": "minor",
"published_at": "2026-06-26T13:38:51Z"
},
{
"tag": "v0.4.0",
"kind": "minor",
"published_at": "2026-06-24T10:16:24Z"
},
{
"tag": "v0.3.0",
"kind": "minor",
"published_at": "2026-06-19T11:30:47Z"
},
{
"tag": "v0.2.0",
"kind": "minor",
"published_at": "2026-05-22T13:35:34Z"
},
{
"tag": "v0.1.0",
"kind": "minor",
"published_at": "2026-05-22T12:34:51Z"
}
],
"recent_commits": [
{
"oid": "61ac7466426943fdc1cc4b174e68dd6bd853e3a3",
"body": "The View() method used v.lines[start:end] which shares the underlying\narray. Writing the scroll indicator to visible[last] was corrupting\nv.lines itself, so the indicator text persisted permanently in message\ndata and appeared on every redraw — creating repeated '↑ N new (scroll\ndown to view)' lines throughout the conversation.\n\nFix: copy the slice before modifying.",
"is_bot": false,
"headline": "fix(tui): scroll indicator bleeds into message content",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-13T05:17:21Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c7b17c6a46147f07e252f46ca0df1e830c40e6d6",
"body": "Users need bash to run system commands (free, top, ps, etc).\nWithout it, the agent can't check memory/CPU/disk and may refuse\nclaiming it's in 'planning mode' or lacks tools.",
"is_bot": false,
"headline": "fix(installer): enable bash tool by default in new .env",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-12T11:33:05Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "cb7573240b70d0272379d6d0e315e104c869982b",
"body": "Enable WithMouseCellMotion() so the terminal sends wheel events to the\nTUI instead of scrolling its own scrollback buffer. Without this, users\ncould scroll up past the TUI and see pre-TUI output (install logs, etc).\nAdded MouseMsg handler to scroll the viewport on wheel up/down.",
"is_bot": false,
"headline": "fix(tui): capture mouse wheel events to prevent scrollback leak",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-12T11:13:03Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "6bb39276e5fc97ec45c45e4d5c4576772508afab",
"body": "The banner was printed via PrintBanner(os.Stdout) before p.Run(),\nwhich means it was written to the terminal's normal scrollback\nbuffer BEFORE AltScreen mode was entered. Users could scroll up\nand see the banner mixed with previous command history.\n\nFix: removed the pre-AltScreen banner print entirely. AltScreen\ncreates a clean separate buffer that's discarded on exit, so\nnothing should be printed before p.Run().",
"is_bot": false,
"headline": "fix(tui): banner leaks into terminal scrollback",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-12T11:00:07Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "7a7b9e8f8e4d48fbb721de93af8d252e387346b7",
"body": "Problems fixed (visible in user screenshot):\n\n1. Status icons and checkmarks cut off by border\n - The header content was not properly fitted to the inner width\n - Status text (✓/✗/running) was overflowing past the border edge\n - Fix: calculate innerWidth (width minus border + padding) and\n \n[…]\n● running' instead of static spinner char\n - Completed tools with elapsed time: '✓ 1.2s'\n - Failed tools: '✗'\n\n5. Restore maxInt helper (was removed in refactor, still used by completion_popup.go)",
"is_bot": false,
"headline": "fix(tui): rewrite tool panel layout to fix rendering bugs",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-12T10:53:58Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "8146bd1a7f680eab86cabd1a5987e988203f0312",
"body": "Two bugs fixed:\n\n1. Tool args always showed <nil>\n - Root cause: EventToolExecutionStart was emitted without Args field\n - loop.go: emit now passes call.Args (raw JSON string)\n - TUI: formatArgsForDisplay() handles nil/empty properly\n - tool_panel.go: formatToolArgs() tries to parse JSON and\n[…]\ned with ellipsis\n - JSON args parsed and displayed as readable key: value pairs\n - Strings quoted for clarity\n\nTesting:\n- go build ./... ✓\n- go test ./internal/tui/ ✓\n- go test ./internal/agent/ ✓",
"is_bot": false,
"headline": "fix(tui): tool args showing <nil> + tool panel rendering bugs",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-12T10:44:14Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "9b1df845ba80fbf9a08165a2882540e2afff7d94",
"body": "Root cause: handleSlashCommand passed App=nil, so all commands\nrequiring app-level operations (/new, /switch, /sessions, /models,\n/profile, /profiles) failed with 'app not available'.\n\nFix:\n- TUI now receives and stores the AppContext (slashcmd.AppContext)\n- handleSlashCommand passes m.app instead o\n[…]\nn display, resets token counts\n- ClearScreen result is handled: clears viewport and messages\n- Model info is updated on session switch\n\nAlso added runtime import for type assertion on SessionSwitchTo.",
"is_bot": false,
"headline": "fix(tui): /new, /switch, /clear now work in TUI",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-12T10:25:43Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "23e27fdf3958b61bfbb30d99f6de0fdac6528bd7",
"body": "Third-pass audit fixes:\n\n1. CRITICAL: Confirmation dialog denied on ANY keypress\n - ConfirmationState.HandleKey returned consumed=true for ALL keys\n - This meant pressing any unrecognized key (arrow, space, etc.)\n immediately called resolveConfirmation(false), auto-denying\n - Fix: HandleKe\n[…]\nwport streaming state properly cleared\n\n6. Scroll indicator: '↑ N new' when scrolled up\n - Shows count of new lines that appeared since user scrolled up\n - Helps user know when to scroll back down",
"is_bot": false,
"headline": "fix(tui): confirmation dialog, tool updates, cancel flow, dedup, UX",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-12T10:00:45Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "7edefd15270af045954c531f71dfde664cce4a85",
"body": "Fixes found in second-pass audit:\n\n1. Spinner frozen during text streaming\n - TickMsg handler only animated when spinnerOn=true (tool execution)\n - During text streaming, spinnerOn is false, so spinnerIdx never changed\n - Fix: also animate when m.streaming is true\n\n2. Token tracking pipeline (\n[…]\nores the draft\n - Multi-line drafts are properly preserved\n\n4. Remove dead code in cursorHighlight()\n - Reverse(false).Render(\"\") was a no-op that did nothing\n - Removed the useless reset clause",
"is_bot": false,
"headline": "fix(tui): spinner animation, token tracking, history navigation",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-12T07:41:03Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "c7a71183cf2718d2843935068eef7bf6f1121e14",
"body": "1. Incremental rendering for streaming\n - Viewport now caches rendered message lines separately\n - Only streaming text is re-rendered per token, not the full history\n - Eliminates lag on long conversations\n\n2. Smart auto-scroll\n - Added userScrolled flag to viewport\n - When user scrolls up\n[…]\nxt no longer has static spinner char in message area\n- StreamTextMsg now properly triggers spinner tick\n- Removed dead ToolUpdateMsg case\n- Model selector popup uses styled popup instead of plain text",
"is_bot": false,
"headline": "feat(tui): 5 major UX improvements + bug fixes",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-12T04:48:45Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "d90ef1fd9a033a8d3a44915a2c2473ddb4cd304c",
"body": "README 重写:\n- 从开发者视角切换到用户视角\n- 突出产品核心特色(写代码/记知识/放音乐)\n- 技术细节移到独立文档,README 用链接引用\n- 添加终端快捷键表格\n- 精简安装和使用说明\n\n新增技术文档:\n- docs/ARCHITECTURE.md — 四层架构设计\n- docs/CONFIG.md — 完整配置参考\n- docs/API.md — HTTP API 文档",
"is_bot": false,
"headline": "docs: rewrite README for users, extract tech docs",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-12T03:30:14Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "49ddfcaf016422f6401ad131a565ac2113d1f306",
"body": "Root cause found: \\x1b (ESC byte) was leaking into config values from\ntwo sources:\n1. .env file — arrow keys pressed during install.sh's read prompts\n2. Environment variables — terminal corruption\n\nThe error '\\x1bhttp://localhost:4001/v1/chat/completions' confirms the\nESC byte was embedded in PI_GO_\n[…]\nENAI_API_KEY\n- PI_GO_MODEL / OPENAI_MODEL\n- ANTHROPIC_API_KEY / ANTHROPIC_MODEL\n- PI_GO_API_KEY (server auth)\n- All .env file values via LoadDotEnv\n\nAdded comprehensive unit tests in sanitize_test.go.",
"is_bot": false,
"headline": "fix(config): strip ANSI escape codes from all config values",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-12T03:17:45Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "4cdfeff83ecc0c0be4cd67907d02521d20cc2d25",
"body": "Add sanitizeURL() to both OpenAI and Anthropic providers to strip\ncontrol characters from BaseURL. This is a defense-in-depth fix:\n\n1. sanitizeRunes() in TUI input.go prevents escape codes from entering\n the input buffer (primary fix from previous commit)\n2. sanitizeURL() in providers strips any r\n[…]\naracters\n from BaseURL at construction time (this commit)\n\nRoot cause: \\x1b[A (up arrow) leaked into input, got sent as message,\nand when concatenated with /v1/chat/completions produced invalid URL.",
"is_bot": false,
"headline": "fix(providers): sanitize BaseURL to strip ANSI escape codes",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-11T17:57:12Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "4dccd20224da10fb0a5e99cd3160b04dab3d804f",
"body": "Root cause: Arrow key presses (\\x1b[A) were leaking into the input\nbuffer as raw escape sequences. When the user pressed Up (history)\nfollowed by Enter, the escape codes got concatenated into the message\nand corrupted the API URL: \\x1b[A\\x1b[/v1/chat/completions\n\nTwo-layer fix:\n1. sanitizeRunes(): F\n[…]\nny remaining\n control characters from the complete input string\n\nThis also fixes potential issues with terminal paste containing escape\ncodes, and clipboard content with embedded control characters.",
"is_bot": false,
"headline": "fix(tui): filter ANSI escape codes from input buffer",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-11T17:30:26Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "0f4ca1f38b4ac287c145771cdf9d3226478ee3a0",
"body": "Root cause: glamour's WithAutoStyle() sends OSC 11 query\n(ESC]11;rgb:ffff/ffff/ffff) to detect terminal background color.\nMany terminals (especially Windows Terminal, older xterm, screen)\ndon't support OSC 11 and print the raw response as garbled text.\n\nFixes:\n- glamour: WithAutoStyle() → WithStanda\n[…]\nsor\n- Tool panel Unicode (🔧✓✗▸▾) kept for now — these are in comments/data,\n not control sequences\n\nAlso: Banner text no longer printed before AltScreen (was leaving\nbanner artifacts when TUI exited)",
"is_bot": false,
"headline": "fix(tui): garbled output from OSC 11 escape sequences",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-11T17:02:33Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "2cebd6e4593f340a89be71ebe4aba5f9f3425f50",
"body": "Three root causes found and fixed:\n\n1. DATA RACE — Goroutine mutated model fields directly\n - startAgentStream() accumulated streamBuf += delta inside the goroutine\n AND returned lastMsg at the end, causing double-update on main goroutine.\n - Fix: Removed m.streamBuf mutation from goroutine.\n[…]\n.\n - Fix: Added proper fields, wired TurnEnd as continue.\n\nAlso fixed: ToolStartMsg now creates a placeholder message if messages\nis empty (was silently dropping tool calls before any text arrived).",
"is_bot": false,
"headline": "fix(tui): eliminate duplicate display + garbled output",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-11T13:49:52Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "0ddf01a97178f5b7811354282ccbbe442f8deac6",
"body": "…d tag\n\nRoot cause: recommend_test.go called real music.163.com API in CI.\nGitHub Actions runners are in US, music.163.com blocks foreign IPs,\ncausing TestGetRankings/TestGetTopList/TestGetNewSongs/TestGetPlaylistDetail\nto fail with network timeout.\n\nFix: Added //go:build integration tag to recommend_test.go.\nThese tests now only run with: go test -tags integration ./...\nDefault 'go test ./...' (used by CI) skips them.",
"is_bot": false,
"headline": "fix(ci): gate network-dependent netease tests behind integration buil…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-11T09:04:05Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ac977d7e9394a119ae1ec9877293b76e84a930cc",
"body": null,
"is_bot": false,
"headline": "ci: simplify test step (tests actually pass, show verbose on failure)",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-11T08:49:03Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ae28c39c310c4e2fb1a8a13568d7d623b87f70a9",
"body": null,
"is_bot": false,
"headline": "ci: add verbose test output to diagnose failure",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-11T08:43:05Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d1499de2aa0a34a68c633ee26e2a4f8acb7ed64a",
"body": "- Remove bin/pi-agent (27MB binary) from git tracking, add bin/ to .gitignore\n- go mod tidy: add glamour to go.mod (was only in go.sum), clean up indirect deps\n- This was causing CI 'go test ./...' to fail due to go.mod/go.sum mismatch",
"is_bot": false,
"headline": "fix(ci): remove committed binary + run go mod tidy",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-11T08:27:33Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "20d5ef8b0923a1464c6d7a1a50030e9eb4e6dbdc",
"body": "Root cause: go.mod requires go 1.24.2 but CI workflows used go 1.22.\nGo 1.22 cannot build/test a module requiring 1.24.2.\n\nFixed in both deploy.yml and release.yml.",
"is_bot": false,
"headline": "fix(ci): bump Go version from 1.22 to 1.24.2 to match go.mod",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-11T08:22:44Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "6575691fed2c9197d00b6e51b820a2a67d646902",
"body": "scripts/install.sh overhaul:\n- Interactive API key setup wizard (OpenAI/Anthropic/manual)\n- Creates ~/.pi-go/.env automatically\n- 'pi-go' wrapper: pi-go chat / pi-go serve / pi-go run -p\n- Auto-detects shell (bash/zsh/fish), auto-edits rc file\n- Fallback: prebuilt binary → go build from source\n\n.git\n[…]\n Cross-compile: linux/amd64, linux/arm64, darwin/amd64, darwin-arm64\n- Auto-creates GitHub Release with binary assets + checksums\n\nREADME: Simplified install to one curl command + friendly subcommands",
"is_bot": false,
"headline": "feat: one-line installer with config wizard + GitHub release workflow",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-11T08:17:32Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "459b02e5ef573ed99ea0b43dfe8f8fe61a6fe441",
"body": "- Makefile: make build/install/run/chat/serve/test/vet/clean\n- scripts/install.sh: one-line installer (go install → binary fallback → source build)\n Auto-detects OS/arch, auto-adds to PATH, supports custom install dir\n- README: Updated install section with 3 methods (one-line, go install, source)\n Updated run commands to reflect new TUI default + --legacy flag",
"is_bot": false,
"headline": "feat: one-line install + Makefile + README overhaul",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-11T07:58:56Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c2bf36c5f82c341a68407b185447c093d93de2b2",
"body": "…n dialog)\n\nNew files:\n- completion.go (283L): Autocomplete engine for /commands, @filepaths, model selector\n- completion_popup.go (204L): Dropdown popup with highlighted selection\n- keybindings.go (192L): Centralized key binding system (input/completion/confirmation contexts)\n- confirm_tui.go (189L\n[…]\nm() so callbacks can send messages to TUI\n- tui_test.go: Added 4 new tests (completion, confirmation, keybindings, toggle)\n\n21/21 tests pass. Build + vet clean. Total TUI: 3,350 lines across 16 files.",
"is_bot": false,
"headline": "feat: TUI Phase 3 — UX polish (autocomplete, keybindings, confirmatio…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-11T07:01:30Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "9973781d0d44a8c3878c9a1103bf29902f51feb2",
"body": "…tus bar)\n\n- theme.go (181L): Adaptive lipgloss color scheme (auto dark/light)\n- markdown.go (130L): Glamour markdown renderer with caching\n- tool_panel.go (210L): Collapsible tool panels with colored borders\n- status_bar.go (100L): Styled status bar (model, workspace, spinner state)\n- diff_renderer\n[…]\nnt, styled tool panels\n- tui.go upgraded: themed status bar + help hint + spinner\n- input.go upgraded: styled prompt, visible block cursor\n\n17/17 tests pass. Build + vet clean. Total TUI: 2,145 lines.",
"is_bot": false,
"headline": "feat: TUI Phase 2 — rich rendering (theme, markdown, tool panels, sta…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-11T06:45:51Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "4109da59cad407f892f5eea22c624715682e343d",
"body": "New package: internal/tui/\n- tui.go: Main TuiModel with Init/Update/View (Elm architecture)\n- update.go: Key handling, agent stream bridge, slash commands\n- input.go: Multi-line input editor (cursor movement, undo, history, kill)\n- viewport.go: Scrollable message viewport with streaming text\n- messa\n[…]\nactive mode)\n- Added deps: bubbletea, glamour, bubbles\n\nStats:\n- Build: PASS | Vet: PASS | Tests: 14/14 PASS | Full project: 0 failures\n- Phase 1 target was ~1,100 lines, actual 1,329 (includes tests)",
"is_bot": false,
"headline": "feat: TUI Phase 1 — Bubble Tea interactive CLI (1,329 lines)",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-11T04:30:00Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "e2bfcde063bb41ee0fa37a8cf53527a92746bbe6",
"body": "- Comprehensive comparison: pi-go vs pi (earendil) vs hwjcode TUI\n- 3-phase implementation plan (~3,000 lines total)\n- Bubble Tea + lipgloss + glamour tech stack\n- Package structure: internal/tui/ (16 files)\n- Key bindings, event flow, migration strategy\n- Success criteria + risk mitigations\n\nWiki updated: index.md + log.md",
"is_bot": false,
"headline": "docs: TUI Bubble Tea design document",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-11T04:08:47Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d839126cb99e4c8e798fde882a38e064c0b9ca97",
"body": null,
"is_bot": false,
"headline": "docs: update wiki log for worktree PR merge",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-06T03:23:52Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4e7e4acf9bc16d087a502ec37fca95582186ccbc",
"body": "Adds internal/worktree/ package + /worktree command (status/commit/discard).\n1,576 lines, 82 tests, race-clean.\nReviewed: security OK (git injection safe, slugify branch names, path traversal blocked).",
"is_bot": false,
"headline": "Merge PR: feat(feishu): add worktree project controls",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-06T03:22:20Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4e20c5fcf5035c2b63f1a3a2195490a402433c51",
"body": null,
"is_bot": false,
"headline": "feat(feishu): add worktree project controls",
"author_name": "weijian",
"author_login": null,
"committed_at": "2026-07-06T01:15:10Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "197aad5fbb9ad0c94707ae71f4c920d1ef40fd04",
"body": "1. batch tool properly wired: runtime builds toolListRegistry and injects\n via SetRegistry() after BuildTools(), replacing dead BuildToolsWithRegistry()\n2. Removed dead code: BuildToolsWithRegistry() + unused basetools import\n3. Cleaned up 4 stale worktrees and branches (b5cc53, hooks, lsp, mcp)\n4. gofmt applied to all modified files\n\nAll tests pass (37 packages, 0 failures). Race detector clean.\nWiki updated: hwjcode-absorption-batch.md + log.md",
"is_bot": false,
"headline": "fix: deep audit round 3 — batch tool wiring + worktree cleanup",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-05T15:18:20Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "6804df1aed743ad486feca1176a3d7215f4bcd3d",
"body": "1. LSP cache dir namespace leak: ~/.easycode-user/lsp → ~/.pi-go/lsp\n (hwjcode copy-paste artifact)\n\n2. batch tool ToolRegistry never injected:\n - BuildList creates batch tool but ListOptions.ToolRegistry never set\n - Added BuildToolsWithRegistry() to coding application.go\n\n3. LSP gopls proces\n[…]\narted lazily but never cleaned up\n - Added defer tools.ResetLSPManager() in cmd/pi-agent/main.go\n\nAll tests pass (0 failures). Race detector clean.\nWiki updated: hwjcode-absorption-batch.md + log.md",
"is_bot": false,
"headline": "fix: 3 bugs found in deep audit after hwjcode absorption merge",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-05T14:29:20Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "c6603391702ed0b4a3b8a123d2ebe081c44e17f6",
"body": "Audit findings:\n- Enhanced tools (9 tools): ✅ wired into tools.go\n- LSP tools (6 tools): ✅ wired into tools.go\n- Hooks system: ⚠️ island code (not wired into runtime)\n- Policy engine: ⚠️ island code (not wired into runtime)\n- MCP client: ⚠️ island code (not wired into runtime)\n- ask_user: ⚠️ stub implementation\n- Security: ✅ all path validation OK\n- Concurrency: ✅ race detector clean\n- Process lifecycle: ✅ no leaks\n\nWiki: hwjcode-absorption-batch.md created",
"is_bot": false,
"headline": "docs: post-merge audit + knowledge base update for 4 hwjcode modules",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-05T13:51:09Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "e6be57a1e3f188b78e3aae3c3b2cb4fc2da4a23a",
"body": null,
"is_bot": false,
"headline": "chore: update memory with parallel dev workflow standard",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-05T13:42:52Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "e631b99e74637c08248eccdcb11d484173937661",
"body": "# Conflicts:\n#\tTASK.md",
"is_bot": false,
"headline": "Merge branch 'easycode/lsp'",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-05T11:46:54Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a5a21979f0ec5ecdfee254020bf5055e33c966e6",
"body": null,
"is_bot": false,
"headline": "Merge branch 'easycode/mcp'",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-05T11:46:48Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c41bedc392d96f26e8ee54d303394a8ec19c9ff8",
"body": "# Conflicts:\n#\tTASK.md",
"is_bot": false,
"headline": "Merge branch 'easycode/hooks'",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-05T11:46:43Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "67c6828123f7f10e0c6935a83904d2a10f63bebe",
"body": "…ols, implementation)",
"is_bot": false,
"headline": "feat: LSP tools (gopls integration, go-to-def, find-refs, hover, symb…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-05T11:46:17Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3a1aa9ff2ecbdcc39c39997a411f0509470ce813",
"body": "…lti-server manager)",
"is_bot": false,
"headline": "feat: MCP client (JSON-RPC 2.0, stdio+SSE transport, tool adapter, mu…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-05T11:46:03Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "dc6eb0454b1d80a94f962ad4ef03b040e07f6478",
"body": "…ow/Deny/AskUser rules)",
"is_bot": false,
"headline": "feat: hooks system + policy engine (registry, runner, aggregator, All…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-05T11:45:55Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "54c54df3475dc7631785919c264d963af6c8d2b7",
"body": "…me, delete_file, read_many_files, ask_user)",
"is_bot": false,
"headline": "feat: enhanced tools (multiedit, patch, batch, todo, memory, local_ti…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-05T11:45:50Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1fb16e64bba80d5b93d8aba7b83923535d9b9fcf",
"body": "- internal/feishu/registration.go: Device-code app registration flow\n (init → begin → poll) via accounts.feishu.cn/oauth/v1/app/registration\n Automatically creates a PersonalAgent-type Feishu app by QR scan.\n- internal/feishu/oauth.go: OAuth flow with local callback server\n- internal/feishu/creden\n[…]\nstop/status/logout)\n- cmd/pi-feishu-bridge/main.go: Auto-load credentials from file\n (fallback when env vars not set)\n- ProbeCredentials: validates app_id/secret via tenant_access_token + bot/v3/info",
"is_bot": false,
"headline": "feat: implement feishu QR-code registration flow (port from hwjcode)",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-05T07:26:30Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "241c495fac81e4e48c830f4484600b83c3a2ac59",
"body": null,
"is_bot": false,
"headline": "fix: TASK.md path .easycode → .pi-go (correct project namespace)",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-05T03:48:26Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "8a22673ec979b6d6d5c645418b2a8cdbbc6ddaac",
"body": null,
"is_bot": false,
"headline": "ci: trigger deploy (firewall reopened)",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-05T03:36:59Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d627097aea60e624e8dce1771524f45f9e974407",
"body": "Four security and operational improvements:\n\n1. SSRF Protection on External Tool Callbacks\n - Extracted shared SSRF utilities to internal/util/ssrf.go\n - validateCallbackURL now blocks private IPs (169.254.169.254, etc.)\n - ExternalToolDef.AllowPrivate flag for trusted internal services (Feish\n[…]\non Info\n - var version = \"dev\" injectable via -ldflags\n - GET /health returns {\"status\":\"ok\",\"version\":\"...\"}\n - mode.SetVersion() propagates to server\n\nAll 33 packages pass tests. Wiki updated.",
"is_bot": false,
"headline": "feat: security hardening — SSRF, API auth, YAML config, version flag",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-05T02:13:31Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "5bb855a4e26b872119609b5364b75b6d6046622d",
"body": "Three major features:\n\n1. Web Search Tool (internal/tools/web_search.go)\n - Dual engine: SearXNG (self-hosted) + DuckDuckGo (zero-config fallback)\n - No API key required (DDG HTML parsing)\n - SSRF protection (reuses isPrivateHost from web_fetch)\n - Config: PI_GO_ENABLE_WEB_SEARCH=true, SEARX\n[…]\n\n - /undo slash command: revert last, all, list, clear\n - Handles both existing files (restore content) and new files (delete)\n - 8 tests, all passing\n\nAll 30+ packages pass tests. Wiki updated.",
"is_bot": false,
"headline": "feat: web search tool + session crash-safety + undo/rollback system",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-05T01:39:55Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "470738cc19fadc40d1d338f8a819929cbf8e5fcb",
"body": "1. Config-driven Model Registry (internal/models/registry.go)\n - Replaces hardcoded model lists with JSON-configurable registry\n - 13 built-in default models (Anthropic, OpenAI, DeepSeek, Qwen)\n - Config file resolution: PI_GO_MODELS_FILE > ~/.pi-go/models.json > data dir\n - CodingApplicatio\n[…]\nw includes session_id for chat context tracing\n - getAnySender() fallback for backward compatibility\n - All feishu tests still passing\n\nWiki updated: model-registry-feishu-fix.md, index.md, log.md",
"is_bot": false,
"headline": "feat: model registry + Feishu multi-chat sender race fix",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-05T00:57:03Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "ff8c5d9e0aa464717c650d486e78b98c4713bdef",
"body": "- internal/models/registry.go: Registry with Register/Get/List/ListByProvider\n- JSON config file support (PI_GO_MODELS_FILE or ~/.pi-go/models.json)\n- 13 built-in default models (Anthropic, OpenAI, DeepSeek, Qwen)\n- CodingApplication.AvailableModels() now uses registry instead of hardcoded list\n- 11 tests, all passing",
"is_bot": false,
"headline": "feat(models): config-driven model registry replacing hardcoded lists",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-05T00:50:12Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "697bfe66bd7a3fc79b467e0c7658f827d86ee0ae",
"body": "Two new features inspired by the hwjcode (deepvcode) project:\n\n1. /loop — Watchdog recurring loop\n - internal/scheduler/loop.go: LoopManager with goroutine + time.Ticker\n - internal/scheduler/duration.go: Duration parsing (5m, 1h, 30s)\n - internal/agents/coding/commands/loop.go: /loop slash co\n[…]\n/task <goal>, /task show, /task save, /task done, /task clear\n\nAll tests pass: scheduler (7 tests), handoff (6 tests), full suite green.\nWiki updated: loop-scheduler.md concept page, index.md, log.md.",
"is_bot": false,
"headline": "feat: /loop watchdog scheduler + TASK.md handoff (absorbed from hwjcode)",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-07-05T00:43:58Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "54eb2800263a0b7b4394688154b5ae2e9abdb11b",
"body": "Root cause of connect button spinning forever:\nThe /models endpoint returns { models: [...], current: {...} }, a dict.\nBut the store code treated it as a bare array and called .map() on it,\nwhich threw a TypeError. Although caught by try/catch, the exception\nprevented navigation.replace('List') from\n[…]\n /models response correctly (dict with .models key)\n- Add 15s timeout to all REST requests via fetchWithTimeout\n- Add 30s timeout for ASR uploads\n\nFixes: Connection hangs after clicking Connect button",
"is_bot": false,
"headline": "fix(mobile): /models API response shape mismatch + fetch timeout",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-30T09:08:46Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "2a1c334b88023f046965906acbfa2708f32c2a19",
"body": "The connect button was not responding to taps. Root cause:\nreact-native-gesture-handler native module was installed but\nGestureHandlerRootView was not wrapping the app root, so touch\nevents were not properly routed through the gesture handler system.\n\nAlso added SafeAreaProvider and 10s timeout on health check fetch.\n\nFixes: Connect button not responding to taps",
"is_bot": false,
"headline": "fix(mobile): add GestureHandlerRootView + SafeAreaProvider to root",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-30T05:02:34Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "2b86bbc1683ac250d28b667d9202dee2d99b9a8a",
"body": "Android 9+ blocks all cleartext (HTTP) traffic by default. Since pi-go\nservers may run on plain HTTP (e.g. http://8.141.97.21:8080), we must\nexplicitly allow cleartext traffic via:\n- android:usesCleartextTraffic=\"true\" in AndroidManifest.xml\n- usesCleartextTraffic in app.json (Expo config plugin)\n\nFixes: 'Network request failed' error when connecting to HTTP servers",
"is_bot": false,
"headline": "fix(android): enable cleartext traffic for HTTP server connections",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-30T01:07:08Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "fed4c15e574b005ecc97a4700561d9c93687c1f9",
"body": null,
"is_bot": false,
"headline": "docs: 更新知识库 — React Compiler移除记录",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-29T18:57:08Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "59ba432cf542548fe41e1aa60b4cf7b8598990ac",
"body": "闪退根因:\n1. React Compiler (babel-plugin-react-compiler@19 beta) 需要 React 19\n 但项目使用 React 18.3.1 → 启动即崩溃\n2. react-native-safe-area-context 未安装 → @react-navigation 运行时报错\n\n修复:\n- 移除 babel-plugin-react-compiler + react-compiler-runtime\n- 移除 app.json experiments.reactCompiler\n- 安装 react-native-safe-area-context + react-native-gesture-handler\n- 保留手动 React.memo + useCallback (R1优化不受影响)\n\nAPK已更新: https://github.com/hwj123hwj/pi-go/releases/download/v0.9.0/pigo-rn-release.apk",
"is_bot": false,
"headline": "fix(mobile): 修复闪退 — React Compiler需React19、缺失导航依赖",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-29T18:55:00Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "88cdae8680459fce99a2208faa18f26997b04524",
"body": "- abiFilters: 只打包 armeabi-v7a + arm64-v8a 真机架构\n- gradle.properties: reactNativeArchitectures 移除 x86/x86_64\n- 启用 R8 minify + 资源压缩\n- 旧Debug: 120MB → 新Release: 34MB\n\n手机安装: https://github.com/hwj123hwj/pi-go/releases/download/v0.9.0/pigo-rn-release.apk",
"is_bot": false,
"headline": "perf(mobile): APK瘦身 — Release构建+砍x86架构 120MB→34MB (减71%)",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-29T18:40:25Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "62e0aa02938e9fbe56abb02c8e0c6ec193eb88fb",
"body": "BUG-14 (MEDIUM): destroy() left serverReady=true → loading screen interrupted reconnect\n- Fixed: destroy() now resets serverReady: false alongside ready/connected\n\nBUG-15 (MEDIUM): onContentSizeChange forced scroll-to-bottom during streaming\n- User couldn't scroll up to read history while assistant \n[…]\nttomRef via onScroll; only auto-scroll when near bottom\n\nBUG-16 (LOW): connect() with same URL didn't close previous WebSocket\n- Fixed: Always call doDisconnect() if ws exists, regardless of URL match",
"is_bot": false,
"headline": "fix(mobile): state reset + scroll hijack + same-URL zombie socket",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-28T21:34:03Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "86b82fc31a8e7e1068b5f65982e0016a8a9ea22e",
"body": "…reconnect\n\nBUG-11 (CRITICAL): Server URL change → WS/REST target different servers\n- init() short-circuit (initialized guard) left WS connected to old server\n- ServerConnect now calls destroy() before init() to reset all state\n\nBUG-12 (HIGH): ws.ts connect() didn't close previous WebSocket\n- Callin\n[…]\nsconnect() → stale onclose → phantom reconnect\n- Old WebSocket.onclose fired after disconnect(), triggering scheduleReconnect\n- Fix: added connected flag + wsId counter; stale callbacks bail out early",
"is_bot": false,
"headline": "fix(mobile): WS lifecycle — server URL change, zombie sockets, stale …",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-28T21:03:26Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "3694d79c7036a9f3b98ed931318dc7c6bad027b8",
"body": "…n bubble, reset dead\n\nBUG-6 (CRITICAL): destroy() in root useEffect killed WS in Strict Mode\n- React Strict Mode runs mount→unmount→mount; destroy() on first unmount\n killed WS, initPromiseRef prevented re-init → permanent disconnect\n- Fix: Removed destroy() from root cleanup; for explicit disconn\n[…]\nme read once)\n- Fix: Added navKey state; reset increments key → full navigator remount\n\nBUG-10 (LOW): initPromiseRef rejection unhandled\n- Fix: try/catch in async IIFE + source-level try/catch (BUG-7)",
"is_bot": false,
"headline": "fix(mobile): second audit — Strict Mode WS kill, init no-catch, orpha…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-28T20:33:26Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "4067191072dac84953458ce5f803c215034b1e70",
"body": "…ve, scroll jumps\n\nBUG-1 (CRITICAL): init() guard race condition\n- initialized=true was set before URL check → second init() call was no-op\n- WS never connected when user entered URL on ServerConnect screen\n- Fix: Move guard after URL validation, return Promise<boolean>\n\nBUG-2 (CRITICAL): setActive(\n[…]\nted\n- Fix: await init() before navigation\n\nBUG-5 (LOW): destroy() never called on unmount\n- WS listeners leaked when app backgrounded/closed\n- Fix: destroy() in App.tsx cleanup useEffect + state reset",
"is_bot": false,
"headline": "fix(mobile): 5 bugs from optimization audit — init race, dead setActi…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-28T20:05:58Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "b07e3714f544b11d0d2a2e42714f96e9be5d186f",
"body": "…ment, native navigation\n\nbundle-analyze-js (CRITICAL):\n- Production HBC: 859KB, 529 modules — 100% RN core, no bloat\n- Installed expo-asset (was missing for metro config)\n- No unnecessary third-party polyfills found\n\nnative-android-16kb-alignment (CRITICAL):\n- zipalign -c -P 16: all 52 .so files 16\n[…]\ne)\n\nnative-sdks-over-polyfills (HIGH):\n- Audited 21 polyfill modules in production bundle\n- All are RN core infrastructure (buffer, whatwg-url, whatwg-fetch, etc.)\n- Zero app-level polyfills to remove",
"is_bot": false,
"headline": "perf(mobile): RN best practices round 4 — bundle analysis, 16KB align…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-28T17:41:33Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "d36e9fd09309114c9a7b00a5cf9309eaeba79b23",
"body": "…ndaries, React Compiler\n\nError Boundaries (HIGH):\n- New ErrorBoundary component wrapping all three screens\n- Catches render crashes, shows fallback with retry button\n\njs-concurrent-react (HIGH):\n- useDeferredValue on transcript + busy during streaming\n- FlatList renders deferred data, prioritizing \n[…]\nainers\n\njs-react-compiler (HIGH):\n- babel-plugin-react-compiler@beta enabled (target: '18')\n- app.json experiments.reactCompiler = true\n- Automatic memoization — no more manual memo/useCallback needed",
"is_bot": false,
"headline": "perf(mobile): RN best practices round 3 — concurrent React, error bou…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-28T17:08:14Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "2ddd95dff612642ec5bf097ce98a0a68b0507227",
"body": "…g, memory leaks\n\nbundle-barrel-exports (CRITICAL):\n- Split api/index.ts → api/rest.ts + api/server-url.ts\n- Split types/index.ts → types/ChatItem.ts + types/ModelInfo.ts + types/SessionView.ts\n- All imports now reference specific files, eliminating unnecessary module evaluation\n\nbundle-tree-shaking\n[…]\nects WS\n- WS client: disconnect() clears timer + all listeners\n- Exponential backoff: 3s→6s→12s→max 30s, resets on success\n\nWiki updated: react-native-mobile-app.md with all 9 optimizations documented",
"is_bot": false,
"headline": "perf(mobile): RN best practices round 2 — barrel exports, tree shakin…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-28T16:41:11Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "b515893ed4a1300eeaba5c8cbf36866732cc7bff",
"body": "Complete rewrite of mobile client from Capacitor to React Native + Expo.\n\nNew mobile/ directory:\n- Expo SDK 52 + React Native 0.76.7 + TypeScript (zero errors)\n- Zustand store with atomic selectors (fine-grained subscriptions)\n- WebSocket client with auto-reconnect\n- Three screens: ServerConnect, Se\n[…]\naxToRenderPerBatch, windowSize, getItemLayout\n6. Zustand atomic selectors — each field subscribed independently\n\nWiki: react-native-mobile-app.md documenting architecture, best practices, build config",
"is_bot": false,
"headline": "feat(mobile): React Native app with RN best practices optimization",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-28T15:56:39Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "2262de6b0c3d15342260d33d5136b25b628223f7",
"body": "- useVoiceInput: show actual server error message instead of generic text\n- Network errors get dedicated message\n- Error toast is now clickable to dismiss\n- Added extensive console.log for debugging\n- asr.go: parse SiliconFlow error body for detailed message\n- asr.go: log audio MIME type and size on success\n\nVersion: 0.8.7 (versionCode 15)",
"is_bot": false,
"headline": "fix(asr): detailed error messages + server-side error parsing",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-28T11:25:52Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "fa5764e5fcbf30e6f9c5ecb6ed8450104ffa29f9",
"body": "Root cause: mobile-updater.ts used (Capacitor as any).registerPlugin\nwhich doesn't exist on Capacitor 7 — getAppVersion() silently failed\nand returned '0.0.0', so checkMobileUpdate() always thought the app\nwas outdated or the version comparison was wrong.\n\nFixes:\n- Use registerPlugin from @capacitor\n[…]\nomparison debugging\n- Improved Sidebar check-update button: shows current version + manual\n download URL in the fallback message\n- Added getManualDownloadUrl() helper\n\nVersion: 0.8.6 (versionCode 14)",
"is_bot": false,
"headline": "fix(mobile): registerPlugin for ApkUpdater + improved update check UX",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-28T09:29:06Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "ecf39e5627d9e7b594c41c8af4e12716821e8b89",
"body": "Root causes of mic still failing:\n1. JS accessed native plugin via Capacitor proxy object — unreliable\n2. Method names startRecording/stopRecording/requestPermission/checkPermission\n collided with Capacitor Plugin base class methods\n\nFixes:\n- Use registerPlugin<>() for proper TypeScript-safe plugi\n[…]\naccess\n- Renamed methods: askPermission, hasPermission, start, stop\n- Added extensive logging for Logcat debugging\n- Updated useVoiceInput.ts to match new method names\n\nVersion: 0.8.5 (versionCode 13)",
"is_bot": false,
"headline": "fix(android): registerPlugin + method name collision fix",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-28T08:56:54Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "070bd186f5754c8cd6810cee616f1775899d98df",
"body": "- Changed flex-direction from column-reverse to column (content top, rail bottom)\n- Rail items: 48px min-width, 52px min-height (was 44px) for comfortable touch\n- Active item now has accent-weak background + accent color\n- Rail background: bg-elev (darker, visual separation)\n- Padding: 6px + safe-area-inset-bottom (avoids system gesture area)\n- Rail labels: 10px font (was 9px) for readability\n- Launcher mode: justify-content flex-end (rail sits at bottom)\n\nVersion: 0.8.4 (versionCode 12)",
"is_bot": false,
"headline": "fix(mobile): optimize right sidebar rail to bottom navigation bar",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-28T04:38:17Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3024a0c0fb0944a8ac83361f806bd4cd78977d0a",
"body": "WebView getUserMedia is fundamentally unreliable on Android Capacitor.\nReplaced with native recording approach:\n\n- New NativeRecorderPlugin.java:\n - Android native MediaRecorder (AudioSource.MIC, AAC encoder)\n - startRecording / stopRecording methods\n - Returns base64-encoded audio + mimeType\n -\n[…]\nhook\n - Android: NativeRecorderPlugin → base64 → Blob → upload\n - Desktop/Browser: standard MediaRecorder + getUserMedia\n\n- Registered NativeRecorder in MainActivity\n\nVersion: 0.8.3 (versionCode 11)",
"is_bot": false,
"headline": "fix(android): native MediaRecorder plugin to bypass WebView mic issues",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-28T04:13:26Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "2c9cc11845a03c9f5edaa35e93804e70410ed9c6",
"body": "…ations\n\nRoot cause: Capacitor's BridgeActivity sets its own WebChromeClient that\ndenies all getUserMedia permission requests. Even with OS-level\nRECORD_AUDIO granted, the WebView blocks audio capture.\n\nFix (3 layers):\n1. WebChromeClient override: auto-grant all PermissionRequest resources\n (this \n[…]\notations for proper Capacitor 7 API\n3. useVoiceInput: simplified permission flow (native plugin only on\n Capacitor, skip browser Permissions API which is unreliable)\n\nVersion: 0.8.2 (versionCode 10)",
"is_bot": false,
"headline": "fix(android): WebChromeClient auto-grant + Capacitor permission annot…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-28T04:07:02Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "1259a0716d78d3bf38011372f7a14c6b1edbc2e1",
"body": "- New MicrophonePermissionPlugin.java: calls Android\n ActivityCompat.requestPermissions for RECORD_AUDIO, returns granted/denied\n- Registered in MainActivity.java\n- useVoiceInput.ts: calls native plugin before getUserMedia on Capacitor\n (WebView getUserMedia silently fails without OS-level permission)\n- Version bump to 0.8.1 (versionCode 9)",
"is_bot": false,
"headline": "fix(android): native MicrophonePermission plugin for RECORD_AUDIO",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-28T03:59:48Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4231f9d173ddced7b62a308c0fa7153cc34a1fc8",
"body": "Backend:\n- New /asr/transcribe endpoint proxies audio to SiliconFlow ASR API\n- Config: ASRAPIKey/ASRModel/ASRBaseURL env vars (defaults: SiliconFlow, TeleAI/TeleSpeechASR)\n- Reuses SILICONFLOW_API_KEY if ASR_API_KEY not set\n\nFrontend:\n- useVoiceInput hook: MediaRecorder API for audio capture\n- Promp\n[…]\nIcon: added 'mic' icon (24x24 SVG path)\n- CSS: .btn-voice styles (desktop + mobile), recording pulse animation\n- Android: RECORD_AUDIO permission in AndroidManifest.xml\n\nVersion: 0.8.0 (versionCode 8)",
"is_bot": false,
"headline": "feat: add voice input (ASR) via SiliconFlow TeleSpeechASR",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-28T03:42:39Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "cd633531f6b7fac5c7c28ee86cd4ca44da4a7bb6",
"body": "- Bumped version to 0.7.0 (versionCode 7) so auto-update can detect it\n- Fixed music bar: removed leftover transform: translateX(-50%) on mobile\n- Music bar layout: full-width, two-row flex-wrap on mobile",
"is_bot": false,
"headline": "feat(mobile): v0.7.0 — music bar layout fix + version bump",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-27T11:07:22Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "88cb0eeeb8199c33d75c674a43c035660b076f03",
"body": "- PromptBar.tsx: removed isElectron guard on model selector <select>\n- SessionView.tsx: same — model selector now visible on mobile\n- app.css: changed .prompt-config from display:none to display:flex on mobile\n with compact sizing for small screens",
"is_bot": false,
"headline": "feat(mobile): show model selector on mobile (remove isElectron guard)",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-27T10:52:00Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "6b185cc730dcfd5fb36eae8fa1b254e67d7fd9ec",
"body": "…oid gestures\n\nProblem: buttons at screen edges (sidebar footer, promptbar, music bar,\nright sidebar rail) were too close to Android gesture navigation area\n(bottom pill/line), causing accidental system triggers.\n\nFix: added env(safe-area-inset-bottom) padding to ALL bottom-anchored elements:\n- Side\n[…]\n:\n- Sidebar check-update button: removed hacky DOM manipulation, simplified\n- Right sidebar mobile close: top offset accounts for status bar\n- Consolidated duplicate .sidebar-foot definitions into one",
"is_bot": false,
"headline": "fix(mobile): edge safety zones — buttons no longer conflict with Andr…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-27T10:07:41Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "f92e15a7d9faef78b45687e885bbd2752c3f1dee",
"body": "- Added ↻ refresh icon button in sidebar footer (mobile only)\n- Click: checks GitHub Releases for newer version\n - If update available: shows MobileUpdateDialog\n - If already latest: shows alert '已是最新版本 vX.X.X'\n- Auto-check still runs 3s after app launch\n- MobileUpdateDialog listens for 'pi-go-show-update' custom event\n for manual triggering from the sidebar button",
"is_bot": false,
"headline": "feat(mobile): add manual check-update button in sidebar footer",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-27T09:54:26Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3eedd1dac98a95f8389ff3f7eafc2fcca395c58b",
"body": "The music bar was trying to fit everything (icon, song, play btn, progress,\ntime, close) in one horizontal row on a narrow phone screen, causing elements\nto overflow and get cut off by the screen edge.\n\nFixed with a two-row flex-wrap layout:\n- Row 1: icon + song info (flex:1, left) | close button (right)\n- Row 2: play button + progress bar (flex:1) + time (full width)\n- gap reduced, padding compacted\n- promptbar bottom padding increased to 110px to clear the taller bar",
"is_bot": false,
"headline": "fix(mobile): global music bar two-row layout — no more cut-off/overflow",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-27T09:44:34Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4ae96b0b92f8c943e7aff4f943a3385bdaa2a47a",
"body": "…dateDialog\n\nCustom Capacitor plugin (ApkUpdaterPlugin.java):\n- downloadAndInstall(): downloads APK natively with progress events\n- getAppVersion(): returns native versionName\n- Uses FileProvider + ACTION_VIEW intent to trigger system installer\n- Progress events via notifyListeners('downloadProgress\n[…]\name 0.6.0\n\nToolbar declutter (also included):\n- Hide density toggle on mobile\n- Hide sidebar + bottom terminal toggles on mobile\n- Only right-panel toggle shown\n- justify-content: space-between layout",
"is_bot": false,
"headline": "feat(mobile): in-app self-update v0.6.0 — ApkUpdaterPlugin + MobileUp…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-27T08:42:28Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "8ddfd0709d051fc42b8221e6ac521f790e336771",
"body": "…-panel button (v37)\n\nMobile toolbar was overcrowded with 8 elements in 48px height:\n- Title, status dot, density toggle (3 mini buttons), 3 workspace toggles\n\nFixed:\n- Density toggle: hidden entirely on mobile (display:none !important)\n- WorkspaceToggles: sidebar toggle and bottom terminal toggle w\n[…]\nht\n panel toggle.\n- Toolbar: justify-content: space-between — title left, toggle right\n- Title: max-width 50vw to prevent overflow\n- Removed duplicate .workspace-toggles CSS block (was defined twice)",
"is_bot": false,
"headline": "fix(mobile): declutter toolbar — hide density toggle, show only right…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-27T03:06:41Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "f8abb19a02aece23b71c0f1f63abdf114eb042ee",
"body": "…andled rejection (v36)\n\n1. .rsidebar-content overflow conflict: desktop sets overflow:hidden (line 494),\n mobile sets overflow-y:auto (line 5227). Without !important, desktop rule\n could win via cascade, making right sidebar panel unscrollable on mobile.\n Fixed: overflow-y: auto !important on\n[…]\n?.writeText()\n in Markdown.tsx had no .catch(). On HTTP origins (no HTTPS), Clipboard API\n throws NotAllowedError, causing unhandled promise rejection.\n Fixed: added .catch() to silently ignore.",
"is_bot": false,
"headline": "fix: code review round 4 — rsidebar overflow conflict + clipboard unh…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-26T22:40:40Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "b547cbd1c7cc82f53db70178b75c03fa01eea849",
"body": "… !important (v35)\n\n1. Sidebar backdrop double-dimming on mobile: app::before overlay (50% black,\n pointer-events:none) AND .sidebar-mobile-backdrop div (50% black, has click\n handler) were both rendered, creating 75% effective dimming. The ::before\n also sat at same z-index as backdrop, poten\n[…]\n !important in mobile media query, allowing base .btn-stop definition\n (height:32px, font-size:12.5px) to override depending on cascade order.\n Fixed: all critical properties now have !important.",
"is_bot": false,
"headline": "fix: code review round 3 — sidebar backdrop double-dimming + btn-stop…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-26T22:10:09Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "6a9a7c86bfd410a55dfe3239600283529bc4bb12",
"body": "…eal (v34)\n\n1. File tree not hidden on mobile: CSS targeted '.files-sidebar' class that\n doesn't exist in DOM. FilesPanel renders <Resizer> + <FileTree> directly\n in .files-body. Fixed selectors to '.files-panel .file-tree' and\n '.files-body > .resizer'.\n\n2. ChatPane onTouchStart steals focus \n[…]\non every touch, including taps on code copy buttons,\n tool card expand, etc. Added target.closest() guard for interactive elements:\n button, a, input, textarea, .tool-head, .md-code-copy, .gm-btn.",
"is_bot": false,
"headline": "fix: code review round 2 — file tree mobile selector + touch focus st…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-26T21:36:42Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "75760c746f41beb0c2e90a4c8e6b18985da93914",
"body": "1. Duplicate .toolbar-density-mobile CSS: two blocks with conflicting props.\n Consolidated to one with display:flex + margin-left:auto.\n\n2. Duplicate .rsidebar-content CSS: three definitions existed (desktop + two\n mobile). Merged into single mobile definition with padding-top for close\n butto\n[…]\n+ audio.load() to fully release.\n\n4. Unused playMusic store subscription in GlobalMusicBar — after v30 refactor,\n playMusic was subscribed but never used, causing unnecessary re-renders.\n Removed.",
"is_bot": false,
"headline": "fix: code review — 4 bugs from mobile optimization rounds v27-v32",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-26T21:19:36Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "8a21bd181279b8f308067783ac903205e99c9098",
"body": "…dismiss (v32)\n\nToolbar density toggle on mobile:\n- Was hidden entirely, now uses 'toolbar-density-mobile' class\n- Compact 28px buttons, 10px font — functional without crowding toolbar\n\nEmpty state mobile cleanup:\n- Hide folder picker on mobile (no native folder dialog)\n- Hide model selector on mobi\n[…]\ns\n\nKeyboard auto-dismiss:\n- Touching/scrolling transcript blurs active input on mobile\n- Hides soft keyboard, reclaims screen for reading\n- Implemented via onTouchStart on pane-body (isElectron gated)",
"is_bot": false,
"headline": "feat(mobile): density toggle mobile + empty state cleanup + keyboard …",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-26T20:36:00Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "7fd4d04872fc3c3f8f0bc352750bf9acd3bb2a75",
"body": "…ular (v31)\n\nRight sidebar mobile close button:\n- Floating ← back arrow in top-left of any right sidebar panel\n- 40px touch target, calls toggleWorkspaceRight() to close\n- rsidebar-content gets top padding to avoid overlap\n- Hidden on desktop (display:none by default)\n\nPromptBar stop button mobile:\n- Changed from pill (text+icon) to 36px circular icon-only\n- Matches send button size and visual rhythm\n- font-size:0 removes text on mobile",
"is_bot": false,
"headline": "feat(mobile): right sidebar close button + PromptBar stop button circ…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-26T20:05:18Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "23e93f603e59e02f97cd840a3e332a4d7a387fc2",
"body": "…le panel touch (v30)\n\nCritical fix: Right sidebar mobile CSS was targeting wrong class names\n- CSS rules used '.right-sidebar*' but actual component classes are '.rsidebar*'\n- This meant the file browser (Files panel), Review, Plan, KB, Profile panels\n were completely inaccessible on mobile — no f\n[…]\nN: 'Close', ZH: '关闭')\n\nFile panel mobile optimizations:\n- File tree hidden on mobile (save space)\n- File tabs: touch-friendly with always-visible close buttons\n- Compact code view with momentum scroll",
"is_bot": false,
"headline": "fix(mobile): right sidebar CSS mismatch + music bar close button + fi…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-26T19:29:35Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "61b2e5dda0a65fae40fb4ff5e7520d55a7ff9ab0",
"body": "…zontal space\n\n- Toolbar status: font-size:0 (hide text, keep status dot)\n- Status dot: 8px on mobile\n- Also fix: missing line break after right-sidebar comment",
"is_bot": false,
"headline": "fix(mobile): hide toolbar status text — dot-only indicator saves hori…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-26T19:06:40Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "480c12a62990d1e89b306e3d0151d48fb621dbdc",
"body": "…utton\n\n- Input: 15px → 16px font (prevents iOS auto-zoom)\n- Button: 48px min-height (HIG touch target)\n- Card title: 28px → 24px, icon: 64px → 56px (proportional)",
"is_bot": false,
"headline": "fix(mobile): server connect screen iOS zoom prevention + 48px touch b…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-26T18:55:41Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "e1dd393224c358bae743c2d8423f479eb503ca32",
"body": "…omentum scroll (v29)\n\nDiff preview mobile optimizations:\n- Hide line-number gutters on phone screens (saves horizontal space)\n- Compact font: 12px → 11px, tighter line-height\n- Smaller diff head: verb/path/meta font reduced\n\nTool body & console output:\n- Max-height 200px with momentum scroll (-webk\n[…]\nin-height for touch\nScrolling: momentum scroll + overscroll-behavior: contain\nRole tags: compact 10px font, 18px badge\nTyping dots: 7px → 6px\n\nWiki: desktop-app.md v29 table + CodeBlock component docs",
"is_bot": false,
"headline": "feat(mobile): UX overhaul round 3 — diff preview, modal, code copy, m…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-26T18:43:54Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "3bcaadab2c01c5ecbab152ba214634a437c78e89",
"body": "…down, keyboard adaptive (v28)\n\nChat transcript mobile optimizations:\n- Transcript padding 28px → 16px 14px (edge-efficient)\n- Message spacing 22px → 16px (denser reading)\n- User message border-radius 12px → 16px (rounder, chat-like)\n- Assistant text 13.5px → 14px with 1.65 line-height (readability)\n[…]\n\n\nSidebar mobile:\n- Search input 15px, 36px min-height\n- Sidebar head safe-area padding\n- Right sidebar rail buttons: 44px min-width/height\n\nWiki: desktop-app.md mobile table expanded with 15 new rows",
"is_bot": false,
"headline": "feat(mobile): UX overhaul round 2 — chat density, touch targets, Mark…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-26T18:10:40Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "10ba56cc28b66d7f68bcf337e1a924efaebbbc7b",
"body": "PromptBar optimizations:\n- Hide model selector chip on mobile (saves vertical space)\n- Hide ⌘V keyboard shortcut hint on mobile (no keyboard shortcuts)\n- Increase send button to 36px circular for larger touch target\n- Remove 'Stop' text label on mobile (icon only)\n- Tighter padding with safe-area-in\n[…]\nyed):\n- Detect and reject HTML/text Content-Type from upstream\n- NetEase: return error instead of unchecked stale URL fallback\n\nWiki: desktop-app.md updated with full Mobile/Capacitor platform section",
"is_bot": false,
"headline": "feat(mobile): UX overhaul for mobile experience (v27)",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-26T17:43:28Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "309596a78f3887522db8275bf7002dfe7e0e82fb",
"body": "Two fixes for audio not playing on mobile:\n\n1. Handler: detect non-audio Content-Type (text/html, text/plain,\n application/json) from upstream even when status=200, treat as stale\n URL and retry. NetEase often returns HTML error pages with 200 status\n for blocked/VIP songs.\n\n2. NetEase: Strategy 3 (fallback) now returns an error instead of the\n unchecked outer URL. Previously it returned a broken URL that resulted\n in HTML being proxied to the audio player.",
"is_bot": false,
"headline": "fix(music): detect and reject HTML error pages in audio proxy",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-26T15:35:17Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c9c06ce0ff4226518cf0e4d2363b3ff2d574871b",
"body": "- Backend: audioBaseURL changed from http://host:port/music/audio to\n /music/audio (relative), so the frontend resolves it against whatever\n server it's connected to — works for mobile (Capacitor), desktop, web\n- Frontend: rewriteAudioURL now handles relative paths by prepending\n current base URL, with backward compat for old absolute URLs\n- Also removed unused 'fmt' import from application.go",
"is_bot": false,
"headline": "fix(music): use relative path for audio proxy URL",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-26T14:45:14Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "870b0f7d1da5295b204f6e5122b87e6905345c0d",
"body": "The systemd service was listening on 127.0.0.1:8080 (localhost only),\nwhich prevented external connections from mobile clients or other\nmachines. Changed to 0.0.0.0:8080 so the server is accessible on all\nnetwork interfaces.\n\nThis enables the Android APK to connect to the cloud-hosted backend.",
"is_bot": false,
"headline": "fix(deploy): bind pi-agent to 0.0.0.0 for mobile/remote access",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-26T14:06:31Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "148acdcddac3d70d0b72c67f311ff64291d3df94",
"body": "Major addition: the same React frontend now builds as a native Android APK.\n\nPlatform abstraction (platform.ts):\n- isElectron / isCapacitor / isRemotePlatform detection\n- Mobile platforms use stored server URL (localStorage) instead of IPC\n- canPickFolder / canCheckUpdates feature flags\n\nServer conn\n[…]\nild-android.sh: end-to-end APK build script\n\ni18n: 11 new keys for server connect + mobile UI (en + zh)\n\nStore init: conditional IPC vs localStorage for server URL\n\nIcons: added menu, link, info icons",
"is_bot": false,
"headline": "feat(mobile): add Android APK support via Capacitor",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-26T12:49:11Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "c7219a26df7ebf210c93439dd005b1695d74e17b",
"body": "…leanup\n\n- Created source-project-root-v26.md (4 commits covered)\n- Updated 7 wiki pages:\n - four-layer-architecture: removed cmd/pi-music from entrypoints\n - music-agent: marked cmd/pi-music as removed\n - desktop-app: added Bottom Terminal, sidebar toggle, profile error state\n - kb-agent: added v26 absolute path fix for clickable desktop links\n - overview: updated stats (16 commands, ~26k LOC, 67 test files)\n- Resolved 3 contradictions: pi-music references, slash count, LOC stats",
"is_bot": false,
"headline": "docs(llm-wiki): ingest v26 — desktop UI fixes, KB paths, entrypoint c…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-26T12:17:31Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b0b7feeece8c1b9b78adfad8198d7f6e83740ba1",
"body": "…oggle, profile error\n\n1. File explorer 'Open in' dropdown was clipped by overflow:hidden on\n .file-toolbar → changed to overflow:visible\n2. Bottom panel toggle had no rendered component → added BottomTerminal.tsx\n showing aggregated command output, wired into SessionView with Resizer\n3. Right s\n[…]\nve icon now toggles closed instead of\n being a no-op (added toggleWorkspaceView action)\n4. Profile panel: error state now shows the actual error message + retry\n button instead of silently failing",
"is_bot": false,
"headline": "fix(desktop): fix 4 UI issues — file menu, bottom terminal, sidebar t…",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-26T12:08:16Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "d559148bbc412b8948fd06fd3afff728559022ff",
"body": "KB tools previously returned relative paths (e.g. issues/xxx.md). The\ndesktop Markdown renderer's isFilePath() requires a leading / or ~/,\nso these relative paths were never clickable — they displayed as plain\ntext/code with no way to open them in the Files panel sidebar.\n\nChanges:\n- kb_search: emit\n[…]\n truncate to relative\n\nThe desktop Markdown renderer already handles absolute paths in inline\ncode (isFilePath → clickable file-path-link → open-file event →\nFilesPanel opens the file in the sidebar).",
"is_bot": false,
"headline": "fix(kb): output absolute paths so desktop renders clickable file links",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-26T10:48:52Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "313e6ad540bdf5933a69b8d1ef6556ff6e55e8e9",
"body": "cmd/pi-music is fully covered by cmd/pi-agent, which already includes\nall three applications (coding, music, kb) with unified configuration.\nThe standalone pi-music binary served no additional purpose.\n\n- Delete cmd/pi-music/ directory\n- Remove references from README.md and docs/PROJECT_CONTEXT.md",
"is_bot": false,
"headline": "refactor: remove redundant cmd/pi-music entrypoint",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-26T05:21:28Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "037b606148e33e55fd7202125eac6b93146f714a",
"body": "- Remove DeepV/Mock provider references (removed v6/v7)\n- Add PI_GO_API_KEY/PI_GO_MODEL/PI_GO_BASE_URL env priority vars\n- Add KB agent (3rd application) to architecture and description\n- Add new features: unified profile, KB vector search, memory extraction,\n tool output synopsis, desktop client\n-\n[…]\n/*, /workspace/* endpoints to HTTP API table\n- Add KB embedding config vars (PI_GO_KB_*)\n- Update stats: 144 source files, 67 test files, ~26k LOC, 16 commands\n- Add wiki slash command to command list",
"is_bot": false,
"headline": "docs: update README with v17-v25 features and accurate stats",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-26T05:03:18Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "d3c95ef0360df463c8ad48122994ba91f251c3e5",
"body": "Created 5 wiki pages:\n- wiki/source-project-root-v25.md (source summary)\n- wiki/unified-profile.md (cross-agent profile concept)\n- wiki/kb-vector-search.md (hybrid search concept)\n- wiki/session-memory-extraction.md (ExtractLoop adaptation)\n- wiki/tool-output-synopsis.md (After-hook synopsis concept\n[…]\nroadmap.md (P0/P1/P1.5 marked done)\n- wiki/config-system.md (KB embedding config fields)\n- index.md (4 new concept entries, updated descriptions)\n- log.md (ingest entry with 5 contradictions resolved)",
"is_bot": false,
"headline": "docs(llm-wiki): ingest v25 — 4 new concept pages, 5 entity updates",
"author_name": "EasyAgent User",
"author_login": null,
"committed_at": "2026-06-26T04:52:44Z",
"body_truncated": true,
"is_coding_agent": false
}
],
"releases_count": 32,
"commits_last_year": 277,
"latest_release_at": "2026-07-13T05:19:04Z",
"latest_release_tag": "v0.10.12",
"releases_from_tags": false,
"days_since_last_push": 14,
"active_weeks_last_year": 9,
"days_since_latest_release": 14,
"mean_days_between_releases": 0.1
},
"community": {
"has_readme": true,
"has_license": false,
"has_description": true,
"has_contributing": true,
"health_percentage": 42,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"ecosystem": {
"packages": [
{
"name": "github.com/hwj123hwj/pi-go",
"exists": true,
"license": null,
"keywords": [],
"ecosystem": "go",
"matches_repo": true,
"registry_url": "https://pkg.go.dev/github.com/hwj123hwj/pi-go",
"is_deprecated": false,
"latest_version": "v0.10.12",
"repository_url": "https://github.com/hwj123hwj/pi-go",
"versions_count": 33,
"total_downloads": null,
"dependents_count": null,
"deprecation_note": null,
"maintainers_count": null,
"monthly_downloads": null,
"first_published_at": null,
"latest_published_at": "2026-07-13T05:17:21Z",
"latest_version_yanked": null,
"days_since_latest_publish": 14
}
]
},
"popularity": {
"forks": 1,
"stars": 3,
"watchers": 0,
"fork_history": {
"days": [
{
"date": "2026-07-05",
"count": 1
}
],
"complete": true,
"collected": 1,
"total_forks": 1
},
"star_history": null,
"open_issues_and_prs": 0
},
"ai_readiness": {
"has_nix": false,
"example_dirs": [],
"has_llms_txt": false,
"has_dockerfile": false,
"has_mcp_signal": false,
"bootstrap_files": [
"Makefile"
],
"api_schema_files": [],
"has_devcontainer": false,
"typecheck_configs": [
"desktop/tsconfig.json",
"mobile/tsconfig.json"
],
"toolchain_manifests": [
"desktop/android/app/build.gradle",
"desktop/android/build.gradle",
"go.mod",
"mobile/android/app/build.gradle",
"mobile/android/build.gradle"
],
"largest_source_bytes": 41145,
"source_files_sampled": 377,
"oversized_source_files": 0,
"agent_instruction_files": [
".claude/CLAUDE.md",
"AGENTS.md"
],
"agent_instruction_max_bytes": 4071
},
"dependencies": {
"manifests": [
"desktop/package.json",
"go.mod",
"mobile/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": [
"go",
"npm"
],
"dependencies": [
{
"name": "@capacitor/android",
"manifest": "desktop/package.json",
"ecosystem": "npm",
"version_constraint": "^7.0.0"
},
{
"name": "@capacitor/app",
"manifest": "desktop/package.json",
"ecosystem": "npm",
"version_constraint": "^7.0.0"
},
{
"name": "@capacitor/core",
"manifest": "desktop/package.json",
"ecosystem": "npm",
"version_constraint": "^7.0.0"
},
{
"name": "@capacitor/filesystem",
"manifest": "desktop/package.json",
"ecosystem": "npm",
"version_constraint": "^7.1.8"
},
{
"name": "@capacitor/splash-screen",
"manifest": "desktop/package.json",
"ecosystem": "npm",
"version_constraint": "^7.0.0"
},
{
"name": "@capacitor/status-bar",
"manifest": "desktop/package.json",
"ecosystem": "npm",
"version_constraint": "^7.0.0"
},
{
"name": "@types/semver",
"manifest": "desktop/package.json",
"ecosystem": "npm",
"version_constraint": "^7.7.1"
},
{
"name": "fuzzysort",
"manifest": "desktop/package.json",
"ecosystem": "npm",
"version_constraint": "^3.1.0"
},
{
"name": "highlight.js",
"manifest": "desktop/package.json",
"ecosystem": "npm",
"version_constraint": "^11.11.1"
},
{
"name": "mermaid",
"manifest": "desktop/package.json",
"ecosystem": "npm",
"version_constraint": "^11.15.0"
},
{
"name": "react",
"manifest": "desktop/package.json",
"ecosystem": "npm",
"version_constraint": "^19.0.0"
},
{
"name": "react-dom",
"manifest": "desktop/package.json",
"ecosystem": "npm",
"version_constraint": "^19.0.0"
},
{
"name": "semver",
"manifest": "desktop/package.json",
"ecosystem": "npm",
"version_constraint": "^7.8.4"
},
{
"name": "zustand",
"manifest": "desktop/package.json",
"ecosystem": "npm",
"version_constraint": "^5.0.0"
},
{
"name": "github.com/JohannesKaufmann/html-to-markdown",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.6.0"
},
{
"name": "github.com/charmbracelet/bubbletea",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.3.10"
},
{
"name": "github.com/charmbracelet/glamour",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.0.0"
},
{
"name": "github.com/charmbracelet/lipgloss",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.1.1-0.20250404203927-76690c660834"
},
{
"name": "github.com/gorilla/websocket",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.5.3"
},
{
"name": "github.com/joho/godotenv",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.5.1"
},
{
"name": "github.com/larksuite/oapi-sdk-go/v3",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v3.9.2"
},
{
"name": "github.com/stretchr/testify",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.11.1"
},
{
"name": "gopkg.in/yaml.v3",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v3.0.1"
},
{
"name": "@react-navigation/native",
"manifest": "mobile/package.json",
"ecosystem": "npm",
"version_constraint": "^7.3.4"
},
{
"name": "@react-navigation/native-stack",
"manifest": "mobile/package.json",
"ecosystem": "npm",
"version_constraint": "^7.17.6"
},
{
"name": "expo",
"manifest": "mobile/package.json",
"ecosystem": "npm",
"version_constraint": "~52.0.0"
},
{
"name": "expo-asset",
"manifest": "mobile/package.json",
"ecosystem": "npm",
"version_constraint": "~11.0.5"
},
{
"name": "expo-secure-store",
"manifest": "mobile/package.json",
"ecosystem": "npm",
"version_constraint": "~13.0.0"
},
{
"name": "expo-status-bar",
"manifest": "mobile/package.json",
"ecosystem": "npm",
"version_constraint": "~2.0.0"
},
{
"name": "react",
"manifest": "mobile/package.json",
"ecosystem": "npm",
"version_constraint": "18.3.1"
},
{
"name": "react-native",
"manifest": "mobile/package.json",
"ecosystem": "npm",
"version_constraint": "0.76.7"
},
{
"name": "react-native-gesture-handler",
"manifest": "mobile/package.json",
"ecosystem": "npm",
"version_constraint": "~2.20.2"
},
{
"name": "react-native-safe-area-context",
"manifest": "mobile/package.json",
"ecosystem": "npm",
"version_constraint": "4.12.0"
},
{
"name": "react-native-screens",
"manifest": "mobile/package.json",
"ecosystem": "npm",
"version_constraint": "~4.4.0"
},
{
"name": "zustand",
"manifest": "mobile/package.json",
"ecosystem": "npm",
"version_constraint": "^5.0.0"
}
],
"all_dependencies": {
"error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
"source": null,
"packages": [],
"collected": false,
"truncated": false,
"total_count": null,
"direct_count": null,
"indirect_count": null
}
},
"maintainership": {
"issues": {
"open_prs": 0,
"merged_prs": 33,
"open_issues": 0,
"closed_ratio": null,
"closed_issues": 0,
"closed_unmerged_prs": 0
},
"bus_factor": 1,
"bot_contributors": 0,
"top_contributors": [
{
"type": "User",
"login": "hwj123hwj",
"commits": 32,
"avatar_url": "https://avatars.githubusercontent.com/u/130386673?v=4"
},
{
"type": "User",
"login": "Steven-Chen13",
"commits": 20,
"avatar_url": "https://avatars.githubusercontent.com/u/77038088?v=4"
}
],
"contributors_sampled": 2,
"top_contributor_share": 0.615
},
"quality_signals": {
"has_ci": true,
"has_tests": true,
"ci_workflows": [
"deploy.yml",
"release.yml"
],
"has_docs_dir": true,
"linter_configs": [],
"has_editorconfig": false,
"has_linter_config": false,
"has_precommit_config": false
},
"security_signals": {
"lockfiles": [
"go.sum",
"package-lock.json"
],
"scorecard": {
"checks": [
{
"name": "Binary-Artifacts",
"score": 8,
"reason": "binaries present in source code",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
},
{
"name": "Branch-Protection",
"score": 0,
"reason": "branch protection not enabled on development/release branches",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
},
{
"name": "CI-Tests",
"score": 0,
"reason": "0 out of 1 merged PRs checked by a CI test -- score normalized to 0",
"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/29 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": 0,
"reason": "license file not detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
},
{
"name": "Maintained",
"score": 0,
"reason": "project was created within the last 90 days. Please review its contents carefully",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
},
{
"name": "Packaging",
"score": null,
"reason": "packaging workflow not detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
},
{
"name": "Pinned-Dependencies",
"score": 0,
"reason": "dependency not pinned by hash detected -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
},
{
"name": "SAST",
"score": 0,
"reason": "SAST tool is not run on all commits -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
},
{
"name": "Security-Policy",
"score": 0,
"reason": "security policy file not detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
},
{
"name": "Signed-Releases",
"score": 0,
"reason": "Project has not signed or included provenance with any releases.",
"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": "76 existing vulnerabilities detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
}
],
"commit": "61ac7466426943fdc1cc4b174e68dd6bd853e3a3",
"ran_at": "2026-07-27T18:10:54Z",
"aggregate_score": 1.6,
"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-13T05:18:32Z",
"oldest_open_prs": [],
"last_merged_pr_at": "2026-07-06T03:23:55Z",
"ci_last_conclusion": "SUCCESS",
"oldest_open_issues": []
}
},
"config": {
"disabled_metrics": [],
"disabled_categories": [],
"disabled_components": {}
},
"source": {
"url": "https://github.com/hwj123hwj/pi-go",
"host": "github.com",
"name": "pi-go",
"owner": "hwj123hwj"
},
"metrics": {
"overall": {
"key": "overall",
"band": "at_risk",
"name": "Overall health",
"note": null,
"notes": [],
"value": 46,
"inputs": {
"security": 16,
"vitality": 68,
"community": 24,
"governance": 53,
"engineering": 59
},
"components": []
},
"categories": [
{
"key": "vitality",
"band": "moderate",
"name": "Vitality",
"value": 68,
"weight": 0.22,
"metrics": [
{
"key": "development_activity",
"band": "moderate",
"name": "Development activity",
"note": null,
"notes": [],
"value": 53,
"inputs": {
"commits_last_year": 277,
"human_commit_share": 1,
"days_since_last_push": 14,
"active_weeks_last_year": 9
},
"components": [
{
"key": "push_recency",
"name": "Push recency",
"detail": "last push 14 days ago",
"points": 28.8,
"status": "partial",
"details": [
{
"code": "push_recency",
"params": {
"days": 14
}
}
],
"max_points": 36
},
{
"key": "commit_cadence",
"name": "Commit cadence",
"detail": "9/52 weeks with commits",
"points": 6.2,
"status": "partial",
"details": [
{
"code": "commit_cadence_weeks",
"params": {
"weeks": 9
}
}
],
"max_points": 36
},
{
"key": "commit_volume",
"name": "Commit volume",
"detail": "277 commits in the last year",
"points": 18,
"status": "met",
"details": [
{
"code": "commits_last_year",
"params": {
"count": 277
}
}
],
"max_points": 18
},
{
"key": "openssf_scorecard_maintained",
"name": "OpenSSF Scorecard: Maintained",
"detail": "project was created within the last 90 days. Please review its contents carefully",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "release_discipline",
"band": "excellent",
"name": "Release discipline",
"note": null,
"notes": [],
"value": 90,
"inputs": {
"releases_count": 32,
"latest_release_tag": "v0.10.12",
"releases_from_tags": false,
"days_since_latest_release": 14,
"mean_days_between_releases": 0.1
},
"components": [
{
"key": "ships_releases",
"name": "Ships releases",
"detail": "32 releases published",
"points": 27,
"status": "met",
"details": [
{
"code": "releases_published",
"params": {
"count": 32
}
}
],
"max_points": 27
},
{
"key": "release_recency",
"name": "Release recency",
"detail": "latest release 14 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "release_recency",
"params": {
"days": 14
}
}
],
"max_points": 36
},
{
"key": "release_cadence",
"name": "Release cadence",
"detail": "a release every ~0.1 days",
"points": 27,
"status": "met",
"details": [
{
"code": "release_cadence",
"params": {
"gap": 0.1
}
}
],
"max_points": 27
},
{
"key": "openssf_scorecard_signed_releases",
"name": "OpenSSF Scorecard: Signed-Releases",
"detail": "Project has not signed or included provenance with any releases.",
"points": 0,
"status": "missed",
"details": [],
"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": "critical",
"name": "Community & Adoption",
"value": 24,
"weight": 0.18,
"metrics": [
{
"key": "popularity",
"band": "critical",
"name": "Popularity & adoption",
"note": null,
"notes": [],
"value": 5,
"inputs": {
"forks": 1,
"stars": 3,
"watchers": 0,
"growth_state": "unverified",
"growth_factor_pct": 100,
"growth_unverified_reason": "no_history"
},
"components": [
{
"key": "stars",
"name": "Stars",
"detail": "3 stars",
"points": 4.9,
"status": "partial",
"details": [
{
"code": "stars",
"params": {
"count": 3
}
}
],
"max_points": 60
},
{
"key": "forks",
"name": "Forks",
"detail": "1 forks",
"points": 0,
"status": "missed",
"details": [
{
"code": "forks",
"params": {
"count": 1
}
}
],
"max_points": 25
},
{
"key": "watchers",
"name": "Watchers",
"detail": "0 watchers",
"points": 0,
"status": "missed",
"details": [
{
"code": "watchers",
"params": {
"count": 0
}
}
],
"max_points": 15
}
]
},
{
"key": "community_health",
"band": "at_risk",
"name": "Community health",
"note": null,
"notes": [],
"value": 45,
"inputs": {
"has_readme": true,
"has_license": false,
"has_contributing": true,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 22.5,
"status": "met",
"details": [],
"max_points": 22.5
},
{
"key": "license",
"name": "License",
"detail": "no license file detected",
"points": 0,
"status": "missed",
"details": [
{
"code": "license_absent",
"params": {}
}
],
"max_points": 22.5
},
{
"key": "contributing_guide",
"name": "CONTRIBUTING guide",
"detail": null,
"points": 18,
"status": "met",
"details": [],
"max_points": 18
},
{
"key": "code_of_conduct",
"name": "Code of conduct",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 13.5
},
{
"key": "issue_template",
"name": "Issue template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.2
},
{
"key": "pr_template",
"name": "PR template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 6.3
}
]
}
],
"description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
},
{
"key": "governance",
"band": "moderate",
"name": "Sustainability & Governance",
"value": 53,
"weight": 0.24,
"metrics": [
{
"key": "maintainer_resilience",
"band": "critical",
"name": "Maintainer resilience (bus factor)",
"note": null,
"notes": [],
"value": 20,
"inputs": {
"bus_factor": 1,
"contributors_sampled": 2,
"top_contributor_share": 0.615
},
"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 62% of commits",
"points": 8.7,
"status": "partial",
"details": [
{
"code": "top_contributor_share",
"params": {
"share": 62
}
}
],
"max_points": 22.5
},
{
"key": "contributor_breadth",
"name": "Contributor breadth",
"detail": "2 contributors",
"points": 2.7,
"status": "partial",
"details": [
{
"code": "contributors_sampled",
"params": {
"count": 2
}
}
],
"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": "good",
"name": "Issue & PR responsiveness",
"note": "Excluded from scoring (no data or not applicable): Issue resolution. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"issue_resolution"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 72,
"inputs": {
"merged_prs": 33,
"open_issues": 0,
"closed_issues": 0,
"issue_closed_ratio": null,
"closed_unmerged_prs": 0
},
"components": [
{
"key": "issue_resolution",
"name": "Issue resolution",
"detail": "no issues or no data",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_issues_or_data",
"params": {}
}
],
"max_points": 46.75
},
{
"key": "pr_acceptance",
"name": "PR acceptance",
"detail": "33/33 decided PRs merged",
"points": 38.2,
"status": "met",
"details": [
{
"code": "decided_prs_merged",
"params": {
"merged": 33,
"decided": 33
}
}
],
"max_points": 38.25
},
{
"key": "openssf_scorecard_code_review",
"name": "OpenSSF Scorecard: Code-Review",
"detail": "Found 0/29 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
}
]
},
{
"key": "stewardship",
"band": "at_risk",
"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": 37,
"inputs": {
"followers": 2,
"owner_type": "User",
"is_verified": null,
"owner_login": "hwj123hwj",
"public_repos": 18,
"account_age_days": 1204
},
"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": "2 followers of hwj123hwj",
"points": 3.4,
"status": "partial",
"details": [
{
"code": "owner_followers",
"params": {
"count": 2,
"login": "hwj123hwj"
}
}
],
"max_points": 25
},
{
"key": "track_record",
"name": "Track record",
"detail": "18 public repos, account ~3 yr old",
"points": 15.9,
"status": "partial",
"details": [
{
"code": "public_repos",
"params": {
"count": 18
}
},
{
"code": "account_age_years",
"params": {
"years": 3
}
}
],
"max_points": 25
}
]
},
{
"key": "package_maintenance",
"band": "excellent",
"name": "Package maintenance",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"packages": [
"github.com/hwj123hwj/pi-go"
],
"ecosystems": "go",
"any_deprecated": false,
"min_days_since_publish": 14
},
"components": [
{
"key": "published_resolvable",
"name": "Published & resolvable",
"detail": "1 package(s) on go",
"points": 25,
"status": "met",
"details": [
{
"code": "packages_published",
"params": {
"count": 1,
"ecosystems": "go"
}
}
],
"max_points": 25
},
{
"key": "publish_recency",
"name": "Publish recency",
"detail": "latest publish 14 days ago",
"points": 35,
"status": "met",
"details": [
{
"code": "publish_recency",
"params": {
"days": 14
}
}
],
"max_points": 35
},
{
"key": "version_history",
"name": "Version history",
"detail": "33 published versions",
"points": 20,
"status": "met",
"details": [
{
"code": "published_versions",
"params": {
"count": 33
}
}
],
"max_points": 20
},
{
"key": "not_deprecated",
"name": "Not deprecated",
"detail": "active, not deprecated or yanked",
"points": 20,
"status": "met",
"details": [
{
"code": "package_not_deprecated",
"params": {}
}
],
"max_points": 20
}
]
}
],
"description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
},
{
"key": "engineering",
"band": "moderate",
"name": "Engineering Quality",
"value": 59,
"weight": 0.2,
"metrics": [
{
"key": "engineering_practices",
"band": "at_risk",
"name": "Engineering practices",
"note": null,
"notes": [],
"value": 48,
"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": "2 workflow(s)",
"points": 24,
"status": "met",
"details": [
{
"code": "ci_workflows",
"params": {
"count": 2
}
}
],
"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": "0 out of 1 merged PRs checked by a CI test -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 20
}
]
},
{
"key": "documentation",
"band": "good",
"name": "Documentation",
"note": null,
"notes": [],
"value": 75,
"inputs": {
"topics": [],
"has_wiki": true,
"homepage": null,
"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": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
},
{
"key": "repository_description",
"name": "Repository description",
"detail": null,
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "topics",
"name": "Topics",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
},
{
"key": "wiki",
"name": "Wiki",
"detail": null,
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
}
],
"description": "Are baseline engineering and documentation practices in place?"
},
{
"key": "security",
"band": "critical",
"name": "Security",
"value": 16,
"weight": 0.16,
"metrics": [
{
"key": "security_posture",
"band": "critical",
"name": "Security posture",
"note": "Excluded from scoring (no data or not applicable): Packaging. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"packaging"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 16,
"inputs": {
"source": "openssf_scorecard",
"checks_evaluated": 17,
"scorecard_version": "v5.5.0",
"checks_inconclusive": 1,
"scorecard_aggregate": 1.6
},
"components": [
{
"key": "binary_artifacts",
"name": "Binary-Artifacts",
"detail": "binaries present in source code",
"points": 6,
"status": "partial",
"details": [],
"max_points": 7.5
},
{
"key": "branch_protection",
"name": "Branch-Protection",
"detail": "branch protection not enabled on development/release branches",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "ci_tests",
"name": "CI-Tests",
"detail": "0 out of 1 merged PRs checked by a CI test -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 2.5
},
{
"key": "cii_best_practices",
"name": "CII-Best-Practices",
"detail": "no effort to earn an OpenSSF best practices badge detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 2.5
},
{
"key": "code_review",
"name": "Code-Review",
"detail": "Found 0/29 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 not detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 2.5
},
{
"key": "maintained",
"name": "Maintained",
"detail": "project was created within the last 90 days. Please review its contents carefully",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "packaging",
"name": "Packaging",
"detail": "packaging workflow not detected",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 5
},
{
"key": "pinned_dependencies",
"name": "Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "sast",
"name": "SAST",
"detail": "SAST tool is not run on all commits -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "security_policy",
"name": "Security-Policy",
"detail": "security policy file not detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "signed_releases",
"name": "Signed-Releases",
"detail": "Project has not signed or included provenance with any releases.",
"points": 0,
"status": "missed",
"details": [],
"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": "76 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": 3
},
"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": 76,
"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": 0.97,
"agent_instruction_files": [
".claude/CLAUDE.md",
"AGENTS.md"
],
"agent_instruction_max_bytes": 4071
},
"components": [
{
"key": "agent_instructions",
"name": "Agent instructions",
"detail": ".claude/CLAUDE.md, AGENTS.md",
"points": 45,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": ".claude/CLAUDE.md, AGENTS.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": "97 of 100 human commits state their intent (structured subject or explanatory body)",
"points": 40,
"status": "met",
"details": [
{
"code": "legible_history",
"params": {
"legible": 97,
"sampled": 100
}
}
],
"max_points": 40
}
]
},
{
"key": "ai_verify_loop",
"band": "moderate",
"name": "Verify loop (build / test / typecheck)",
"note": null,
"notes": [],
"value": 61,
"inputs": {
"has_nix": false,
"has_tests": true,
"lockfiles": [
"go.sum",
"package-lock.json"
],
"has_dockerfile": false,
"typed_language": true,
"bootstrap_files": [
"Makefile"
],
"has_devcontainer": false,
"has_linter_config": false,
"typecheck_configs": [
"desktop/tsconfig.json",
"mobile/tsconfig.json"
],
"agent_commit_share": 0,
"toolchain_manifests": [
"desktop/android/app/build.gradle",
"desktop/android/build.gradle",
"go.mod",
"mobile/android/app/build.gradle",
"mobile/android/build.gradle"
],
"dependency_bot_commit_share": 0
},
"components": [
{
"key": "one_command_bootstrap",
"name": "One-command bootstrap",
"detail": "Makefile",
"points": 18,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "Makefile"
}
}
],
"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": "desktop/tsconfig.json, mobile/tsconfig.json",
"points": 11,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "desktop/tsconfig.json, mobile/tsconfig.json"
}
}
],
"max_points": 11
},
{
"key": "reproducible_environment",
"name": "Reproducible environment",
"detail": "lockfile",
"points": 10,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "lockfile"
}
}
],
"max_points": 10
},
{
"key": "demonstrated_agent_practice",
"name": "Demonstrated agent practice",
"detail": "no agent-authored commits among the last 100",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_agent_authored_commits",
"params": {
"sampled": 100
}
}
],
"max_points": 10
},
{
"key": "automated_maintenance",
"name": "Automated maintenance",
"detail": "no automated dependency updates observed",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_dependency_automation",
"params": {}
}
],
"max_points": 8
},
{
"key": "openssf_scorecard_pinned_dependencies",
"name": "OpenSSF Scorecard: Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "ai_code_legibility",
"band": "excellent",
"name": "Code legibility for models",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"primary_language": "Go",
"largest_source_bytes": 41145,
"source_files_sampled": 377,
"oversized_source_files": 0
},
"components": [
{
"key": "type_checkable_code",
"name": "Type-checkable code",
"detail": "Go (statically typed)",
"points": 45,
"status": "met",
"details": [
{
"code": "statically_typed_language",
"params": {
"language": "Go"
}
}
],
"max_points": 45
},
{
"key": "manageable_file_sizes",
"name": "Manageable file sizes",
"detail": "0/377 source files over 60KB",
"points": 55,
"status": "met",
"details": [
{
"code": "oversized_source_files",
"params": {
"kb": 60,
"sampled": 377,
"oversized": 0
}
}
],
"max_points": 55
}
]
}
],
"description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
}
],
"metrics_version": "1.13.0"
},
"warnings": [
"Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
"Could not fetch npm package 'pi-go-desktop' from its registry",
"GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository"
],
"report_type": "repository",
"generated_at": "2026-07-27T18:11:01.541605Z",
"schema_version": "0.27.0",
"badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/h/hwj123hwj/pi-go.svg",
"full_name": "hwj123hwj/pi-go",
"license_state": "absent",
"license_spdx": null
}