)]}'
{
  "log": [
    {
      "commit": "bf6e9422960401da6bba01d03a8ea9979722bb5a",
      "tree": "9cc75e286f7fde4535e1251059d33b9330621d49",
      "parents": [
        "fa25b3d018380d1893602af832756f2bb35a4a89"
      ],
      "author": {
        "name": "Guangdong Liu",
        "email": "liugddx@gmail.com",
        "time": "Mon Sep 14 16:21:11 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 14 16:21:11 2026 +0800"
      },
      "message": "feat(runtime): report background task process and endpoint health (#5261)"
    },
    {
      "commit": "fa25b3d018380d1893602af832756f2bb35a4a89",
      "tree": "a4b3e207cb385781bcd5d2aa2d6b543b177b8784",
      "parents": [
        "f109ccde910dd8a42d35c6a72e60cef91815819f"
      ],
      "author": {
        "name": "QuinnWan",
        "email": "144975606+somewan820@users.noreply.github.com",
        "time": "Mon Sep 14 15:10:20 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 14 15:10:20 2026 +0800"
      },
      "message": "feat(desktop): add Work Board Phase 3 start-task spike (#4598)"
    },
    {
      "commit": "f109ccde910dd8a42d35c6a72e60cef91815819f",
      "tree": "ddb7afa5f8ae4d87e9dface8fdf0f785769970f4",
      "parents": [
        "6bff26b420ff31938d4e49a6640515b1bd5e5fc7"
      ],
      "author": {
        "name": "AstroHan",
        "email": "lei.yuhan@outlook.com",
        "time": "Mon Sep 14 12:55:51 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 14 12:55:51 2026 +0800"
      },
      "message": "fix(runtime): unify safe stream recovery and preserve interrupted responses (#5270)\n\nUnify EOF, idle timeout, and retryable transport recovery under a ten-request budget while preserving failed response fragments as interrupted transcript output. Keep provider-side effects and continuation boundaries as replay barriers, and exclude failed fragments from model history.\n\nCarry interruption markers through persistence and live/reload projection, render response dividers without empty thinking-only bubbles, and preserve finalized provider reasoning. Account for overflow recovery and sampled tool input, and remove redundant retry state.\n\nGenerated-by: Codex"
    },
    {
      "commit": "6bff26b420ff31938d4e49a6640515b1bd5e5fc7",
      "tree": "26536428f2b6cf4e3cdf7fcb0a2e998fb5d04bd3",
      "parents": [
        "0d4a6ba5f48de6807ab96d6b5aad3635cc6a1f57"
      ],
      "author": {
        "name": "SummerC0zyR0ck",
        "email": "98086622+SummerC0zyR0ck@users.noreply.github.com",
        "time": "Mon Sep 14 11:37:34 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 14 11:37:34 2026 +0800"
      },
      "message": "fix(context): make provider-dropping note truthful for declared windows (#5174)\n\n* fix(context): make provider-dropping note truthful for declared windows\n\n* fix(context): use neutral provider-dropping guidance"
    },
    {
      "commit": "0d4a6ba5f48de6807ab96d6b5aad3635cc6a1f57",
      "tree": "83aa87e27f2f555b36c9f5080db179615de1a236",
      "parents": [
        "837133a291a2508fe21e9cdf1bfed790d1a9f763"
      ],
      "author": {
        "name": "Xiao Liu",
        "email": "liuxiao2103@qq.com",
        "time": "Mon Sep 14 00:07:52 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 14 00:07:52 2026 +0800"
      },
      "message": "perf(core): count diff lines without materializing display rows (#5243)\n\nShare a structural scanner between diff counting and display parsing. Avoid line splitting, body substrings and display-row allocation for count-only callers while preserving hunk semantics and row shapes. Include boundary, differential and allocation regression coverage.\n\nFixes #5242\n\nGenerated-by: Codex"
    },
    {
      "commit": "837133a291a2508fe21e9cdf1bfed790d1a9f763",
      "tree": "74adaa28b60b73576f14d32d086006e661f95d44",
      "parents": [
        "906c3c9075639a9cc83bbb8206286ca99a694119"
      ],
      "author": {
        "name": "Nyvo",
        "email": "czp12123@gmail.com",
        "time": "Mon Sep 14 00:07:48 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 14 00:07:48 2026 +0800"
      },
      "message": "feat(runtime): persist durable Goal continuation outbox (#4864)\n\nPersist the frozen successor intent alongside Goal settlement in the existing Goal authority. Consume the pending continuation into currentExecution before dispatch, preserving recovered waiting prompts and atomic supersession. Legacy records remain readable without a SQL migration.\n\nGenerated-by: Codex"
    },
    {
      "commit": "906c3c9075639a9cc83bbb8206286ca99a694119",
      "tree": "ed0bbb67fd1f73bde008e0bcdd02431608a6b141",
      "parents": [
        "d2e6c1f273b7daa23ff75b84c8a30dca3f316713"
      ],
      "author": {
        "name": "ChengBo Zhang",
        "email": "66726968+ARE404@users.noreply.github.com",
        "time": "Sun Sep 13 23:33:23 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 13 23:33:23 2026 +0800"
      },
      "message": "feat(ui): fold turn process and improve WorkHub rail feedback (#5259)\n\n* feat(ui): collapse turn process above the final reply\n\nGroup intermediate commentary, reasoning and tools behind a native elapsed-time disclosure. Preserve final answers, steering boundaries and manual disclosure state.\n\nGenerated-by: Codex\n\n* fix(workhub): strengthen rounded message rail feedback\n\nGive identity rails full-height hit targets and visible hover and focus feedback without shifting message content.\n\nGenerated-by: Codex\n\n* fix(workhub): refine rail widths and remove hover backdrop\n\nUse a 4px default stripe and 6px hover stripe without a tinted background.\n\nGenerated-by: Codex\n\n* fix(workhub): spread work identity colors across the hue wheel\n\nShare an incremental max-gap hue allocation across navigation and conversation. Preserve assigned colors while the surface remains mounted and separate new Works from existing hues.\n\nGenerated-by: Codex\n\n* fix(workhub): cycle identity colors through six separated hue bands\n\nSample a stable ID-seeded hue within each 30-degree band, advancing sequentially and leaving alternating bands unused.\n\nGenerated-by: Codex\n\n* fix(desktop): route WorkHub color tests through testing entry\n\nThe renderer architecture guard rejects tests importing feature-private modules. Export the allocator through the existing testing entry and consume that boundary.\n\nGenerated-by: Codex\n\n* fix(storybook): verify painted WorkHub colors instead of tokens\n\nKeep range math in allocator tests and check resolved stripe colors in the browser, as required by the ink-ladder contract.\n\nGenerated-by: Codex\n\n* fix(storybook): open completed process before cold scroll checks\n\nThe oversized-turn fixture now defaults to collapsed. Reach its expanded reading state before asserting overflow and first upward traversal stability.\n\nGenerated-by: Codex\n\n* fix(perf): expand process content for transcript geometry trials\n\nReach the expanded process before measuring the 45-tool scene so cold-scroll assertions exercise actual overflow.\n\nGenerated-by: Codex\n\n* fix(ui): preserve imported replies before trailing reasoning\n\nGenerated-by: Codex"
    },
    {
      "commit": "d2e6c1f273b7daa23ff75b84c8a30dca3f316713",
      "tree": "8ee73e0bc35ff730b33356da6cfdf4e889738151",
      "parents": [
        "4cd71eaed26dbf296f1142db3296b27136d7d131"
      ],
      "author": {
        "name": "Wang",
        "email": "m4n5terrr@gmail.com",
        "time": "Sun Sep 13 20:03:26 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 13 20:03:26 2026 +0800"
      },
      "message": "fix(ui): open magnetic model pickers without shifting nearby controls (#5257)\n\n* fix(ui): open magnetic model pickers without shifting nearby controls\n\nGenerated-by: Codex\n\n* fix(ui): retain model picker focus and opaque popup surfaces\n\nGenerated-by: Codex"
    },
    {
      "commit": "4cd71eaed26dbf296f1142db3296b27136d7d131",
      "tree": "a0ddad1e8e0436d1b2779928c2f6d7f6b0d5d72b",
      "parents": [
        "b37eb96398ace9a9935dbfd87999b12d0af865b8"
      ],
      "author": {
        "name": "AstroHan",
        "email": "lei.yuhan@outlook.com",
        "time": "Sun Sep 13 18:45:33 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 13 18:45:33 2026 +0800"
      },
      "message": "refactor(runtime): unify bounded Read and tool-result pruning (#5247)\n\nUnify bounded Read pagination and tool-result pruning, preserve durable Bash output and failure semantics, and stream bounded transcript views with recoverable Read references.\n\nGenerated-by: Codex"
    },
    {
      "commit": "b37eb96398ace9a9935dbfd87999b12d0af865b8",
      "tree": "5036711f2ae15a0ccb2eb7feef7c9dfa9df98ef2",
      "parents": [
        "09f0a5d364a3da869c06069f166d758ef6025855"
      ],
      "author": {
        "name": "AstroHan",
        "email": "lei.yuhan@outlook.com",
        "time": "Sun Sep 13 17:55:55 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 13 17:55:55 2026 +0800"
      },
      "message": "fix(runtime): report Grep completeness and Glob traversal errors (#5246)\n\n* fix(runtime): name ripgrep when Grep cannot run it\n\nGrep failed with a bare `spawn rg ENOENT` on the local path and a\ngeneric \"Grep is unavailable in this runtime.\" in the filesystem worker.\nBoth now fail with grep_unavailable and copy that names ripgrep, an\ninstall command and the next step (retry locally, restart Maka for the\nworker).\n\nThe local path checks that the cwd still exists before blaming ripgrep,\nbecause Node reports a missing spawn cwd with the same ENOENT. The\nworker maps a spawn ENOENT for its startup-resolved executable to\ngrep_unavailable instead of not_found, which read as a missing search\npath.\n\nFixes #5167\n\nGenerated-by: Claude Code\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n* ci: track ripgrep-guidance in the Windows gates\n\nThe shared ripgrep copy is imported by the filesystem worker and the\nbuiltin tools, so it joins the Windows package closure and the recovery\nfilter. Register the new POSIX-only EACCES test in the Windows skip\ninventory as a platform contract.\n\nGenerated-by: Claude Code\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n* fix(runtime): let Grep recover from a missing ripgrep with a retry\n\nThe filesystem worker\u0027s launch configuration cached its first ripgrep\nlookup for the life of the Host, so installing ripgrep, or an upgrade\nthat moved it, needed a Host restart that quitting Desktop does not\nalways perform. Keep a resolved copy while the same file is still\nthere, and look again on the next launch when it was missing, has\ndisappeared or was replaced in place, with the same executable and\ndependency-root checks, so the sandbox only grants the copy found.\nMach-O inspection results are kept per file identity, so an unchanged\nbinary never runs otool twice.\n\nThe guidance now says where to install ripgrep and to retry. It names\nthe WSL distribution when there is one and otherwise the machine the\nHost runs on, without the hostname: the text reaches the model as tool\noutput. On Windows the winget Links directory is also a candidate,\nsince a running Host keeps the PATH it started with.\n\nRefs #5167\n\nGenerated-by: Claude Code\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n* fix(runtime): report exact Grep completeness with bounded results\n\nGenerated-by: Codex\n\n* fix(ci): include Grep scanner in Windows package trigger\n\nGenerated-by: Codex\n\n* fix(runtime): surface Glob traversal permission failures\n\nGenerated-by: Codex\n\n* fix(runtime): preserve Glob directory symlink traversal semantics\n\nGenerated-by: Codex\n\n* refactor(runtime): resolve ripgrep dependencies per search\n\nGenerated-by: Codex\n\n* fix(runtime): prioritize Grep completeness in bounded projections\n\nGenerated-by: Codex\n\n* fix(runtime): preserve authorized ancestor ignore rules in Grep\n\nGenerated-by: Codex\n\n* fix(runtime): distinguish Grep protocol from bounded Read protocol\n\nGenerated-by: Codex\n\n* fix(runtime): mount authorized Grep metadata in Linux workers\n\nGenerated-by: Codex\n\n* fix(runtime): create sandbox metadata markers before host mounts\n\nGenerated-by: Codex\n\n* fix(runtime): preserve lexical Grep metadata paths in Linux\n\nGenerated-by: Codex\n\n* fix(runtime): validate opened Linux paths before granting descriptors\n\nGenerated-by: Codex\n\n* chore(runtime): refresh search dependency and test inventories\n\nGenerated-by: Codex\n\n* chore(cli): account for reviewed search dependencies in artifact budget\n\nThe measured multi-platform tarball is 33,585,405 bytes. Set a 33 MiB compressed ceiling while retaining the unpacked-size and entry-count limits.\n\nGenerated-by: Codex\n\n* fix(runtime): report Grep metadata descriptor limits before launch\n\nReuse the existing descriptor ceiling and reject excessive ancestor metadata before opening descriptors. Preserve all ignore rules and give an actionable search-scope error.\n\nGenerated-by: Codex\n\n* chore: refresh Windows inventory after rebase\n\nGenerated-by: Codex\n\n* fix(cli): retain ACP prompts until Stop delivery settles\n\nKeep the active prompt owned until an in-flight Stop response settles, even when terminal subscription events arrive first. This prevents shutdown from interrupting the control request.\n\nGenerated-by: Codex\n\n* fix(runtime): surface invalidated glob traversal directories\n\n* fix(runtime): share ripgrep discovery with bypass searches\n\n* ci: track shared ripgrep discovery in Windows checks\n\n---------\n\nCo-authored-by: Totoro \u003cmsy626836554@gmail.com\u003e\nCo-authored-by: Claude Opus 5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "09f0a5d364a3da869c06069f166d758ef6025855",
      "tree": "1119eb51a87ac66c614436ff8b1da4488e02fb22",
      "parents": [
        "bb8280505c27960eebc564cdaff04095292b6311"
      ],
      "author": {
        "name": "NekoPunch",
        "email": "95899648+orangeCatDeveloper@users.noreply.github.com",
        "time": "Sun Sep 13 01:15:45 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 13 16:15:45 2026 +0800"
      },
      "message": "fix(desktop): return expected failures as codes across IPC (#4878)\n\nPreserve expected setting, Plan and attachment failures as structured values through Electron IPC and contextBridge, then reconstruct typed errors in renderer-owned adapters for actionable localized feedback. Reuse shared attachment preparation and retain Runtime Host as the configuration authority. The Runtime Host protocol is unchanged; no migration is required.\n\nGenerated-by: Claude Code\nGenerated-by: OpenCode\nGenerated-by: Codex"
    },
    {
      "commit": "bb8280505c27960eebc564cdaff04095292b6311",
      "tree": "41dcd6621fbb3719850e1c017898c174ac152a04",
      "parents": [
        "6dfec43fe201607584fe148ead6093d22586b70e"
      ],
      "author": {
        "name": "NekoPunch",
        "email": "95899648+orangeCatDeveloper@users.noreply.github.com",
        "time": "Sun Sep 13 00:39:10 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 13 15:39:10 2026 +0800"
      },
      "message": "fix(ci): widen the locale hygiene gate to its blind spots (#5180)\n\nUse the existing typed handoff catalog and explicit bot surface locale, and extend the source hygiene check to Runtime Host and multiline native-dialog literals. Existing handoff behavior is preserved; no protocol or migration change is required.\n\nGenerated-by: Claude Code\nGenerated-by: Codex"
    },
    {
      "commit": "6dfec43fe201607584fe148ead6093d22586b70e",
      "tree": "fd01bb148feee27001712a2fed99ef5ccdec8f96",
      "parents": [
        "9d4a6e4de30bcfc89d947369e4b3321186c2aeef"
      ],
      "author": {
        "name": "ChengBo Zhang",
        "email": "66726968+ARE404@users.noreply.github.com",
        "time": "Sun Sep 13 15:23:00 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 13 15:23:00 2026 +0800"
      },
      "message": "feat(workhub): unify conversation identity and Host-owned choices (#5198)\n\nGenerated-by: Codex"
    },
    {
      "commit": "9d4a6e4de30bcfc89d947369e4b3321186c2aeef",
      "tree": "541af2332058b001b22a558c35d58b2746c223cc",
      "parents": [
        "6ce9c72c351b527585b7bc9d944ab52e7c5cb4cf"
      ],
      "author": {
        "name": "悉尼麦当劳大王",
        "email": "471926906@qq.com",
        "time": "Sun Sep 13 17:01:29 2026 +1000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 13 15:01:29 2026 +0800"
      },
      "message": "fix:desktop skill select ui bug (#5249)"
    },
    {
      "commit": "6ce9c72c351b527585b7bc9d944ab52e7c5cb4cf",
      "tree": "b747abf606ce7fe409adedc30f09bc43df309b80",
      "parents": [
        "fe7a98960ae280e3c307fd543d835bdb357a84d6"
      ],
      "author": {
        "name": "Sun-GLiang",
        "email": "81428141+Sun-GLiang@users.noreply.github.com",
        "time": "Sun Sep 13 14:35:13 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 13 14:35:13 2026 +0800"
      },
      "message": "feat(cli): add ACP live session lifecycle (#4862)"
    },
    {
      "commit": "fe7a98960ae280e3c307fd543d835bdb357a84d6",
      "tree": "5abebd6beb8791b2292650d4a52e7ece4013c422",
      "parents": [
        "a9f5f6790dc72253ffa3c0d1282f38b2fd58453a"
      ],
      "author": {
        "name": "Colafornia",
        "email": "wangyilinchn@icloud.com",
        "time": "Sun Sep 13 14:15:03 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 13 14:15:03 2026 +0800"
      },
      "message": "fix(desktop): preserve workbar tab scrollbar behavior (#5204)\n\nGenerated-by: Maka\n\nCo-authored-by: colafornia \u003ccolaforniaw@gmail.com\u003e"
    },
    {
      "commit": "a9f5f6790dc72253ffa3c0d1282f38b2fd58453a",
      "tree": "4ab7b54da6b85642d5f1922ec98655ed67c3a48d",
      "parents": [
        "84ece04d015c0b0143c4154a735e967a7737eb0c"
      ],
      "author": {
        "name": "Guangdong Liu",
        "email": "liugddx@gmail.com",
        "time": "Sun Sep 13 10:44:39 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 13 10:44:39 2026 +0800"
      },
      "message": "fix(desktop): make HTML artifacts directly openable (#5216)"
    },
    {
      "commit": "84ece04d015c0b0143c4154a735e967a7737eb0c",
      "tree": "6348bcdbe5ed6643a0127aa952578c1b98c8361e",
      "parents": [
        "ca4136a026ef2cc1a470906d6d237145d66a2057"
      ],
      "author": {
        "name": "小七",
        "email": "ggbdpq@gmail.com",
        "time": "Sun Sep 13 10:07:02 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 13 10:07:02 2026 +0800"
      },
      "message": "fix(runtime-host): admit structured-only Messages and keep them model-visible (#4815)\n\nAllow quote-only, attachment-only, and directory-reference messages through the existing shared admission and replay rules. Preserve structured content, message metadata, and confirmed-admission cleanup in Desktop and Side Conversations.\n\nAdvance the Host compatibility epoch to 150 for structured-only admission; incompatible peers are refused at handshake.\n\nGenerated-by: GLM-5.3-Flash (ZCode)"
    },
    {
      "commit": "ca4136a026ef2cc1a470906d6d237145d66a2057",
      "tree": "5a300e0453618eb892279033070004234a6f8521",
      "parents": [
        "c1d50256c38b66080013a7ba98414c9a9835a8c9"
      ],
      "author": {
        "name": "NekoPunch",
        "email": "95899648+orangeCatDeveloper@users.noreply.github.com",
        "time": "Sat Sep 12 11:59:16 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 13 02:59:16 2026 +0800"
      },
      "message": "fix(desktop): carry typed OAuth failure reasons from main-process producers (#4887)\n\nDesktop-owned browser presentation and concurrent-login failures now cross IPC as structured reasons, so renderer copy no longer depends on local English prose. Generic Host conflicts remain unknown because the same code also represents exhausted connection capacity.\n\nGenerated-by: Claude Code\nGenerated-by: Codex"
    },
    {
      "commit": "c1d50256c38b66080013a7ba98414c9a9835a8c9",
      "tree": "c9278b9e3524f13bdedfd6507ebf7a5727074ae1",
      "parents": [
        "6f01fbf710de94c150e17330c797ea5b75fa6686"
      ],
      "author": {
        "name": "NekoPunch",
        "email": "95899648+orangeCatDeveloper@users.noreply.github.com",
        "time": "Sat Sep 12 11:59:08 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 13 02:59:08 2026 +0800"
      },
      "message": "fix(desktop): localize the native file and save dialog titles (#5179)\n\nThe open and save panels carried English titles in every locale, so a zh\nuser picking a reference folder or saving a conversation read the one\nEnglish string on an otherwise translated screen. `All Files` was the\nworst of them: the panel lists it beside the OS\u0027s own localized entries.\n\nFormat names (`Markdown`, `Skill Markdown`, `PNG and JPEG`) stay in\nEnglish — they identify a file format rather than a product concept.\n\nDeletes runtime-host-boot-copy.ts, whose only importer was its own test.\n\nGenerated-by: Claude Code"
    },
    {
      "commit": "6f01fbf710de94c150e17330c797ea5b75fa6686",
      "tree": "fd0d29b7b7f984e1fb83d016ad89ff5423075f82",
      "parents": [
        "e70c97bdb92a53550bb8b92ea3363c4fb7bd30b8"
      ],
      "author": {
        "name": "NekoPunch",
        "email": "95899648+orangeCatDeveloper@users.noreply.github.com",
        "time": "Sat Sep 12 11:59:01 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 13 02:59:01 2026 +0800"
      },
      "message": "refactor(cli): give each command its own help screen (#5181)\n\n`maka --help` printed 110 lines, 62 of them the Runtime Host service,\naccess, plugin and profile surfaces that only an operator installing a\nservice needs. A newcomer asking what the tool does met a wall of\nadministration syntax, and the six option sections meant the root screen\ncarried titles like \"Managed Runtime Host direct-peer options\".\n\nHelp is now layered the way `run` and `activate` already were: the root\nlists the top-level commands and the TUI options in 25 lines, and\n`runtime-host --help` and `runtime-host \u003ccommand\u003e --help` carry what\nbelongs to them. `update --help` gains a screen it never had — it used to\nanswer \"Unexpected argument\".\n\nColumn widths are measured rather than fixed, so a development launcher\n(\"npm run cli:dev --\") aligns like the packaged `maka` name.\n\nGenerated-by: Claude Code"
    },
    {
      "commit": "e70c97bdb92a53550bb8b92ea3363c4fb7bd30b8",
      "tree": "e4914fb91907d8fe26179812695072abe25e4027",
      "parents": [
        "3cce78f75c23858ed387ea2538def0ceb0677a19"
      ],
      "author": {
        "name": "NekoPunch",
        "email": "95899648+orangeCatDeveloper@users.noreply.github.com",
        "time": "Sat Sep 12 11:58:54 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 13 02:58:54 2026 +0800"
      },
      "message": "refactor(desktop): type the main-process copy tables as catalogs (#5178)\n\nFour trilingual tables in the main process were plain object literals, so\na missing locale or a key present in one language only was a runtime\nsurprise rather than a compile error. Declaring the shape and applying\n`satisfies UiCatalog\u003cT\u003e` makes drift a type error, matching the renderer\ncatalogs and the main-process tables that already do this.\n\nNo copy changes.\n\nGenerated-by: Claude Code"
    },
    {
      "commit": "3cce78f75c23858ed387ea2538def0ceb0677a19",
      "tree": "18b097cdccd267cd7a77e434d7d8abd972f22ffe",
      "parents": [
        "9af46ac3c80f5784c901781f75db364f3dff46f7"
      ],
      "author": {
        "name": "NekoPunch",
        "email": "95899648+orangeCatDeveloper@users.noreply.github.com",
        "time": "Sat Sep 12 11:58:06 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 13 02:58:06 2026 +0800"
      },
      "message": "ci: install only the headless Chromium shell (#5187)\n\nThe Storybook smoke always launches headless, and Playwright picks its\nexecutable by headedness, so the full Chrome build was downloaded on\nevery Storybook-selected run and never opened.\n\nGenerated-by: Claude Code"
    },
    {
      "commit": "9af46ac3c80f5784c901781f75db364f3dff46f7",
      "tree": "2aff13a110fc720d203d55b1aa01d1593e14c3a1",
      "parents": [
        "de134f9b1f5b30170b8ed19fb0d3e47bf2571848"
      ],
      "author": {
        "name": "AstroHan",
        "email": "lei.yuhan@outlook.com",
        "time": "Sun Sep 13 02:41:42 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 13 02:41:42 2026 +0800"
      },
      "message": "revert(ci): stop triggering validation on PR edits (#5241)\n\nRevert the PR edit routing introduced in #4186. Restore default pull request triggers and the unconditional required test job.\n\nGenerated-by: Codex"
    },
    {
      "commit": "de134f9b1f5b30170b8ed19fb0d3e47bf2571848",
      "tree": "4c8e040a669cb9a747a94bb3db0db5086b0d10a0",
      "parents": [
        "dc8a2c2da72a43499bfd6515f0c1879919d9f5f3"
      ],
      "author": {
        "name": "AstroHan",
        "email": "lei.yuhan@outlook.com",
        "time": "Sun Sep 13 02:13:47 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 13 02:13:47 2026 +0800"
      },
      "message": "refactor(models): unify connection-scoped model configuration (#5225)\n\nUnify connection-scoped model declarations in the atomic connection catalog with Host-owned projections. Resolve context and input limits independently, keep compaction and reply budgets separate, and share the model editor. Nightly breaking change: schema 2 and compatibility epoch 149; older builds are unsupported.\n\nGenerated-by: Maka\nGenerated-by: Codex"
    },
    {
      "commit": "dc8a2c2da72a43499bfd6515f0c1879919d9f5f3",
      "tree": "ff3307f958f58bd942527b4b9bad6448da04c6f4",
      "parents": [
        "d2e1be5db93101ffcc0fb6a107a0d51764ace28b"
      ],
      "author": {
        "name": "AstroHan",
        "email": "lei.yuhan@outlook.com",
        "time": "Sun Sep 13 02:00:06 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 13 02:00:06 2026 +0800"
      },
      "message": "fix(desktop): preserve session views and defer hidden terminal rendering (#5229)\n\n* fix(desktop): preserve terminal lifetimes across session navigation\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): commit session identity with its loaded transcript\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): preserve git review rows across snapshot refreshes\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): defer hidden terminal rendering\n\nGenerated-by: OpenAI Codex\n\n* fix(legal): include xterm patch license in source distribution\n\nGenerated-by: OpenAI Codex\n\n* refactor(desktop): own conversation display state in the conversation feature\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): retain terminal controls until stop and reconcile retired owners\n\nGenerated-by: OpenAI Codex\n\n* refactor(desktop): recover session-owned terminals from Host\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): preserve terminal recovery across concurrent stops\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): bind session handoff to navigation ownership\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): enforce requested session ownership for async actions\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): own terminal close intent across view lifetimes\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): make transcript publisher type dependency explicit\n\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "d2e1be5db93101ffcc0fb6a107a0d51764ace28b",
      "tree": "ad3a355c81b956eac9ef6a9ece976dc1749e8be1",
      "parents": [
        "12839c18a872b25d2605f1933cf4d2f4c971af28"
      ],
      "author": {
        "name": "Xiao Liu",
        "email": "liuxiao2103@qq.com",
        "time": "Sat Sep 12 23:29:56 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 23:29:56 2026 +0800"
      },
      "message": "fix(desktop): stop credential warning flash (#5020)\n\nKeep normal credential probing in the existing inline loading status and reserve the page-level warning for read failures. Credential-dependent actions remain disabled until a usable credential is confirmed. No persistence or protocol changes.\n\nFixes #5017.\n\nValidated with 18 renderer tests, a failing pre-fix negative control, and light/dark Electron component checks for loading, success and failure states.\n\nGenerated-by: Codex"
    },
    {
      "commit": "12839c18a872b25d2605f1933cf4d2f4c971af28",
      "tree": "2df0b561ab18b636e7936e5634ce5edf27bd7043",
      "parents": [
        "5049ffc1a7780c0b3efd336cde7fe011886d9410"
      ],
      "author": {
        "name": "Xiao Liu",
        "email": "liuxiao2103@qq.com",
        "time": "Sat Sep 12 23:25:33 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 23:25:33 2026 +0800"
      },
      "message": "fix(desktop): keep Side Conversation follow-ups visible (#4901)\n\nKeep Side Conversation follow-ups visible through queue edits, Turn handoffs and reconnects. Use Host execution snapshots and ownership queries as the execution authority, share queue projection with the main conversation, and recover replies outside the transcript window through the existing Host Turn index and bounded paging.\n\nFixes #4900. Enter queues a follow-up; Shift+Enter steers the current Turn. No storage migration or parallel execution authority is introduced.\n\nValidated after syncing main: Desktop build and typecheck, format and lint, 122 focused tests, Windows inventory checks, and real Electron queue/reconnect acceptance. CI and Windows package checks passed.\n\nGenerated-by: Codex"
    },
    {
      "commit": "5049ffc1a7780c0b3efd336cde7fe011886d9410",
      "tree": "d5887b667cf256bae46df49ff9f6f6d34def9cb2",
      "parents": [
        "c0430f6c26f47b2bb70222f09ee6c006d24bc25d"
      ],
      "author": {
        "name": "yum",
        "email": "yang@chihum.dev",
        "time": "Sat Sep 12 22:51:12 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 22:51:12 2026 +0800"
      },
      "message": "fix(desktop): harden the renderer architecture ratchet base comparison (#4584)\n\nFail closed in CI when base-tree analysis or the required base-checker cross-check cannot run. Measure both trees with the base generator while keeping comparison rules in the current checker; preserve diagnostic fallback for local non-strict runs. Cover compatibility and filesystem failures with real-Git fixtures.\n\nRefs #4582.\n\nGenerated-by: Claude Code\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "c0430f6c26f47b2bb70222f09ee6c006d24bc25d",
      "tree": "aed860c639018858f6458c752fa99066f4aabbc8",
      "parents": [
        "c08626bf2e641a6dbe9b6d299203441ae54dd6ba"
      ],
      "author": {
        "name": "AstroHan",
        "email": "lei.yuhan@outlook.com",
        "time": "Sat Sep 12 22:49:54 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 22:49:54 2026 +0800"
      },
      "message": "fix(ui): keep transcript geometry stable during reader input (#5192)\n\n* test(ui): measure transcript geometry ablations (#5184)\n\n* test(perf): compare layout costs in frontend CI (#5184)\n\n* fix(ui): keep transcript geometry stable during reader input (#5184)\n\n* fix(ci): normalize geometry probe ASF headers\n\n* fix(ui): move transcript publication into conversation ownership\n\n* fix(ui): preserve transcript publication action identity\n\n* test(ui): measure history insertion after initial markdown layout\n\n* fix(ui): align publication lifecycle with renderer transcript window\n\n* fix(ui): preserve tail following after stationary edge input\n\nGenerated-by: Codex\n\n* test(ui): synchronize geometry probes with native input settlement\n\nGenerated-by: Codex\n\n* fix(ui): make transcript publication an atomic scroll boundary\n\nGenerated-by: Codex\n\n* fix(ui): retain transcript publication beyond viewport lifetime\n\nGenerated-by: Codex\n\n* fix(desktop): retain stream settlement until transcript publication\n\nGenerated-by: Codex\n\n* test(ui): focus geometry guards and trim experiment diagnostics\n\nGenerated-by: Codex\n\n* fix(ui): hold publication until the last touch ends\n\n* fix(ui): distinguish answer accessibility scopes by conversation context\n\n* fix(ui): preserve literal text in message accessibility labels\n\n* test(ui): allow deferred markdown to settle before accessibility audit\n\n* test(ui): remove geometry story readiness polling\n\n* test(ui): remove redundant synthetic history anchor story\n\n* fix(ui): converge input release through the idle notification gate\n\n* fix(desktop): query current message publication from its owner\n\n* test(ui): align migrated motion story with stable geometry\n\n* test(desktop): remove frame-dependent wheel sampling\n\n* test(ui): wait for restored model picker focus before keyboard input"
    },
    {
      "commit": "c08626bf2e641a6dbe9b6d299203441ae54dd6ba",
      "tree": "a3747ecd36adff9d8497616bd91fe68349fba19b",
      "parents": [
        "f2b6066a6277c02bd6c37b8b64f7841d931461a2"
      ],
      "author": {
        "name": "小七",
        "email": "ggbdpq@gmail.com",
        "time": "Sat Sep 12 22:01:59 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 22:01:59 2026 +0800"
      },
      "message": "fix(desktop,cli): preserve structured-history revision boundaries (#5118)\n\nAllow Desktop editing of a plain-text message when earlier retained turns contain attachments, relying on the existing Runtime Host revision copier to preserve and rewrite those references. Keep unsupported selected-message attachments explicitly rejected.\n\nReject TUI rewind before creating a revision when the selected message carries quotes, attachments, or directory references that the editor cannot restore. Show the corresponding localized notice. No storage migration or compatibility path is introduced; staging selected structured content remains outside this change.\n\nPart of #5109\n\nGenerated-by: GLM-5.3-Flash (ZCode)"
    },
    {
      "commit": "f2b6066a6277c02bd6c37b8b64f7841d931461a2",
      "tree": "5c6bbd31a8ca565e43aadb0ed8906fbcdaed2801",
      "parents": [
        "83aa12a29c57e82bfe807e0913a35a90881cf6d0"
      ],
      "author": {
        "name": "Phoenix",
        "email": "Phoenix500526@163.com",
        "time": "Sat Sep 12 21:05:15 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 21:05:15 2026 +0800"
      },
      "message": "perf(desktop): paginate usage activity (#4539)\n\nLimit Usage Activity rendering to 50 records per page using the existing table pagination support. Keep totals and filtering based on the full dataset, with one pagination reset owner for filter, range, and refresh changes. No storage or API migration is required.\n\nCloses #4531\n\nGenerated-by: OpenAI Codex\nSigned-off-by: Jiawei Zhao \u003cPhoenix500526@163.com\u003e"
    },
    {
      "commit": "83aa12a29c57e82bfe807e0913a35a90881cf6d0",
      "tree": "226881a3aa7eaeb38e8a5110fc81b16b1d8c9f48",
      "parents": [
        "c220ba1f32109b6d9e1ad15bc7effe84b898195e"
      ],
      "author": {
        "name": "WuHaoYang",
        "email": "1425326620@qq.com",
        "time": "Sat Sep 12 19:44:26 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 19:44:26 2026 +0800"
      },
      "message": "fix(ci): run CI when pull requests retarget main (#4186)\n\nRun the existing required CI check when a pull request is retargeted to main. Isolate title/body-only edits in unique concurrency groups and a differently named skipped job so they cannot cancel or satisfy the required test check.\n\nKeep the existing required-check configuration and single workflow authority. Add workflow-policy regression coverage.\n\nFixes #4181.\n\nValidation: 41 exact-head workflow-policy tests passed; required CI passed.\n\nGenerated-by: Codex"
    },
    {
      "commit": "c220ba1f32109b6d9e1ad15bc7effe84b898195e",
      "tree": "24c8719b216ed94e224515abf7d336eca6ae519e",
      "parents": [
        "d92fed919a0a63daa1e576102c723d882d249447"
      ],
      "author": {
        "name": "ying-hua",
        "email": "60057611+ying-hua@users.noreply.github.com",
        "time": "Sat Sep 12 19:07:36 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 19:07:36 2026 +0800"
      },
      "message": "fix(runtime): route DingTalk direct replies by staff id (#5112)\n\nCapture DingTalk conversation type at receipt and route direct replies using senderStaffId. Preserve legacy unstamped group and staff-id delivery targets so existing scheduled tasks keep their routing behavior.\n\nFixes #5111.\n\nValidated by exact-head CI and review of the stamped and legacy routing cases.\n\nGenerated-by: Claude Code (Opus 5)"
    },
    {
      "commit": "d92fed919a0a63daa1e576102c723d882d249447",
      "tree": "67d6b44e41e0a3f5aa66a7d7293edc1558c9c1b2",
      "parents": [
        "5313759080ca34f4fff013c7488e47222a9c4b84"
      ],
      "author": {
        "name": "AstroHan",
        "email": "lei.yuhan@outlook.com",
        "time": "Sat Sep 12 18:54:51 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 18:54:51 2026 +0800"
      },
      "message": "test(desktop): reduce Electron coverage from 41 to 34 tests (#5228)\n\n* test(desktop): move renderer checks out of Electron\n\nGenerated-by: OpenAI Codex\n\n* docs(desktop): define Electron test admission rules\n\nGenerated-by: OpenAI Codex\n\n* docs(storybook): add scoped test tier guidance\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): remove unused settings modal re-exports\n\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "5313759080ca34f4fff013c7488e47222a9c4b84",
      "tree": "744ca65ea80d9e214ec75d9e4beb42e46ca23e55",
      "parents": [
        "ec93b9ca3e1acdb1fc259d9ae495d710d3aef5f4"
      ],
      "author": {
        "name": "小七",
        "email": "ggbdpq@gmail.com",
        "time": "Sat Sep 12 18:25:02 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 18:25:02 2026 +0800"
      },
      "message": "docs: audit the Computer Use documentation group (#5172)\n\n* docs: audit the Computer Use documentation group (#3522)\n\nAudit the nine Computer Use documents against current source:\n\n- foundation-contract: the layer-3 verification description still\n  named apps/desktop/e2e/accessibility-coverage.spec.ts, which #4803\n  retired with the broad route inventories; the section now records\n  that the coverage is carried by the ax-tree-audit rules and the\n  Storybook smoke at their owning boundaries.\n- The other eight documents verified clean: command names and lab\n  fixture variables (evidence-classes), outcome types and the\n  deterministic harness (host-events-contract), the maka_computer\n  action surface and fail-closed coordinate policy (model-loop),\n  provenance paths and bundled-tools pinning (provenance,\n  cursor-provenance), report classes and sanitizer scripts\n  (provider-evidence), and the story manifest (ui-coverage).\n- All nine gain the standard frontmatter with last_verified dates.\n\nRefs #3522\n\nGenerated-by: GLM-5.3-Flash (ZCode)\n\n* docs: correct the Computer Use audit per review\n\nFour follow-ups from the review of the A10 audit:\n\n- foundation-contract layer 3 now says what #4803 actually did: the\n  broad route inventory was retired rather than relocated, nothing\n  enumerates routes against a running Electron app, and layer 2\u0027s\n  ax-tree-audit.mjs runs Storybook-only. The old text claimed\n  equivalent coverage that #4803 explicitly declined to make, and the\n  adjacent \"Storybook 与 Electron E2E 共用\" line said the same thing.\n- ui-coverage: the three prose passages still describing the retired\n  Electron spec (dynamic settings-navigation enumeration, named-dialog\n  overlay sequencing, running-UI inventory) are corrected the same way,\n  so the two documents no longer contradict each other.\n- translation_status is source-only on all nine documents: none has a\n  counterpart, and main\u0027s convention reserves synced for pairs.\n- provenance §3 marks the binary-recovered cursor facts as removed by\n  #3293 (hotspot is now the glyph tip); codex-pip notes that the\n  pip-motion test it cited as exact coverage was deleted by #2478;\n  provider-evidence says four evidence classes; the lease-class list\n  matches computer-use.ts\u0027s four classes; the window-action lesson is\n  annotated with its date.\n\nRefs #3522\n\nGenerated-by: GLM-5.3-Flash (ZCode)\n\n* docs: separate PiP motion provenance from the cursor replacement\n\nReview follow-up on #5172. The audit paragraph attributed the PiP window\u0027s\nmotion constants to the #3293 cursor replacement, but `pip-motion.ts` is\nbyte-identical before #3456, after it, and at this head — the replacement\nrebuilt the agent cursor engine and glyphs, not the PiP springs or anchor\nscoring. The paragraph now says the #2478 deletion only ends the retired\ntest\u0027s coverage, records that the motion module is untouched, and scopes\nthe cursor-provenance link to the agent cursor explicitly.\n\nGenerated-by: GLM-5.3-Flash (ZCode)"
    },
    {
      "commit": "ec93b9ca3e1acdb1fc259d9ae495d710d3aef5f4",
      "tree": "c241c9a2e5de7835284fa08913b2e4a01e90eb9e",
      "parents": [
        "aa3f8e538a0f9460bf52fd7067959a6a67612f78"
      ],
      "author": {
        "name": "Wang",
        "email": "m4n5terrr@gmail.com",
        "time": "Sat Sep 12 18:21:52 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 18:21:52 2026 +0800"
      },
      "message": "feat(desktop): unify magnetic model selection across entry points (#5227)\n\n* feat(desktop): unify magnetic model selection across entry points\n\nUse the WorkHub inline wheel for single-model pickers and apply snapped selections automatically. Keep confirmed WorkHub model revisions authoritative over delayed reads and remove the retired selection state hook.\n\nGenerated-by: OpenAI Codex\n\n* fix(ui): refresh surface inventory for magnetic model picker\n\nRegenerate the tracked Astryx inventory after adding the shared wheel and replacing selector usages.\n\nGenerated-by: OpenAI Codex\n\n* test(desktop): align recovery and WorkHub checks with model wheel\n\nAssert the shared listbox opens from model recovery and remains closed while unavailable. Exercise automatic keyboard selection in the WorkHub story instead of querying the retired menu.\n\nGenerated-by: OpenAI Codex\n\n* test(desktop): verify snapped model identity in WorkHub E2E\n\nWait for the intended row after scrolling, dragging and keyboard navigation, then verify the persisted connection and model ID. Keep display labels separate and update the remaining menu assertion for the shared listbox.\n\nGenerated-by: OpenAI Codex\n\n* test(desktop): check model button focus outlines in settings\n\nInspect the shared model button\u0027s outline instead of the retired Selector wrapper\u0027s border and shadow. Preserve normal and forced-colors focus coverage and remove the obsolete field chrome helper.\n\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "aa3f8e538a0f9460bf52fd7067959a6a67612f78",
      "tree": "02a27d209ddbafaa4f124253024811572511fd32",
      "parents": [
        "8af5612457c64b5c1ec90d44f6b31907f5b82a39"
      ],
      "author": {
        "name": "riba2534",
        "email": "riba2534@qq.com",
        "time": "Sat Sep 12 18:01:04 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 18:01:04 2026 +0800"
      },
      "message": "fix(storage): reject non-directory paths in project add (#5223)\n\nresolveProjectLocation realpath\u0027d the input but never checked\nstat().isDirectory() before Git discovery. A regular file inside a\nrepository reached `git -C \u003cfile\u003e rev-parse`, whose numeric failure is\nnot an invalid-path errno, so the Host coordinator drained with\ncommit_outcome_unknown. Outside Git the same file was registered as an\nunavailable folder project.\n\nReject non-directories with TypeError so register/add treat them as\ninvalid input and the Host stays up."
    },
    {
      "commit": "8af5612457c64b5c1ec90d44f6b31907f5b82a39",
      "tree": "da92cf83d51dd000960a76a88642748b2079e59a",
      "parents": [
        "f4148595d232eb18058c25d86be30f7cb1733f8b"
      ],
      "author": {
        "name": "Mira",
        "email": "hey2missmira@gmail.com",
        "time": "Sat Sep 12 17:56:46 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 17:56:46 2026 +0800"
      },
      "message": "feat(cli): support OAuth login in setup (#4665)"
    },
    {
      "commit": "f4148595d232eb18058c25d86be30f7cb1733f8b",
      "tree": "83ca058571e79bda3b63c4def303942150135209",
      "parents": [
        "d5d7816f33cd6de5a4d938879f2132549c254afc"
      ],
      "author": {
        "name": "AstroHan",
        "email": "lei.yuhan@outlook.com",
        "time": "Sat Sep 12 17:53:07 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 17:53:07 2026 +0800"
      },
      "message": "fix(desktop): derive conversation execution from Host snapshots (#5217)\n\n* docs: define Host-owned conversation lifecycle projection\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): project conversation execution from Host snapshots\n\nGenerated-by: OpenAI Codex\n\n* fix(ui): retain conversation content by Turn through handoff\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): invalidate Side Chat observation readiness on failure\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): complete Host-owned conversation projection migration\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): finish unavailable execution presentation cutover\n\nSeparate observable activity from retained Stop targets in Side Chat and WorkHub. Remove unused snapshot surface and make observation type imports explicit for Knip.\n\nGenerated-by: OpenAI Codex\n\n* test(desktop): assert restored observation failure contract\n\nAllow repeated pending invalidation during failed Host restoration while requiring the observation error and excluding synthetic Runtime events.\n\nGenerated-by: OpenAI Codex\n\n* test(desktop): wait for composer admission before queued sends\n\nScope readiness to the Composer submit control and wait before consecutive queued and steering submissions.\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): complete Host observation and turn handoff boundaries\n\nReconcile the whole live buffer, bind compaction Stop requests to Host turns, invalidate observations when recovery starts, and gate retained activity presentation on current Host observation. Remove unused migration interfaces and place reconciliation in the Conversation feature.\n\nGenerated-by: OpenAI Codex\n\n* chore(desktop): refresh inventory after reconciler move\n\nRegenerate both Astryx surface inventories for the Conversation-owned reconciler path.\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): serialize observation seeding with live updates\n\nDeliver execution and content together through the observation stream and publish readiness only after consumption. Remove invoke seed replay and independent readiness IPC; address initial delivery to registered observers and preserve cancellation and recovery ordering.\n\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "d5d7816f33cd6de5a4d938879f2132549c254afc",
      "tree": "e0a086315a5d3c4f8f7d8454f804465521a89ff6",
      "parents": [
        "85468294798719430a8ddeb5e852eff680379c56"
      ],
      "author": {
        "name": "Dante.Cloud",
        "email": "chinawch_007@163.com",
        "time": "Sat Sep 12 17:44:39 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 17:44:39 2026 +0800"
      },
      "message": "fix(runtime): apply live permission switches before the next tool call (#3615)\n\nFixes #3349.\n\nRoute production permission-only updates through the existing boundary transition so widening can commit during an active Turn or Goal. Read the selected permission mode live at tool dispatch, retaining the Plan overlay and keeping managed sandbox expansions separate from the selected mode.\n\nPreserve the existing quiescent resource transition for narrowing and mixed updates. Retain backend invalidation across preflight, construction, and reservation so the next execution refreshes its composition without stopping the active Turn. No protocol or storage migration is introduced.\n\nVerification: reviewed head 9af9b8c3ab8aeae5bbe131a10c566b43cb02961a; CI tests and Windows packaging passed. Production Host regressions cover ordinary sessions, Goal continuation, permission-sensitive tool calls, and activation races. No new manual Desktop picker acceptance was performed during maintainer review.\n\nGenerated-by: OpenAI Codex\nGenerated-by: ZCode (Z.ai GLM)"
    },
    {
      "commit": "85468294798719430a8ddeb5e852eff680379c56",
      "tree": "90ad9f8c617a3c388f8b3f098571219e679ea1e6",
      "parents": [
        "3d3a85069f7438a867ecc2034d84be7ca445000f"
      ],
      "author": {
        "name": "Dante",
        "email": "duanjl.china@gmail.com",
        "time": "Sat Sep 12 17:42:56 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 17:42:56 2026 +0800"
      },
      "message": "fix(scheduled-task): preserve snoozed occurrence on edits (#5226)\n\n* fix(scheduled-task): preserve snoozed occurrence on edits\n\nGenerated-by: Codex\nSigned-off-by: Dante \u003cduanjl.china@gmail.com\u003e\n\n* fix(scheduled-task): retain pending fire while paused\n\nGenerated-by: Codex\nSigned-off-by: Dante \u003cduanjl.china@gmail.com\u003e\n\n---------\n\nSigned-off-by: Dante \u003cduanjl.china@gmail.com\u003e"
    },
    {
      "commit": "3d3a85069f7438a867ecc2034d84be7ca445000f",
      "tree": "78ff7886d07409243561f482bac27c3e06964382",
      "parents": [
        "3cfcb09fd903bfbf94cbc4684b78c67be616342a"
      ],
      "author": {
        "name": "Dante.Cloud",
        "email": "chinawch_007@163.com",
        "time": "Sat Sep 12 17:36:31 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 17:36:31 2026 +0800"
      },
      "message": "perf(runtime-host): reduce repeated encoding across 16 page builders (#5166)"
    },
    {
      "commit": "3cfcb09fd903bfbf94cbc4684b78c67be616342a",
      "tree": "64a44af22069f1efdfd3c6f9c20f2fb6e345c943",
      "parents": [
        "41da161d6d2aa53c82b2ccf261e519cf09a09b7d"
      ],
      "author": {
        "name": "AstroHan",
        "email": "lei.yuhan@outlook.com",
        "time": "Sat Sep 12 16:43:06 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 16:43:06 2026 +0800"
      },
      "message": "feat(settings): opt in to Code Mode for new tasks (#5219)\n\nEnable opt-in Code Mode for newly created Sessions, preserve frozen scheduled task modes, and separate sandbox execution budget from asynchronous host waiting.\n\nGenerated-by: Codex"
    },
    {
      "commit": "41da161d6d2aa53c82b2ccf261e519cf09a09b7d",
      "tree": "8952ed252b804bbd837899e35f443a610c5695ff",
      "parents": [
        "69a3c060907b6549b3d72643d0cd774422b2b4f1"
      ],
      "author": {
        "name": "Sun-GLiang",
        "email": "81428141+Sun-GLiang@users.noreply.github.com",
        "time": "Sat Sep 12 15:23:54 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 15:23:54 2026 +0800"
      },
      "message": "feat(desktop): install and configure Antigravity ACP (#5164)\n\n* feat(desktop): configure Antigravity ACP through Settings\n\nReuse RuntimePolicy, Host setup operations and OAuth presentation for local macOS arm64 connection checks and Google sign-in. Add process cleanup, setup safeguards and branded Settings UI. Record the official account eligibility blocker for successful-login acceptance.\n\nGenerated-by: Codex\n\n* test: complete Antigravity PR1 acceptance\n\nRecord successful official authentication, restart, retry and process cleanup. Update the local-only operation exclusion assertion and remove an unused public type export found by full repository checks.\n\nGenerated-by: Codex\n\n* feat(desktop): install official Antigravity ACP from Settings\n\nAdd pinned verified downloads through the existing setup lifecycle and proxy configuration. Save managed paths through Settings, retain native selection for existing installs, and simplify the setup layout. Cover download integrity, cancellation, cached reuse and stale configuration; record real installation acceptance.\n\nGenerated-by: Codex\n\n* fix(ci): update Windows inventory for Antigravity installer tests\n\nGenerated-by: Codex\n\n* fix(ci): refresh Astryx inventory for external agent settings\n\nGenerated-by: Codex\n\n* docs: capture current Antigravity setup UI\n\nGenerated-by: Codex\n\n* fix(e2e): wait for WorkHub send readiness before keyboard submission\n\nQueue projection may arrive before the previous send releases admission. Wait for the exact Send control before follow-up and steering keyboard actions.\n\nGenerated-by: Codex\n\n* fix(desktop): allow delayed Antigravity authorization links\n\nKeep setup browser presentation available across initialization and authentication while preserving regular OAuth timing. Record remaining continuous acceptance separately from implementation and CI.\n\nGenerated-by: Codex\n\n* docs: record current Antigravity login and retry acceptance\n\nRecord the user-approved reuse of the verified official program, successful authentication, cancellation of a live process and successful retry. Keep prior installation evidence separate.\n\nGenerated-by: Codex\n\n* fix(desktop): expose existing ACP selection without advanced settings\n\nKeep installation and existing-program selection visible in the Program section. Show path confirmation only after selection, remove the redundant advanced foldout, and refresh current UI screenshots.\n\nGenerated-by: Codex\n\n* refactor(desktop): simplify Antigravity setup surface\n\nGenerated-by: Codex\n\n* test(e2e): wait for WorkHub keyboard admission\n\nThe queue projection can render before the previous send releases admission, so an immediate Enter is ignored. Wait for the exact Send control before keyboard submissions.\\n\\nGenerated-by: Codex\n\n* fix: harden Antigravity setup recovery\n\nRepair damaged managed installs through verified crash-recoverable replacement, clean interrupted staging, classify proxy credential failures, renew active OAuth presentation leases, and guard the post-install Settings write against concurrent configuration changes. Keep acceptance evidence in the PR and correct compatibility history without reusing epoch 143.\n\nGenerated-by: Codex\n\n* fix: restore Antigravity cache permissions\n\nRepair executable modes on verified managed cache reuse, remove the unused OAuth timeout override, and keep the acceptance note limited to observed agent behavior.\n\nGenerated-by: Codex\n\n* test(e2e): await WorkHub resize before dragging\n\nGenerated-by: Codex"
    },
    {
      "commit": "69a3c060907b6549b3d72643d0cd774422b2b4f1",
      "tree": "41d14976dea652e1024b7f39f580534f7424ad92",
      "parents": [
        "05164f5359467a9d00ea144395ab0b9f1f74750c"
      ],
      "author": {
        "name": "Yunpei Zhou",
        "email": "Joob1n@outlook.com",
        "time": "Sat Sep 12 14:37:51 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 14:37:51 2026 +0800"
      },
      "message": "feat(desktop): move a Session between installations from Settings (#5197)\n\nExport a task, and everything the model saw while it ran, to a\n`.maka-session` file -- and import one -- without closing the app.\n\nThe work happens in the Runtime Host because the authority it needs is\nalready held there. The Storage Root owner lock is an election taken with\n`tryLock`, and it refuses a second exclusive hold even inside the process\nthat has one, so the Host cannot reach the export by calling it. It lends\nthe lease instead. Export is fenced with\n`runSessionSubtreeQuiescentMutation` so no Turn starts in the subtree\nwhile the bundle is prepared; import needs no Session fence, because the\nSessions it carries do not exist here yet.\n\nSettings › Import/export tasks gains a switch between the two halves.\nImport keeps the external-agent catalog and adds the bundle file as a\nsource of its own -- a source needs no agent installed, which is also why\na machine with no agent no longer sees an empty page. Export is a tree:\na bundle can be rooted at any node, so every row exports, the nesting\nsays which subtree a row would carry, and a row with descendants asks\nbefore writing them.\n\nRefs #5182\n\nClaude-Session: https://claude.ai/code/session_014ajaRxC4jydavY9nYUFj5J"
    },
    {
      "commit": "05164f5359467a9d00ea144395ab0b9f1f74750c",
      "tree": "5271abb147ed3df889a329adbb5ddfe5e35309cf",
      "parents": [
        "9928de5e4557e150fe9d7133ee4bc5216f57249b"
      ],
      "author": {
        "name": "Shizuina",
        "email": "ekbg3575532@163.com",
        "time": "Sat Sep 12 13:38:53 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 13:38:53 2026 +0800"
      },
      "message": "feat(desktop): accept K/M context window inputs (#5171)\n\nFixes #5168\n\nGenerated-by: OpenAI Codex\n\nCo-authored-by: sunrioa \u003c178722768+sunrioa@users.noreply.github.com\u003e"
    },
    {
      "commit": "9928de5e4557e150fe9d7133ee4bc5216f57249b",
      "tree": "a5a79b258aa49cda2acd72368f3dd024db58f445",
      "parents": [
        "dfcadb497e520b46e8692c2c80f542b9102c9c98"
      ],
      "author": {
        "name": "Yunpei Zhou",
        "email": "Joob1n@outlook.com",
        "time": "Sat Sep 12 13:31:57 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 13:31:57 2026 +0800"
      },
      "message": "fix(storage): require an imported bundle\u0027s context to describe itself (#5196)\n\n* fix(storage): require an imported bundle\u0027s context to describe itself\n\nThree paths M4n5ter raised as non-blocking on #5186.\n\n**A bundle\u0027s context could describe more than the bundle.** The snapshot\nvalidator proves each payload is the bytes its row claims and says nothing\nabout who those rows belong to; the archive digest authenticates the\narchive, not the state inside it. So a bundle that was assembled rather\nthan exported passes both while carrying a reference owned by a Session it\ndoes not include -- which can never be released, because that happens when\nits Session is retired -- or collection state from the workspace it left,\nwhich names a blob the target now references and makes every later\ncollection fail. A fresh target adopts the bundle\u0027s database whole, so\nneither is transient. Both are refused.\n\n**A fresh target received its context database by progressive copy.**\nThat path is the one a Context Store opens to decide whether the workspace\nhas a store at all, so a Store initialising alongside the copy could read\na database only partly there. Staged and renamed, it is absent or\ncomplete.\n\n**A payload path could be a symlink onto matching bytes.** Compared\nthrough an ordinary read it looked like the same content arriving twice,\nand the import accepted a tree the Store will not read -- it refuses to\nread through a link and reports the payload corrupt. The comparison now\nopens no-follow and requires a regular file, so a planted link, or a\ndirectory, is different content rather than the same content.\n\nRefs #5182\n\n* fix(storage): state the portable context shape once, and publish by creating\n\nThree follow-ups M4n5ter raised on #5196.\n\n**One validator, not two.** `validateContextSnapshot` checked payload\nhashes and usage arithmetic; a second, bundle-only check added the\nSession closure. Neither covered the transient state a snapshot settles,\nso a tree could decode and still be unusable: a surviving deletion queue\ndrains bytes the target never had, an unreferenced blob is quota nothing\nreclaims, and a surplus usage row fails that Session\u0027s next write. The\nshape a snapshot writes is now stated in the one place that validates it,\nincluding the Session restriction a bundle needs, and the second check is\ngone -- it could only ever drift from the first.\n\n**Publication creates; it never replaces.** Asking whether the context\ndatabase exists and branching on the answer is a decision that can be\nstale by the time it is acted on: a Context Store initialising under the\nsame lease creates that file, and an import that already decided \"absent\"\nreplaced it. On POSIX the Store then keeps writing to the unlinked inode\nwhile every later open reads the new one, so its writes are invisible and\ngone at the next restart. There is now one publication path -- stage,\nthen `link` -- and the filesystem decides which case it is.\n\n**The collision reader is the repository\u0027s.** `readStableBoundedFile` is\nnon-blocking, so a FIFO planted at a payload path cannot hang the import,\nand it compares the opened file against the path, which is the final-link\ncheck `O_NOFOLLOW` does not give on Windows.\n\nRefs #5182\n\nClaude-Session: https://claude.ai/code/session_014ajaRxC4jydavY9nYUFj5J"
    },
    {
      "commit": "dfcadb497e520b46e8692c2c80f542b9102c9c98",
      "tree": "3cce10a93bccd5b13e7f28a335762a939de935a5",
      "parents": [
        "c05e85e3230b88f1df4abc4c1128cac25f4c39cb"
      ],
      "author": {
        "name": "AstroHan",
        "email": "lei.yuhan@outlook.com",
        "time": "Sat Sep 12 13:15:01 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 13:15:01 2026 +0800"
      },
      "message": "fix(desktop): align rail hover fills and put model config before the enable switch (#5212)\n\nFixes two defects reported from the running app.\n\n- Model rows rendered the enable switch before the 配置参数 trigger. `SettingsExpandableRow` now renders its trigger first and its `afterAction` slot (the switch) last, so the enable toggle is the row\u0027s trailing control.\n- The session rail inset its task rows by 8px, which shifted only the task row\u0027s hover/selected fill (titles already shared one x). The inset is zeroed and the leading status gutter is the same 1rem box as the project row\u0027s folder icon, so both fills and titles sit on one left edge.\n\nNo migration or compatibility impact: rail layout and settings-row control order only, both desktop-side.\n\nGenerated-by: Maka"
    },
    {
      "commit": "c05e85e3230b88f1df4abc4c1128cac25f4c39cb",
      "tree": "096f7e392c0893a5b7e46886979bb937e61d6db4",
      "parents": [
        "96f8e3f93da9b78f5ae7bc5378b62c05a6c31485"
      ],
      "author": {
        "name": "UDY4M",
        "email": "72533078+UncertaintyDeterminesYou4ndMe@users.noreply.github.com",
        "time": "Sat Sep 12 12:55:01 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 12:55:01 2026 +0800"
      },
      "message": "docs(runtime): document subpath-only public API and shared composition entry (#5200)\n\n* docs(runtime): document subpath-only public API and shared composition entry\n\n- State that the public API is the declared package.json exports subpaths;\n  the package root is not exported (import(\u0027@maka/runtime\u0027) fails with\n  ERR_PACKAGE_PATH_NOT_EXPORTED)\n- Add explicit subpath import examples for SessionManager, BackendRegistry,\n  AiSdkBackend, and buildBuiltinTools\n- Point contributors to the shared Runtime Host execution composition\n  instead of the stale apps/desktop/src/main/main.ts entry\n\nFixes #5141\n\n* docs(runtime): simplify composition link to the same-packages relative path\n\nReview feedback on #5200: a reference into a sibling package uses one\n\u0027../\u0027 hop (packages/runtime/ -\u003e packages/runtime-host/...), matching the\nconvention in packages/eval\u0027s README.\n\n---------\n\nCo-authored-by: 陆逊 \u003cjiaxiong.liu@longbridge-inc.com\u003e"
    },
    {
      "commit": "96f8e3f93da9b78f5ae7bc5378b62c05a6c31485",
      "tree": "713c6d8496c9a18a6cfed19dcbf773cc9b075f69",
      "parents": [
        "12d3fb9332602ec7708cc90b2ffda9fd78dfa491"
      ],
      "author": {
        "name": "yzy",
        "email": "80751592+yuzhiyang1@users.noreply.github.com",
        "time": "Sat Sep 12 12:23:49 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 12:23:49 2026 +0800"
      },
      "message": "fix(runtime): project generic tool calls in session trace (#5128)\n\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "12d3fb9332602ec7708cc90b2ffda9fd78dfa491",
      "tree": "0a4c2ec4a278bfee606e85c0097b6843a2a281ce",
      "parents": [
        "89f383970ea2b29392a85ac1088b163766f05076"
      ],
      "author": {
        "name": "AstroHan",
        "email": "lei.yuhan@outlook.com",
        "time": "Sat Sep 12 01:06:35 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 01:06:35 2026 +0800"
      },
      "message": "fix(desktop): route every e2e window reveal through the reveal gate (#5194)\n\n* fix(desktop): route every e2e window reveal through the reveal gate\n\n#4579 resolved a reveal mode for the run — `hidden`, `inactive`, `active` —\nand routed the main window\u0027s own reveal gate and the dock rule through it.\nIt did not reach the windows that other subsystems reveal on their own, so a\nlocal suite run still lost the foreground: a WorkHub summon or dock called\n`show()` + `focus()` on the floating panel and on Desktop, and the startup\nprogress window did the same whenever a Runtime Host handoff asked for\nattention. Those calls sat in `workhub-presentation.ts` and\n`startup-progress-window.ts`, neither of which could see the mode, so the\nauthority existed and simply was not consulted.\n\nThe already-resolved mode is threaded into both — `WorkHubPresentationDeps`\ntakes it from `runtime-host-boot.ts` alongside the main window controller,\nand `createStartupProgressWindow` takes it from `startup-presentation.ts`,\nwhich resolves it for its own branding decision already. The gate\u0027s private\n`focusNow` becomes the exported `focusWindow`, so the reveal-and-activate\nrule stays in `window-reveal.ts` with one implementation; `showWindowInactive`\ncovers the reveals that are deliberately quiet even in the product (WorkHub\u0027s\nprogress card, the startup window\u0027s ordinary appearance) and that only had to\nlearn to stay hidden. No new flag, no second resolution.\n\nProduction is unchanged: `active` still un-minimizes, shows and focuses at\nevery one of these sites, and the progress card still appears without\nactivating. Hosted CI is unchanged too — those runs are `inactive` on Xvfb,\nwhere the window is on screen either way. Only the local foreground behavior\nchanges, and only for a run that already declared itself an E2E run.\n\n`browser-message-box.ts` still reveals unconditionally. It is a modal question\nthe app puts to the user; a run that raises one is blocked on an answer rather\nthan quietly stealing focus, so it keeps the product behavior.\n\nGenerated-by: Claude Code\n\n* fix(desktop): reveal the startup message box through the reveal authority\n\n`presentBrowserMessageBox` finished its load by calling `win.show()` and\n`win.focus()` directly, the last reveal in the main process outside\n`window-reveal.ts`. Two callers reach it before the reveal mode is otherwise\nconsulted: the dev single-instance loser dialog (`shouldShowLoserDialog` does\nnot look at the e2e flags at all) and the fatal-startup diagnostic box. In a\n`hidden` run both put a real window on screen, which is exactly what the rest\nof this PR removes.\n\nThe dialog now takes the mode as part of its appearance and reveals through\n`focusWindow`. `BrowserMessageBoxAppearance` splits into the theme the rendered\ndocument consumes (locale, palette, dark) and the reveal mode, so the HTML\nbuilder keeps its narrow input and every caller of the window path has to\nanswer the reveal question. `main.ts` supplies `startupRevealMode()`, which is\nnow exported: all three of its inputs, `app.isPackaged` included, read\ncorrectly before ready. `runtime-host-boot.ts` supplies the mode it already\nresolved, so its two appearance producers stay theme-only.\n\n`hidden` is the one mode that changes an outcome rather than only a reveal: an\nunrevealed dialog has nobody to answer it, so it settles as its cancel id\ninstead of leaving the caller pending forever — the loser instance would\notherwise never reach its `app.exit`. In production the mode is `active` and\nthe only difference is the `isDestroyed()`/`isMinimized()` guards `focusWindow`\nadds, neither of which can fire on a dialog that was just created and loaded.\n\nThe reviewer also flagged `showInactive()` in cursor-overlay-window.ts,\npip-window.ts and permission-overlay-controller.ts. Those are left alone: no\ncurrent spec reaches them, and an inactive reveal cannot take the foreground,\nwhich is the property this PR defends.\n\nGenerated-by: Claude Code"
    },
    {
      "commit": "89f383970ea2b29392a85ac1088b163766f05076",
      "tree": "8c5c40228b9530a28979b9e8c2e3f9c890d38416",
      "parents": [
        "aeb51db079895f3a8d5d09e1b19df4eae3ae1506"
      ],
      "author": {
        "name": "AstroHan",
        "email": "lei.yuhan@outlook.com",
        "time": "Fri Sep 11 22:17:32 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 11 22:17:32 2026 +0800"
      },
      "message": "feat(desktop)!: give the Renderer the transcript window (#5170)\n\n* refactor(desktop): give the Renderer the transcript window\n\nMain owned the presentation window: a resident range with reading\nanchors, navigation versions, overlay settlement across pages and\neviction bookkeeping, while the Renderer kept its own scroll state on\ntop. Two owners of one window meant every reader gesture met Main\u0027s\nrange accounting, and the reading position existed in six\nrepresentations that had to agree.\n\nMain now keeps a tail cache and answers page requests pass-through.\n`loadBefore` / `loadAfter` return a page without touching the cache,\n`loadAround` and `loadLatest` return a reset snapshot, and catch-up\nevicts whole Turns from the oldest edge while always keeping the newest.\nThe Renderer owns the window: it extends it by pixel bandwidth, trims it\nwith `retain`, and re-opens the edge it trimmed as a gap. `hasOlder` /\n`hasNewer` are Host page cursors on an answer; the Renderer combines them\nwith its own coverage, so paging reaching an end never means nothing\nexists outside the window. `navigationVersion` invalidates navigation\nonly — Session id, replica generation and Host epoch stay independent\nidentity checks.\n\nOverlay settlement follows the same rule. Main used to broadcast\n`completedOverlayMessageIds`, so a window retired an overlay whether or\nnot it installed the durable row that replaced it. A window off the tail\ndeclines tail growth, so it deleted the overlay and dropped the body in\nthe same batch and the Turn vanished from the reader\u0027s view. The catch-up\nbroadcast also filtered its rows through Main\u0027s own tail residency, so a\nrow installed and immediately evicted under budget never reached any\nwindow at all. Retirement is now the window\u0027s own inference — installing\na durable row retires the overlay it settles — and the broadcast carries\nevery row the catch-up read.\n\nThe reading position is one representation: the authority publishes the\nTurn crossing the top of the scrollport, the prompt rail derives its tick\nfrom that instead of running its own observers, and the controller keeps\na bookmark to re-anchor after a replica generation change.\n\nBehavior changes: opening a Session prefetches history until two\nviewports sit above the reader; tail growth marks read while any consumer\nis open, where it previously waited for the reader to have nothing newer.\n\nSupersedes #5147, which patched these symptoms at the old window\nauthority.\n\nCloses #5163\n\nGenerated-by: Claude Code\n\n* test(desktop): measure the reader at transcript range boundaries\n\nThe suite asserted that paging works and stays bounded, and sampled the\nmounted count only once the range had settled. Neither says where the\nreader ended up while a page was installing, which is the whole of what\n#5163 reports. This probe reads every frame, and at each change of the\nmounted range compares a Turn present on both sides: with no input\nbetween two frames its document position must not move, so\n`Delta top + Delta scrollTop` is zero unless the boundary displaced the\nreader.\n\nMeasured settled-to-settled rather than across the changing frames: the\nrange passes through an intermediate commit that mounts far more Turns\nthan it keeps, and scroll anchoring corrects after layout, so a reading\ntaken inside the change reports a correction that never reached the\nscreen.\n\nIt fails on this branch. Pure trims land at 18px; every page install\ndisplaces the reader by about 1800px.\n\nAlso stops asserting `data-search-highlight` after waiting for the jumped\nTurn to mount. That highlight clears itself 2.2s after the command lands,\nso the assertion fails whenever loading the page around the Turn takes\nlonger than the flash - a 3s pass turning into an 18s timeout under load,\nreproduced 2 of 6 runs. The jump\u0027s landing place is read from the reading\nposition instead, which does not expire.\n\nRestores the band-check guard removed in the previous commit. A\ncontrolled comparison over 6 runs each puts the flake at 2 of 6 without\nit and 3 of 6 with it, so the ablation that removed it rested on a single\npassing run and the guard is not what that flake was about.\n\nGenerated-by: Claude Code\n\n* fix(desktop): scope transcript window invalidation to what each read assumed\n\nThe window has five writers — command answers, replica replacements, tail\nbroadcasts, band trims and automatic fills — but only command answers were\ninvalidatable, and the automatic fill borrowed the reader\u0027s own navigation\nchannel. Five reported defects fall out of those two gaps.\n\nA read is answerable only while what it assumed still holds, and the two kinds\nof read assume different things. An extension splices rows onto one edge, so\nany replacement of that edge — navigating away, or the band trimming it out —\nmakes its answer unable to reach what is left; installing it would open a hole\nthe contiguous-window model cannot express and no edge cursor can name. A\nreplacement discards the edges, so only a newer navigation makes it stale, and\na replica replacement that answers nothing this window asked for is admitted\nwhole rather than misfiltered as a superseded command.\n\nFilling an edge is not navigating to it: it gets its own channel, so it no\nlonger consumes the reader\u0027s outstanding jump, and it answers whether the\nwindow moved so a read that changed nothing is not reissued in its own\ncallback, forever.\n\nGenerated-by: Claude Code\n\n* feat(desktop)!: drop the transcript range boundary notice\n\nThe notice told the reader that the window they are reading does not hold the\nwhole transcript, and gave them a button to extend it. Neither is theirs to\ncare about: the window is a memory budget, the band already fills the edge a\nreader approaches, and every arrival and departure of the notice is a height\nchange above or below them with no content behind it.\n\nIt arrived in #4560 without a design decision — the merge\u0027s own before/after\nimages do not show it — and #5147 has since had to exclude it from browser\nscroll anchoring, because a row that is not content was becoming the anchor the\nreader\u0027s position is measured from. Removing it retires that exclusion, the\nrow-projection module whose only job was placing it, its copy in three locales,\nand the whole explicit history-load path it was the only entry point to: the\none navigation a reader still makes is returning to the tail.\n\nRemoving it also exposed a bug it had been hiding. Returning to the tail\ncancelled an outstanding bookmark frame only because the notice\u0027s pending state\nforced a render; without that render the queued frame scrolled the reader back\nto the bookmark they had just left. An explicit pin now outranks a queued\nrestore, which is what the existing regression always claimed to check.\n\nGenerated-by: Claude Code\n\n* chore: drop the retired transcript history pending state from the hook inventory\n\nRemoving the range boundary notice removed the `useState` that held its pending\ntarget; the gate counts call sites, so the inventory has to say 11.\n\nGenerated-by: Claude Code\n\n* chore(desktop): refresh the renderer architecture ledger\n\nThe removals in this branch move every recorded number down, except\n`app-shell-effects.ts`, which grew with the reading-position work.\n\nThe retain callback\u0027s parameter was also named `window`, which shadows the\nglobal and which the scanner reads as an environment capability the shell does\nnot use. Naming it for what it is keeps a phantom capability out of the ledger.\n\nGenerated-by: Claude Code\n\n* refactor(desktop): let the subscription\u0027s lifetime say when a transcript apply is live\n\n`applyTranscript` and `applyReadError` each took an `isDisposed` closure so a\nstable event handler could re-check a flag its caller already knew. Both callers\nknow it locally: the store subscription is torn down in the effect\u0027s cleanup, so\nanything it publishes is live by construction, and the two error paths either\nsit behind the batch callback\u0027s own early return or check the flag where they\nare.\n\nRemoving the indirection takes the file below the debt the ledger recorded for\nit before this branch, so the architecture ratchet passes again.\n\nGenerated-by: Claude Code\n\n* fix(desktop): keep a navigation answerable across a trim of the window under it\n\nThe window has two lifetimes, and the split stopped at the Renderer\u0027s\n`accepts()`. Both leaks let a navigation the reader asked for be dropped.\n\nA replacement admitted its reset batch under the navigation epoch and then\nfailed its own continuation fragments against the window epoch a trim had\nminted meanwhile. The reset now takes the window\u0027s identity back to the epoch\nthe navigation was issued under — it discards the edges those trims were\nprotecting — so the rest of its fragments splice on. Minting moves to a counter\nkept apart from that identity, so a number still names one window forever and a\npage in flight under the trimmed one stays refusable.\n\nMain ordered by a single epoch and read any newer number as \"the Renderer left\nthat window\", which an extension issued after a trim is not: it advanced the\nconsumer and silently discarded the outstanding replacement, even a one-batch\none. Only a replacing command now moves the consumer; an extension naming a\nnewer window is admitted without moving it, and a read stays current while its\nepoch is at least the standing replacement\u0027s.\n\nAlso refreshes the astryx surface inventory, stale since chat-view stopped\nreaching for HStack and Text with the range boundary notice.\n\nGenerated-by: Claude Code\n\n* fix(desktop): release the delivery budget a stranded page answer holds\n\nLetting an extension name a newer window without moving the consumer left the\nqueued answers of the window it left behind in place: they held their bytes in\nthe delivery budget until they were sent and refused, and the opening ramp\nmints an epoch per trim. A consumer could reach its delivery capacity on a\ntranscript nothing was wrong with.\n\nQueued answers are dropped again, now by what the window can still take rather\nthan by whichever number is newest: an extension splices onto the window it\nnamed, so any newer one strands it; a replacement installs its own window, so\nonly a newer replacement does. The same question decides what the delivery loop\nsends, so a page cannot be kept and then discarded unsent.\n\nSizes the scroll suite\u0027s settle wait against the opening ramp rather than the\n10s default, which the suite documents as sized for UI already on screen. How\nmany pages the ramp reads is how tall the viewport happens to be against the\nfixture; this machine finishes it in under two seconds and a loaded CI runner\nmeasured past ten.\n\nGenerated-by: Claude Code\n\n* fix(desktop): give the transcript window one lifecycle and two invariants\n\nThree rounds of epoch patches had left the window with no statable rule about\nwhen a read may be spliced onto it. Adversarial review found two ways to break\nit, both of them mine, and both dissolve once the lifecycle is named.\n\nThe window is in one of two states. Settled: its rows are the window its\nidentity names, so an edge can be read from and its answer spliced back.\nNavigating: a replacement has claimed the window but its rows have not arrived,\nso the edges on screen belong to the window being left.\n\nI1, the window is always contiguous. A read is answerable only while the edge\nit was anchored on is still the window\u0027s edge. An extension may therefore only\nbe issued while settled, and carries the window\u0027s identity; a replacement\ncarries its own, and all of its fragments belong to it however many epochs the\nband mints underneath. Installing a replacement names the window afresh, which\nrefuses every read that was anchored on an edge it threw away. Filling while\nnavigating anchored on the window being left and spliced onto the one that\nreplaced it — a hole no edge cursor can name and no later page can fill. Now\nthere is nothing to anchor on, so nothing is asked.\n\nI2, a fill does not spin. A read that left an edge exactly where it found it\nanswers the same way again, so the range keeps where each edge stood and\nrefuses to re-ask until something moves it. This replaces the `moved` answer\n`prefetchHistory` reported back to the scroll hook, which asked the geometry to\ndecide whether a read was worth issuing: it read the store\u0027s snapshot identity,\nwhich a Session streaming into its tail changes on its own, so the guard was\nblind exactly when it was needed. Deciding whether a read is worth issuing\nbelongs to the layer holding the window.\n\nMain keeps a single number again. Which window the Renderer holds is not\nderivable from the epochs Main sees and does not need to be — the Renderer\nrefuses what it cannot splice. The monotone `newestWindowEpoch` of the previous\ncommit claimed to derive it and got it wrong: once a navigation\u0027s answer landed\nit stranded every later fill, leaving the older edge unable to load for the rest\nof the Session.\n\nAlso drops the gap-row assertion the perf suite still made against a row deleted\nwith the range boundary notice, and the two dead gap measurements beside it.\n\nGenerated-by: Claude Code\n\n* test(desktop): tell the displacement probe when the reader\u0027s hand is on the wheel\n\nThe probe skipped frames within 250ms of the last wheel event, on the theory\nthat a reading which catches a tick cannot tell the reader\u0027s own scrolling from\na page that moved them. The gesture and the rAF that reads it land in the same\nframe in an order nothing here controls, so on a loaded runner the reading went\nfirst and the guard was still holding the previous gesture\u0027s timestamp: eight\nboundaries reported displacement of exactly 120px, one wheel tick, where this\nmachine reported none.\n\nA time window cannot fix that, because the quantity it is inferring — whether\nthe reader is mid-gesture — is something the test already knows. It now says\nso: the measurement window closes around each gesture and opens for the quiet\nthat follows, which is where a page lands and where a reader would see it jump.\n\nGenerated-by: Claude Code\n\n* chore(desktop): keep hand-written e2e drivers out of the tree\n\nThrowaway drivers for investigating a scenario by hand have to sit beside the\nsuite to resolve `@playwright/test`, and four of them reached a commit here,\nwhere the ASF header audit correctly refused them.\n\nGenerated-by: Claude Code\n\n* fix(desktop): drop the retired fill answer from the app-shell stories\n\nTwo stories still answered `onPrefetchHistory` with whether the window moved,\nwhich the range controller now decides for itself.\n\nGenerated-by: Claude Code\n\n* refactor(desktop)!: make the transcript window an anchored immutable value\n\nThe Renderer owned the window but kept Main\u0027s mutable structure without\nthe serial queue that had made it consistent. Four writers — jump, fill,\ntrim and tail broadcast — mutated it in place across processes and rAF\nframes, and a monotone window epoch stood in for the transaction the\nstructure never had. Three holes followed from that shape, each found\nindependently by review and by Totoro-qaq\u0027s probes: a tail change lost\nin Main\u0027s delivery loop left the window believing it still reached the\ntail, so the next row spliced onto a gap; `#reset()` forgot to mint and\nleft `#navigating` set; and a jump snapshot carried the whole overlay\ninto a parked window, whose settlement then installed the durable row\nfar from anything it held.\n\nDurable sequences advance by a stride, so adjacency cannot be read off\nthe numbers. The only proof that rows are contiguous is the Host read\nthat produced them, anchored on a known row or watermark. The window is\nnow an immutable value and every answer carries its anchor: a page names\nthe edge it was read from (`extends`), a tail change names the watermark\nit read forward from (`coversFrom`), and a reset names the navigation it\nanswers. Rows land only where the anchor is still the window\u0027s edge;\nwatermark and overlay retirement land regardless, because they are facts\nabout the tail, not the window. Batches assemble off-window and install\nonce at `ready`, so the screen never shows half an answer and no\nnavigating phase or fill barrier is needed.\n\n`coversFrom` has three states: a number or `null` (read from the start\nof the transcript) is a contiguity claim; absent is none. Main\u0027s merge\ndrops rows and clears the claim when consecutive changes do not meet,\nand the delivery loop no longer cuts an answer short mid-stream. A\ndropped increment therefore degrades to a watermark the window cannot\njoin, which sets `hasNewer` and lets the band read forward from its own\nedge — Main\u0027s navigation number is now only the cancellation hint the\nold comment claimed it was.\n\nThe overlay leaves the window. It is shown only while the window reaches\nthe tail, which retires both entrances the escape hatch had: a jump\nsnapshot\u0027s overlay in a parked window, and a trim that opened the newer\nedge without dropping it. The parked-window settlement test encoded that\nhatch and is rewritten to the new contract; Totoro-qaq\u0027s probes are\nadopted as regressions.\n\nFills report whether they issued a read, and the scroll hook re-checks\nonly when one did: the previous \"cannot spin\" claim was false, since a\nrefused fill resolved synchronously and re-entered the check.\n\nAblation considered and rejected: pull-only tail delivery (watermark\nwithout rows) would flip `hasNewer` on every Turn completion and hide the\nstreaming overlay for a round trip each time. The push stays, verified.\n\nGenerated-by: Claude Code\n\n* chore(desktop): refresh the renderer architecture ledger\n\n`app-shell.tsx` gained one token: the prefetch fallback now resolves to\n`false` so the scroll hook knows no read was issued.\n\nGenerated-by: Claude Code\n\n* fix(desktop): move the tail watermark with every catch-up page\n\n`#catchUp` installed rows page by page but only set `#durableThrough` at\nthe end, so a window opening between pages took a snapshot whose rows\nreached further than the watermark it named. The next tail change was\nanchored on the real watermark, which no longer matched the window\u0027s,\nso the anchored window refused it and reported `hasNewer`. The main\nshell reads forward and recovers; WorkHub offers no newer fill, so its\nview stayed behind, the queued follow-up it was waiting to observe never\narrived, and a second follow-up was refused as a retry\n(`workhub-layout.spec.ts`, \"keeps the submitted prompt visible\"). The\nepoch model had masked this by splicing tail rows whenever the window\nbelieved it was at the tail.\n\nGenerated-by: Claude Code\n\n* fix(desktop): bring the app-shell stories onto the Renderer-owned window\n\nThe storybook smoke had never run against the new window model: every CI\nrun on this branch had failed earlier in the same job. Five stories were\nstill written against the contract the window refactor replaced.\n\nTwo encoded the old rule that the tail never asks for history on its own.\nThe band now fills two viewports above the reader when a Session opens,\nso `TailFollowDoesNotAskForHistory` becomes\n`TailPrefetchesHistoryUntilTheBandIsFull`, and\n`AWheelTheScrollerCannotActOnAsksForHistory` goes: a transcript short\nenough for the wheel to be the only signal no longer exists, the band has\nalready asked before the wheel arrives.\n\nTwo rail stories relied on the old rail aiming its own jump. The rail now\nderives its tick from the scroll authority and a rail jump lands through\nthe scroll target that `createSessionOpenCommand` publishes, so the story\nharnesses gain that half of the production seam. The rail itself learns\none rule the stories already asserted: pinned to the tail, the active tick\nis the newest Turn, not whichever Turn crosses the top of the scrollport.\n\n`PartialHistoryNotice` crashed React with `Invalid array length`: its fill\nanswered `true` for a window it had already read and resolved before\nlayout, so the band\u0027s chained re-check ran in the same microtask, saw the\nsame geometry, and asked again until React\u0027s update queue could not grow.\nThe harness now answers the way the Host\u0027s range controller does — `false`\nfor a window it has read, and a frame later otherwise.\n\nGenerated-by: Claude Code\n\n* test(ui): scroll the rail reading-position probe as a reader\n\n84b1f0564 made the rail\u0027s active tick the newest Turn while the scroll\nauthority is pinned to the tail. This probe moved `scrollTop` with no\nreader gesture, so the authority never released the pin and the rail,\ncorrectly, stayed on the newest Turn. The probe now asserts that rule at\nthe tail, then wheels before it scrolls, which is what a reader leaving\nthe tail looks like to the authority.\n\nGenerated-by: Claude Code\n\n* fix(ui): re-check the transcript band when the viewport resizes\n\nThe band is measured in screens of the scroller\u0027s own height, but its\ncheck ran only on reader input and message changes. A resize with the\nreader and the messages standing still redefines the band and reached\nnothing: enlarging the viewport left a fillable edge unfilled and\nshrinking it left a trimmable range retained until the next gesture.\nThe authority is not a substitute signal — it publishes only when its\nsnapshot changes, and a resize that keeps the pin and the reading Turn\nchanges nothing it publishes — so the band observes the root\u0027s size\nitself.\n\nTwo regressions drive a resize alone: growing the scroller issues one\nolder fill, shrinking it retains the band around the reader.\n\nGenerated-by: Claude Code\n\n* fix(desktop): mark the tail read only when the Renderer window reaches it\n\nThe window refactor deleted Main\u0027s window authority but left one of its\nconsumers behind. The read marker used to advance on `!change.hasNewer`,\na fact Main derived from the window it owned; with the window gone Main\nadvanced it whenever a consumer existed, so a reader parked in history\nhad every completing Turn marked read without having received a row of\nit. Restoring the old condition is not possible — Main no longer knows\nwhere the window ends — and guessing from delivery is unsafe: a change\nwhose `coversFrom` meets the last acknowledged watermark still fails to\njoin if a trim lands between the two.\n\nThe owner reports the fact instead. The Renderer window acknowledges\neach new watermark it reaches with `hasNewer` false, once per value and\nnever while parked or serving a cached generation; Main records it per\nconsumer and marks read only when the acknowledged watermark has reached\nthe replica\u0027s own. Opening a Session at the tail acknowledges through the\nsame path, so opening still marks read; delivery and open no longer do so\non their own.\n\nRegressions: a consumer parked off the tail sees the durable transcript\nadvance and the marker stays; acknowledging the current watermark moves\nit. The controller acknowledges once per watermark and nothing while\n`hasNewer`.\n\nGenerated-by: Claude Code\n\n* fix(desktop): read the tail back before answering return-to-latest\n\n`loadLatest` answered from Main\u0027s tail cache. Global memory reclaim can\ntrim that cache to nothing while the Session stays open, so returning\nto the latest messages could install an empty window with `hasNewer`\nfalse — a blank conversation, and no affordance left, until the band\u0027s\nolder prefetch refilled it. On `main` the follow-tail command read a\nfresh page from the Host.\n\nThe tail is read back before it is replayed: when the cache holds fewer\nTurns than it should and older rows exist, `loadTranscriptLatest` reads\nthe newest page from the Host into the cache, then answers through the\nexisting reset path with the watermark the cache already names. A cache\nthat covers the whole transcript is not short, so a small Session still\nanswers without a read. Reclaim keeps trimming; it is a performance\nevent again, not a correctness one.\n\nGenerated-by: Claude Code\n\n* fix(desktop): keep the reader\u0027s place across a Host epoch change\n\nSequences name the same rows only within one Host epoch, so the\ngeneration-change re-anchor stopped at an epoch change and a reader\nparked in history was dropped at the tail when the Runtime Host\nrestarted. On `main` the registry rewrote the outstanding navigation by\nTurn id. The Renderer now does the equivalent with what it already has:\nafter an epoch change it refreshes the Turn landmark index, resolves the\nbookmarked Turn id to its new sequence and navigates there; a Turn the\nnew index does not know leaves the reader at the tail, quietly.\n\nA read still in flight across that change was rejected by Main as a\nstale epoch, and the rejection reached the conversation as a load error\nfor a condition the reset that follows resolves by itself. The\nrecovering controller now raises that rejection as a superseded read;\nthe reading-position layer treats it as neither an error nor an\nunavailable bookmark, so the banner does not appear and the bookmark\nsurvives for the re-anchor above. Every other error is still raised.\n\nGenerated-by: Claude Code\n\n* fix(desktop): give the WorkHub transcript the pixel band\n\nWorkHub mounts the same ChatView as the chat surface but was wired\nwithout the band: no automatic fill, no trim, an explicit \"older\"\nbutton instead. Two consequences of the Renderer-owned window followed.\nEvery page the button loaded was retained forever, where Main used to\nbound every consumer\u0027s window. And a window behind the tail never\nfollowed it — Main used to splice tail growth into whatever window it\nheld — so a queued follow-up\u0027s own row never arrived, the observation\ncheck never satisfied, and the next follow-up was refused as a retry.\n\nThe WorkHub transcript port now carries `prefetchHistory` and `retain`,\ndelegated to the same range controller the chat surface uses, and the\nChatView gets the band\u0027s callbacks. The \"older\" button goes with it.\nQueuing a follow-up returns the window to the tail before admission, on\nevery admission outcome, so the queued row lands and the guard clears.\nA trim publishes the trimmed snapshot: it is the one window change with\nno batch behind it.\n\nGenerated-by: Claude Code\n\n* refactor(desktop): drop transcript window state nothing reads\n\nThree mirrors of state that already lives somewhere else, each written\nand never read back.\n\n`PendingTranscriptPage.replaces` was queued alongside every page answer.\nIts strongest case was that it names the same thing as\n`#admitTranscriptNavigation(request, targetId, replaces)`, so it reads\nlike that concept persisted; but that argument is an input consumed at\nthe call site, and the delivery loop only ever looks at `navigation` and\n`generation`.\n\n`DesktopTranscriptReplicaSnapshot.navigation` was a Renderer concept on\na Main type the replica never sets: the only writers were the observer\u0027s\ntwo `{ ...snapshot, navigation }` spreads. It looked load-bearing because\n`encodeDesktopTranscriptSnapshot` needs a navigation, but what the\nencoder needs is `TranscriptBatchIdentity`\u0027s field, which a second\nparameter supplies. The field also reached the local transcript cache,\nwhich stored it permanently undefined.\n\nThe controller\u0027s `lastNavigation` was identical to the store\u0027s\n`#navigations` by construction — same initial value, incremented only in\n`navigate()`. The extension path needs \"the navigation the window sits\non\" once a pending answer has landed, but that is the store\u0027s own state;\nit now answers for it through a one-line `navigation()` getter.\n\nGenerated-by: Claude Code\n\n* refactor(desktop): publish WorkHub transcript snapshots from the store\u0027s commit\n\nWorkHub delivered window changes over a second, hand-maintained path: a\n`handler(store.snapshot())` inside the batch callback, plus a second one\ninside `retain` guarded by a `trimmed` flag, with a comment explaining\nthat a trim is the one window change nothing else delivers. That comment\nwas the tell — the store already has a single channel that covers both\nentry points, `#commit()` behind `subscribe()`, which is how app-shell\nhas always been wired. Two hosts of the same store were kept consistent\nby hand instead of by construction.\n\n`store.subscribe(() \u003d\u003e handler(store.snapshot()))` puts the callback\nshape the port wants on top of that one channel, so the trim special\ncase and its `cancellation.aborted` re-check go with it. The\nsubscription is torn down both on `close()` and on the cancellation\nsignal, which is what made the extra guard redundant. It is also\nstrictly safer: the old `|| batch.ready` branch could call\n`store.snapshot()` before any reset had installed a range, where\n`range()` throws.\n\nThe two `if (!store.accepts(batch)) return;` guards in front of\n`store.accept(batch)` went too, and `accepts` is now private. `accept()`\ncalls it first and returns false without decoding anything, so the guard\nonly ran the same test twice. It did not even cover the one case where\nthe two differ — a reset for another Session, which `accept()` throws on\nand `accepts` admits.\n\nGenerated-by: Claude Code\n\n* refactor(desktop): let the read-marker gate stand alone\n\n`consumer.acknowledgedThrough` mirrored, per consumer, a deduplication\nthe Renderer already does: the window reports a watermark once, and only\nwhile it is actually at the tail. The case for keeping it was that the\nRenderer is not trusted, so a repeated acknowledgement would re-write the\nread marker.\n\nIt does not hold. The write is idempotent twice over — `#markTranscriptRead`\ngoes to `setSessionReadMarker`, and the Host\u0027s catalog coordinator\ndeclines a marker equal to the one it already holds. The field was\nper consumer, so two windows on one Session each acknowledged and each\ntriggered a marker anyway; it never bought \"once per Session\". And a\nwatermark that goes backwards was never its job: `request.through \u003c\ndurableThrough` rejects that, and stays.\n\nGenerated-by: Claude Code\n\n* refactor(desktop): name the transcript epoch-changed rejection once\n\nMain threw `\u0027Desktop transcript host epoch changed; reopen the\ntranscript\u0027` and the Renderer recognised it with\n`message.includes(\u0027Desktop transcript host epoch changed\u0027)` — the same\nliteral written twice, on either side of `ipcRenderer.invoke`, where\nediting the prose on one side silently reclassifies the rejection on the\nother.\n\nThe reason given for leaving it as prose is that invoke carries only a\nmessage and no type channel. True, and already solved elsewhere in this\napp: `SESSION_WORKSPACE_UNAVAILABLE_CODE` is an exported constant that\nboth the thrower and the matcher name, matched as a `CODE:` message\nprefix. `DESKTOP_TRANSCRIPT_HOST_EPOCH_CHANGED_CODE` in\n`preload/transcript-contract.ts` does the same for this one; both sides\nalready import that module.\n\n`TranscriptReadSupersededError` stays. Making Main silently no-op\ninstead is not equivalent: `restoreSessionTranscriptRange` reads\n\"succeeded but the Turn is not in the window\" as a dead bookmark and\nclears the anchor, which would break re-anchoring across an epoch\nchange. Superseded has to remain a distinguishable outcome.\n\nGenerated-by: Claude Code\n\n* refactor(ui): report reader scroll by phase only\n\n`subscribeToReaderScroll` broadcast `(direction, phase)`. Before this\nbranch the direction had a real consumer: `use-chat-scroll` decided\nwhether to request history with `canLoad(direction) \u0026\u0026\nnearEdge(direction)`. Moving that decision into the pixel band\u0027s own\ngeometry left both production subscribers ignoring the parameter — one\ntakes only `phase`, the other takes nothing — with the argument surviving\nin the contract, in `reportReader`, and in a story.\n\nThe authority does still compute a direction, which is the case for\nkeeping it. But that direction serves the pin decision at scrollend; it\nis not something a subscriber was using, and a subscriber that wanted\none could recompute it from geometry, as the band now does.\n\nGenerated-by: Claude Code\n\n* test(desktop): give the teardown fakes the transcript window contract\n\nThe transcript window work added `acknowledgeTranscriptTail` and\n`loadTranscriptLatest` to the source `openTranscript` requires, so the\nteardown fakes landed on main with five of the seven methods. Against this\nbranch `requireTranscriptSource` rejects them, `openTranscript` throws before\nthe fake ever runs, and the `started` deferred these tests await never\nresolves — the file hangs to the 900s timeout instead of failing.\n\nGenerated-by: Claude Code\n\n* fix(desktop): release a transcript registration whose source is unavailable\n\nopenTranscript registers the consumer, then called requireTranscriptSource\noutside the try. A source missing any transcript method therefore threw past\nthe cleanup every other failure takes: the registration stayed in the map and\nits `ready` promise never settled, so the consumer id was permanently burned\nand anything awaiting readiness hung. #restoreTranscript already made the\ncheck inside its try; this makes the open path agree.\n\nRegression: `releases a transcript registration whose source lacks the window\ncontract` attaches an observe-only source and asserts both that the open\nrejects and that the registration is gone — reusing the consumer id reaches\nthe same failure instead of the duplicate-identity guard. Verified to fail\nwith the check moved back out.\n\nGenerated-by: Claude Code\n\n* refactor(desktop): drop the navigation wrapper and the surface\u0027s pass-through props\n\nA one-field interface around a sequence number bought nothing: the preload\nunwrapped it on the IPC boundary and both the wire request and the batch\npayload already declared `navigation` bare, so the wrapper existed only to\nbe built and taken apart again. Pass the number.\n\nChatMessageSurface re-declared and re-passed four ChatView props that its\nown props type already inherits and `...chatViewRest` already forwards.\nRemoving the duplication keeps them required by naming them through\n`Required\u003cPick\u003c…\u003e\u003e` rather than relying on the surface\u0027s own optionality.\n\nGenerated-by: Claude Code\n\n* fix(desktop): acknowledge the transcript tail only for a visible reader\n\nThe transcript range controller wired tail acknowledgement to every\nconsumer that reached the tail. readDelegatedTurnResult() opens one only\nto compute a bounded WorkHub result preview and never renders it, so a\ndelegated Turn with later durable rows had its Session marked read —\nreturning the target preview while clearing unread state nobody saw.\n\nAcknowledgement is now an explicit property of a reader that renders the\ntranscript: the plain controller stays silent unless asked, and the\nrecovering controller — which every visible reader uses and no projection\ndoes — is the single place that asks. The projection cannot opt in by\naccident.\n\nRegression: `delegation feedback does not advance the target Session read\nmarker` drives delegationFeedback against a handle that records\nacknowledgeTail, with a later Turn beyond the delegated one.\n\nGenerated-by: Claude Code\n\n* chore: trim comments and test scaffolding the transcript window PR added\n\nComments that restate the code they sit on, pin a number nothing\nre-verifies, or repeat a sentence the contract already carries do not\nsurvive the next edit intact, and a stale one is worse than none. Keep\neach statement where the contract lives and delete the copies.\n\nThe parked-completion probe asserted only what the range-store suite\nalready proves; its live overlay row now carries an assertion of its own —\nverified to fail both when the coversFrom check is dropped and when the\noverlay settle is.\n\nAlso: e2e assertions against selectors no product code emits, a local\n`deferred` the shared test-only helper replaces, a private method that only\nforwarded to a generic one, and a probe value threaded through ten sites to\nfeed an assertion that proved nothing.\n\nGenerated-by: Claude Code"
    },
    {
      "commit": "aeb51db079895f3a8d5d09e1b19df4eae3ae1506",
      "tree": "120cd4bf9d6639c3ef3087f19549f005890c4a23",
      "parents": [
        "0b7bf39f4935dffd370389eb5e4926ebb7856246"
      ],
      "author": {
        "name": "Dante",
        "email": "duanjl.china@gmail.com",
        "time": "Fri Sep 11 20:22:19 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 11 20:22:19 2026 +0800"
      },
      "message": "fix(runtime-host): bound sparse transcript continuations (#5188)\n\nGenerated-by: Codex"
    },
    {
      "commit": "0b7bf39f4935dffd370389eb5e4926ebb7856246",
      "tree": "a1b5aef57cddfeda2d372373cd4ac89f355157b7",
      "parents": [
        "a57b4e866cb74fad1d0801d5ff3ff2cafaec99c6"
      ],
      "author": {
        "name": "Wang",
        "email": "m4n5terrr@gmail.com",
        "time": "Fri Sep 11 19:08:40 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 11 19:08:40 2026 +0800"
      },
      "message": "perf: incremental memory optimization across Maka (#5153)\n\n* perf(desktop): defer unused WorkHub and bot SDK initialization\n\nCreate the WorkHub renderer on first use rather than on enable, while retaining drafts after use. Load platform SDKs only when a configured bot starts or Slack credentials are tested.\n\nGenerated-by: OpenAI Codex\n\n* fix(ui): release attachment previews when composers unmount\n\nTrack Blob URL ownership before decode and stop asynchronous staging after unmount while preserving hidden drafts and StrictMode replay.\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime-host): compact completed message replay identities\n\nRetain canonical content digests instead of historical submit and queue edit bodies, without evicting epoch-long outcomes or changing pending operations.\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): cancel completed display frame fallback callbacks\n\nCancel the losing animation frame or timeout after a stream display batch flush, preventing suspended background frames from retaining completed handlers.\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime): release retired graph epoch reconciliation snapshots\n\nFence old supervisor callbacks and preserve explicit reconcile readers across epoch handover. Retain lightweight driver metadata for historical projection repair and close diagnostics.\n\nGenerated-by: OpenAI Codex\n\n* fix(runtime-host): detach transcript preparation close listeners\n\nReplace connection-lifetime Promise races with removable abort listeners so released transcript overlay buffers can be collected while the connection remains open.\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): bound browser release fencing to pending acquires\n\nDrop per-session release epochs when connection attempts settle and avoid retaining tombstones for sessions that never acquired a browser, preserving reentrant teardown and single-flight fences.\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime-host): compact historical root admission bodies\n\nRetain canonical content digests and owned identity metadata for historical admissions while keeping full current tips and validated recovery or conflict results.\n\nGenerated-by: OpenAI Codex\n\n* test(runtime-host): close admission fixture stores before cleanup\n\nRelease the SQLite lease before removing temporary files so root admission tests clean up on Windows and do not retain fixture database owners.\n\nGenerated-by: OpenAI Codex\n\n* perf(desktop): release activated subscription preparation roots\n\nGenerated-by: OpenAI Codex\n\n* refactor(desktop): move display scheduling into conversation ownership\n\nKeep frame cleanup within the renderer architecture boundary without widening legacy budgets.\n\nGenerated-by: OpenAI Codex\n\n* perf: release Zod recursive parse state after completion\n\nKeep cycle memoization scoped to each parse and restore allocation state when parsing throws.\n\nGenerated-by: OpenAI Codex\n\n* docs: record Zod patch source license\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime): release processed WeChat SSE payloads while idle\n\nKeep iterator result and decoded message lifetimes within each completed read. Preserve reconnect cursors, parser boundaries and iterator cleanup semantics.\n\nGenerated-by: OpenAI Codex\n\n* fix(peer): bind WebRTC workers to connection lifetime\n\nCancel connection-owned channel workers and close the native peer on explicit close, unpolled muxer drop and failed or aborted upgrades. Keep successful connection lifetime separate from signaling-attempt cancellation.\n\nGenerated-by: OpenAI Codex\n\n* perf(desktop): release delivery records during retry waits\n\nKeep retry callbacks outside the delivery lexical context so pending or completed attempts do not retain parsed message bodies for the five-second retry interval. Preserve durable intents, timer behavior, and replay identity.\n\nGenerated-by: OpenAI Codex\n\n* perf(peer): cancel obsolete reconciliation timers\n\nOwn the five-minute timer and abort listener in each reconciliation wait. Early public triggers release both immediately while normal expiry and endpoint shutdown still wake the loop.\n\nGenerated-by: OpenAI Codex\n\n* test(desktop): scope POSIX mode assertion to supported platforms\n\nKeep local restart and retry assertions running on Windows without equating stat mode bits with ACL permissions. Production permission handling is unchanged.\n\nGenerated-by: OpenAI Codex\n\n* fix(ui): avoid retaining messages through unknown code languages\n\nGenerated-by: OpenAI Codex\n\n* fix(cli): release completed event waiters\n\nGenerated-by: OpenAI Codex\n\n* fix(cli): share immutable text across editor undo snapshots\n\nCopy mutable editor state and paste maps without deep-cloning each stored paste for every typed word. Preserve all undo steps and cover public editing, paste renumbering, and retained heap growth.\n\nGenerated-by: OpenAI Codex\n\n* perf(core): bound Unicode truncation allocations\n\nCollect only the code-point prefix needed for nonnegative budgets while preserving cleaning and numeric slice semantics. Cover transient allocations and Unicode behavior with regression tests.\n\nGenerated-by: OpenAI Codex\n\n* perf(core): bound diagnostic truncation allocations\n\nPreserve complete redaction and byte-budget semantics while limiting temporary code-point arrays and UTF-8 encoding to the useful prefix.\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime-host): release consumed peer receive buffers\n\nGenerated-by: OpenAI Codex\n\n* perf(ui): defer reasoning bodies until first expansion\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime): detach truncated web search result text\n\nGenerated-by: OpenAI Codex\n\n* perf(desktop): load update attestation dependencies on demand\n\nKeep startup channel metadata free of Sigstore and TUF module graphs. Load the parser and verifier only when an update is actually verified, preserving fail-closed trust checks.\n\nGenerated-by: OpenAI Codex\n\n* fix(runtime): preserve cancellation through request customization\n\nForward the caller\u0027s effective AbortSignal instead of a temporary Request\u0027s GC-sensitive derived signal. Preserve explicit null, inherited and overriding signals on every body path, and cover prompt native HTTP cancellation after GC.\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime): reuse buffered JSON request bodies\n\nDecode the bytes already read for request customization instead of cloning and reading the complete body twice. Preserve the original read boundary, stream error identity, caller locks and cancellation semantics.\n\nGenerated-by: OpenAI Codex\n\n* perf(computer-use): scope session cleanup metadata to live work\n\nAvoid allocating unknown-session state during ordinary cleanup. Retain cancellation generations only while queued operations own them, preserving same-turn stop authority and executor-release fencing.\n\nGenerated-by: OpenAI Codex\n\n* fix(runtime-host): release uploads rejected after session removal\n\nRelease only connection-owned staging in the existing missing-session rejection path. Preserve response and TTL contracts while preventing failed commit and cleanup requests from retaining completed upload buffers.\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime-host): release retired Goal token metadata\n\nScope cached token totals to the existing Goal control lease so late context reads cannot repopulate retired entries or overwrite a new Goal. Delete only after committed retirement and clear during drain, retaining rollback and close fences.\n\nGenerated-by: OpenAI Codex\n\n* test(runtime-host): close Goal fixture execution stores\n\nRelease SQLite execution-store handles before removing temporary roots. Covers the new lifetime regressions and existing Goal coordinator tests that reproduced the same Windows EBUSY failure on pre-fix production source.\n\nGenerated-by: OpenAI Codex\n\n* perf(mcp): release settled request graphs behind blocked sends\n\nScope cancellation error observers independently and revoke the pending send observer\u0027s native rejection reference when the request settles. Preserve queued frames and late error handling in both SDK module formats.\n\nAllow the required unified-diff context prefix before upstream tabs while retaining other patch whitespace checks.\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime-host): share identical turn skill inventories\n\nReuse only fully equal frozen snapshots after each fresh catalog read. Preserve per-turn historical state, the 100-entry FIFO and failed-read retry behavior, and prevent evicted late reads from adding retention.\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime-host): share identical completed prompt text\n\nRetain per-turn source revisions and the existing FIFO while sharing equal text only within live cache ownership.\n\nGenerated-by: OpenAI Codex\n\n* test(runtime-host): make prompt heap checks portable to Electron\n\nGenerated-by: Codex\n\n* perf(ui): detach bounded drafts from oversized input strings\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime): reuse private Responses continuation history\n\nGenerated-by: OpenAI Codex\n\n* perf(ui): detach capped completed stream text\n\nGenerated-by: OpenAI Codex\n\n* perf(ui): simplify bounded draft string copying\n\nGenerated-by: OpenAI Codex\n\n* perf(ui): detach oversized stream seed backings\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime): detach bounded archive read results\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime): release completed tool settlement batches\n\nGenerated-by: OpenAI Codex\n\n* perf(ui): detach normalized sent prompt backing\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime): release unused plugin isolation labels\n\nIntern named isolation symbols weakly so retired configurations do not retain historical labels. Preserve detached Context and service identity, and guard delayed finalizers against newer same-name symbols.\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime): materialize memory split candidates on demand\n\nPreserve split ranking and first-fit semantics while constructing only the candidate currently being tested. Verify complete model context, durable coverage, and bounded event-reference copying through the SQLite-backed Host extraction path.\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime): bound memory localization prefix allocation\n\nGenerated-by: OpenAI Codex\n\n* perf(storage): bound session catalog preview allocation\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime): bound graph handoff prefix allocation\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime): bound child result prefix allocation\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime): bound workspace instruction prefix allocation\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime): bound PTY model tail allocation\n\nGenerated-by: OpenAI Codex\n\n* test(runtime): close shell result recovery fixture store\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime): consume discarded OAuth error bodies once\n\nGenerated-by: OpenAI Codex\n\n* perf(storage): size stable read buffers to admitted files\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime-host): release fully consumed frame buffers\n\nGenerated-by: OpenAI Codex\n\n* test(runtime-host): isolate consumed buffers from shared pools\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime-host): avoid recopying empty frame prefixes\n\nGenerated-by: OpenAI Codex\n\n* perf(ui): initialize persisted composer history once per mount\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime-host): release consumed peer byte-stream buffers\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime): stream live PTY code-point chunks\n\nAvoid full code-point and sliced arrays while preserving exact raw output chunk boundaries, publication sequences, and terminal flush behavior.\n\nGenerated-by: Codex\n\n* perf(runtime-host): avoid length-only Base64 decoding\n\nCount validated or generated Base64 bytes without materializing temporary decoded buffers. Preserve canonical checks, artifact bounds and transcript range semantics.\n\nGenerated-by: Codex\n\n* perf(runtime): bound research artifact character arrays\n\nCollect only requested code points while preserving full ledger hash validation, total length and sanitized output. Exercise the production Host tool facade against real SQLite and artifact files.\n\nGenerated-by: Codex\n\n* perf(runtime): count edit lines without splitting text\n\nReuse existing occurrence counting for match line positions. Preserve exact and fuzzy edits, trailing newline semantics and descriptor-pinned writes.\n\nGenerated-by: Codex\n\n* perf(runtime): collect only localized edit diff windows\n\nCount source lines without full arrays and collect the existing bounded diff windows directly. Preserve valid edit ranges, UTF-8 budgets, hunk formatting and descriptor-pinned writes.\n\nGenerated-by: Codex\n\n* perf(runtime): collect only requested file read lines\n\nPreserve split/slice window behavior while avoiding full-file line arrays in local and worker reads. Add real file regressions and allocation checks.\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): scope interaction hydration fences to pending reads\n\nReplace the ever-growing per-session epoch map with one pending read identity. Preserve stale-response guards without keeping metadata for completed sessions; ratchet the architecture token ledger downward.\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime): avoid full line arrays in bounded tool output\n\nCount line boundaries and collect only the retained head or tail window. Preserve byte slicing, recovery markers, and removed counts, with old-source negative allocation and real pipe projection coverage.\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime): bound oversized tool-line UTF-8 encoding\n\nEncode only a byte-budget-sized UTF-16 window, with one extra unit to preserve surrogate boundaries. Keep legacy Buffer behavior for unusual budgets and verify exact head/tail output against old source.\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime): bound WebFetch preview UTF-8 encoding\n\nEncode only the model-visible prefix plus a surrogate guard unit, preserving the byte cap and truncation marker. Cover real Host HTTP fetches, privacy refusal, Unicode boundaries and old-source allocation regression.\n\nGenerated-by: OpenAI Codex\n\n* perf(runtime-host): avoid duplicate resource result clones\n\nClone each runtime resource update once before bounding its state. Preserve source isolation and query revisions, and cover get/list allocation with old-source negative controls.\n\nGenerated-by: OpenAI Codex\n\n* chore: trim memory optimization test additions\n\nRemove 65 new test and fixture files plus added allocation probes from existing suites. Keep only minimal existing-test behavior and cleanup adaptations. Preserve production memory fixes and remove stale test references.\n\nGenerated-by: OpenAI Codex\n\n* fix: align memory changes with CI metadata gates\n\nRe-pin the compatible byte-count optimization to main\u0027s protocol epoch, record the MCP dependency patch license, and correct the renderer token ledger to the checked source.\n\nGenerated-by: OpenAI Codex\n\n* ci: include bounded line reader in Windows package inputs\n\nGenerated-by: OpenAI Codex\n\n* fix(runtime): keep graph epoch handover independent of teardown\n\nFence retired drivers synchronously, then release their snapshots after admitted work and cleanup settle without blocking the next turn.\n\nGenerated-by: OpenAI Codex\n\n* fix(bots): report lazy SDK initialization failures\n\nHandle module loading and client construction inside each bridge\u0027s failure boundary so registry status reflects failed connections.\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): defer cold WorkHub summons until renderer ready\n\nReuse pending focus to keep the window hidden during initial loading, allow cancellation, and preserve synchronous warm shortcuts.\n\nGenerated-by: OpenAI Codex\n\n* perf(memory): finish scoped lifecycle review follow-ups\n\nInitialize composer attachment ownership lazily, avoid empty handshake backing views, clarify line-window and Zod upgrade contracts, and cover CU observer cleanup without restoring allocation probes.\n\nGenerated-by: OpenAI Codex\n\n* test(desktop): wait for automatic naming before archive\n\n* test(memory): cover cancellation and recursive lifetime contracts\n\nGenerated-by: OpenAI Codex\n\n* test(peer): observe backpressure before testing teardown\n\nGenerated-by: OpenAI Codex\n\n* fix(ci): repin compatible allocation change to epoch 142\n\nRevalidated the byte-count-only protocol changes against current main after merging its Skill query epoch bump.\n\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "a57b4e866cb74fad1d0801d5ff3ff2cafaec99c6",
      "tree": "8b8070d188bcfb3f22ac90a8968800057bd5e596",
      "parents": [
        "1d3545c6341e89d24c531ad49e945e17c0f96b14"
      ],
      "author": {
        "name": "ChengBo Zhang",
        "email": "66726968+ARE404@users.noreply.github.com",
        "time": "Fri Sep 11 18:27:36 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 11 18:27:36 2026 +0800"
      },
      "message": "fix(desktop): restore WorkHub return and align prompt rails (#5177)\n\n* fix(desktop): restore WorkHub return and align prompt rails\n\nGenerated-by: Codex\n\n* fix(desktop): place WorkHub return above composer\n\nGenerated-by: Codex\n\n* fix(desktop): keep WorkHub return within shell architecture budget\n\nMove return rendering into the WorkHub feature and share Session selection checks so the legacy shell does not grow. Validate with the same --base architecture check as CI.\n\nGenerated-by: Codex\n\n* fix(desktop): use Astryx for WorkHub return control\n\nReplace the raw return button with Astryx Button, retain composer geometry, and refresh the surface inventory. Stabilize native startup resizing in the regression.\n\nGenerated-by: Codex\n\n* fix(desktop): address WorkHub rail review findings\n\nUse one rail host and gutter authority, preserve the public empty-state behavior, compare rail edges directly, and expose WorkHub return in shared Sessions. Recapture comparable screenshots and retain baseline failure evidence.\n\nGenerated-by: Codex\n\n* test(desktop): wait for derived effects before archiving history\n\nRegenerate visibility only proves root Turn completion. Retry the specific live-derived-effect retirement rejection while naming or recap settles; propagate all other errors and keep a bounded timeout.\n\nGenerated-by: Codex\n\n* fix(desktop): finish WorkHub review cleanup\n\nRestore named imports, use the rail host consistently, and recapture comparable Session images. Keep one-off baseline logs in the PR discussion rather than the source tree.\n\nGenerated-by: Codex"
    },
    {
      "commit": "1d3545c6341e89d24c531ad49e945e17c0f96b14",
      "tree": "85846ca0d3057eae9ff7ddd98aa668f0365786bc",
      "parents": [
        "797596264d25a5728f076de4901507a819dbfcd9"
      ],
      "author": {
        "name": "Xiao Liu",
        "email": "liuxiao2103@qq.com",
        "time": "Fri Sep 11 18:20:07 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 11 18:20:07 2026 +0800"
      },
      "message": "fix(desktop): keep expanded tool calls in flow (#5158)\n\n* fix(desktop): keep expanded tool calls in flow\n\nStop pinning expanded tool group and call headers over adjacent transcript content while preserving the reasoning disclosure\u0027s sticky behavior. Cover the presentation contract in the existing narrow grouped-tool Storybook interaction.\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): finish tool call flow cleanup\n\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "797596264d25a5728f076de4901507a819dbfcd9",
      "tree": "f3b8686ae09e5614472268a09219fc08d6f20d8b",
      "parents": [
        "03cc3aea7f305046c7084249b101f23f43a97139"
      ],
      "author": {
        "name": "Xiao Liu",
        "email": "liuxiao2103@qq.com",
        "time": "Fri Sep 11 18:20:03 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 11 18:20:03 2026 +0800"
      },
      "message": "fix(desktop): preserve default connection badge typography (#5024)\n\n* fix(desktop): preserve default connection badge typography\n\nKeep the default-state badge on the same label type tier as the action it\nreplaces, so clicking \"set as default\" does not visually shrink the text.\nCover the real connection-detail transition with a Storybook regression.\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): preserve pet action badge typography\n\nApply the shared action-slot badge type tier to selected and disabled pet states, and cover both transitions with a Storybook interaction regression.\\n\\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "03cc3aea7f305046c7084249b101f23f43a97139",
      "tree": "c95c9bc353ced64a61740fdf191ab1ba4db81dbf",
      "parents": [
        "8be2493331b4e9469dd1e94e485b1fff6ab3ef97"
      ],
      "author": {
        "name": "Xiao Liu",
        "email": "liuxiao2103@qq.com",
        "time": "Fri Sep 11 18:20:00 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 11 18:20:00 2026 +0800"
      },
      "message": "fix(runtime-host): classify archived Skill queries (#5149)\n\nInvocable Skill discovery flattened missing and archived Session lifecycle refusals into internal_failure. Preserve not_found and session_archived through the protocol, including lifecycle changes during live graph-tool resolution.\n\nFixes #5148\n\nGenerated-by: OpenAI Codex\n\nSigned-off-by: liuxiaocs7 \u003cliuxiao2103@qq.com\u003e"
    },
    {
      "commit": "8be2493331b4e9469dd1e94e485b1fff6ab3ef97",
      "tree": "eb07fff3296875c76a390f9a4fb426f3f07c1892",
      "parents": [
        "c60e12cb4698e420448b23fc6303da62b943668b"
      ],
      "author": {
        "name": "Phoenix",
        "email": "Phoenix500526@163.com",
        "time": "Fri Sep 11 17:27:51 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 11 17:27:51 2026 +0800"
      },
      "message": "fix(desktop): treat teardown as cancellation (#4562)\n\n* fix(desktop): treat teardown as cancellation\n\nPending renderer teardown is an expected observation outcome.\nRepresent it explicitly across IPC so Electron does not report a\nhandler failure or expose an empty success value.\n\nCLOSES #4434\nGenerated-by: OpenAI Codex\n\nSigned-off-by: Jiawei Zhao \u003cPhoenix500526@163.com\u003e\n\n* fix(desktop): preserve observation failures\n\nSession removal and connection closure must reject pending reads so\nconsumers reach existing failure handling instead of waiting silently.\nOnly caller-initiated teardown should count as cancellation.\n\nRefs #4434\nGenerated-by: OpenAI Codex\n\nSigned-off-by: Jiawei Zhao \u003cPhoenix500526@163.com\u003e\n\n* test(desktop): align observation IPC fixture\n\nThe rebased seed-order test still returned the old array contract.\nUse the ready envelope while preserving the seed-before-ready assertion.\n\nRefs #4434\nGenerated-by: OpenAI Codex\n\nSigned-off-by: Jiawei Zhao \u003cPhoenix500526@163.com\u003e\n\n* fix(desktop): cover observation cancellation\n\nPreserve explicit teardown results when rebasing onto main.\nExercise preload cleanup and keep cancellation logs distinct.\n\nRefs #4434\nGenerated-by: OpenAI Codex\n\nSigned-off-by: Jiawei Zhao \u003cPhoenix500526@163.com\u003e\n\n---------\n\nSigned-off-by: Jiawei Zhao \u003cPhoenix500526@163.com\u003e"
    },
    {
      "commit": "c60e12cb4698e420448b23fc6303da62b943668b",
      "tree": "7e9035603d275258a414bf8b8d3ba0b0f1cdfffa",
      "parents": [
        "a49ba7544c3bdd1ef648ec90c69b8f39f3e881c0"
      ],
      "author": {
        "name": "Yunpei Zhou",
        "email": "Joob1n@outlook.com",
        "time": "Fri Sep 11 17:03:46 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 11 17:03:46 2026 +0800"
      },
      "message": "fix(storage): publish imported context payloads atomically (#5186)\n\n* fix(storage): publish imported context payloads atomically\n\n`copyContextValueTree` filled its destination with `copyFile` and treated\n`EEXIST` as nothing to do. Both halves are wrong, and together they lose\ndata: a copy interrupted midway leaves a truncated payload at the path\nother Sessions read, and the retry accepts it as already present.\n\nPayloads now become visible the way the Context Store publishes its own,\nby `link` from a staging name, so the final path is never observable\nhalf-written -- measured at 38 distinct intermediate sizes while copying\n64 MiB through `copyFile`, and none through `link`. An interrupted\nattempt leaves its bytes under the staging name, which the next attempt\nclears. Reaching `EEXIST` at the final path now means the payload was\nalready there; content addressing says it must be byte-identical, and a\npayload that is not is reported rather than silently accepted.\n\nAlso let a caller supply the Storage Root authority instead of electing\nit. The owner lock is an election taken with `tryLock`: it refuses a\nsecond exclusive hold even inside the process that already has one, so a\nRuntime Host cannot prepare or accept a bundle by calling these at all --\nit can only lend the authority it took at startup. A lease must name the\nsame root it is used on. Callers that hold no authority, the CLI\nincluded, omit it and elect as before.\n\nRefs #5182\n\n* fix(storage): fence context mutations and validate an imported bundle\n\nCloses the six findings from review.\n\n**A lent lease did not fence Context Store mutations.** The Store\u0027s own\noperations read database state, await, and only then act on files:\ncollection decides a payload is unreferenced, awaits, unlinks it. An\nimport publishing inside that await leaves a committed reference pointing\nat a file about to be removed, and the re-check collection performs cannot\nsee it because the check and the unlink straddle the await.\n\nThe Store already serialised those operations, through a promise tail\nprivate to the instance, which fenced nothing outside it. That queue is\nnow keyed by Storage Root and shared, so an importer takes the same turn.\nIn-process is the whole boundary: the interactive write authority is an\nexclusive election, so one process at a time mutates a root\u0027s context.\n\n**The lease could be detached from the root actually used.** Both paths\nvalidated the lease and then derived the Artifact writer lock from\n`input.stateRoot` again, so an alias or a replaced directory between the\ntwo steps would bind the operation to one root while the lease named\nanother -- including an unmarked one, which takes no lock at all. With a\nlease, the lock is now derived from the lease.\n\n**Hydrated context was not validated.** An archive digest authenticates\nthe archive, not the state inside it: a row claiming a hash and a file\nthat does not hash to it survives it. `validateContextSnapshot` already\nexists and the export already runs it on its own output; the import now\nruns it on the bundle before writing anything to the target.\n\nAlso: sync the directory chain after linking a payload, so a crash cannot\nkeep the committed row and lose the name; refuse a destination payload\ndirectory whose realpath leaves the Storage Root, since lexical\ncontainment says nothing about a symlinked `context-offload-values`; and\nclear `context_gc_candidates` for blobs the import references again,\nwhich otherwise makes every later collection fail.\n\nRefs #5182"
    },
    {
      "commit": "a49ba7544c3bdd1ef648ec90c69b8f39f3e881c0",
      "tree": "21a5d873f4bc28694e8ea6f15ca20eb23c79cbbc",
      "parents": [
        "898ac52d9c12da1b58973805d92d01474b780120"
      ],
      "author": {
        "name": "Zhang",
        "email": "96464454+me2seeks@users.noreply.github.com",
        "time": "Fri Sep 11 10:49:09 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 11 10:49:09 2026 +0800"
      },
      "message": "fix(runtime-host): make managed WSL recovery actionable (#5175)\n\nTell source TUI users how to return to the managing Desktop for an explicit Host handoff. Run Desktop setup and update through the same WSL user login environment so current zsh, fish, or bash configuration can provide Node and npm.\n\nShow validated development archive versions instead of package integrity. When recovery fails, direct users to the diagnostic and avoid implying that unchanged retries will repair a deterministic failure.\n\nRefs #5143, #5161\n\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "898ac52d9c12da1b58973805d92d01474b780120",
      "tree": "8fa5b2253bf9ef0460f767c47bf6adbcc3531948",
      "parents": [
        "11b93d111a796f79a91635b00d6acd105ecea435"
      ],
      "author": {
        "name": "Yunpei Zhou",
        "email": "Joob1n@outlook.com",
        "time": "Fri Sep 11 10:27:20 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 11 10:27:20 2026 +0800"
      },
      "message": "feat(runtime): import a Session bundle into a workspace (#5139)\n\n* fix(storage): keep an environment failure out of the schema verdict\n\nOpening the source for backup translated every acquisition failure into\n`schema_unsupported`, so an unreadable `runtime.sqlite` told the caller to\nupgrade when the real answer was that the file could not be opened.\n\nOnly a blocked migration is a statement about the schema. Permission, busy and\nI/O failures are the environment talking, and the operational store preserves\nthem on purpose.\n\n* feat(runtime): import a Session bundle into a workspace\n\nThe mirror of the export, and the asymmetry is the design. The export owns a\nprivate copy and deletes what is not the subtree; the import writes into a live\nworkspace holding other people\u0027s Sessions and can only add.\n\nWhat keeps that from needing a table list is that the bundle\u0027s database already\ncontains nothing else, so the merge copies every table it has. A table added to\nthe schema later travels in both directions without anyone maintaining a list —\nthe same property that made the export\u0027s deny-by-default filter right.\n\nThree kinds of table are not copied. The workspace-level ones belong to the\ntarget, which has its own. `session_catalog_projection` is derived, and\n`session_metadata` carries triggers that maintain it — inserting the bundle\u0027s\ncopy and then the Session row makes the trigger collide with what was just\ninserted, and letting the target derive it is the only way it stays correct\nwhen the derivation changes.\n\nWrite order is the safety argument. Artifact bytes land first and the database\ntransaction commits last, so a failure between them leaves files nothing points\nat — reclaimable — rather than rows pointing at files that are not there. The\ncontext-offload closure is merged too: without it an imported Session arrives\nwith its read-image references intact and none of the bytes behind them.\n\nA Session id already present refuses the whole bundle. Ids are generated rather\nthan chosen, so one already here means this Session is already here, not that\ntwo of them collided. Importing over it would merge two histories that share\nids and agree about nothing else. Copying a Session that already exists is a\nseparate operation and belongs to `conversation-copy`.\n\nUnlike the export, this opens the target the ordinary way. The export refuses\nto migrate its source because it only reads; an import is a write the user\nasked for, and the target is often a workspace with no database yet — moving to\na new machine is the point.\n\nThe round-trip test is the acceptance criterion the export PR could not state:\nexport, import into a different workspace, and compare the rows the model reads\nfield for field, including the JSON columns whose bytes a re-encoding would\nchange.\n\n* fix(storage): stop the import from reaching around the workspace lease\n\nThree defects from reviewing the import against the workspace it writes into.\n\n**The merge drove a shared connection directly.** The operational store hands\nout one reference-counted connection per workspace with its own transaction\ndepth, and this ran `BEGIN IMMEDIATE` on it and left `PRAGMA foreign_keys` off\nafterwards. Every later user of that workspace would have run without\nconstraint checking, and nothing would have reported it. The merge now goes\nthrough the lease\u0027s transaction and puts the pragma back.\n\n**The bundle\u0027s schema was never compared with the target\u0027s.** Rows are copied\nwith `INSERT ... SELECT *`, which maps by position: a bundle whose tables carry\nthe same column count in a different order would be inserted transposed --\nrows that read as data and are not. The export only writes a bundle at its own\ncurrent schema, so a mismatch means two builds disagree, and saying so is the\nonly honest answer.\n\n**A target this build cannot open reported as an IO failure.** Same shape as\nthe export\u0027s own follow-up: a blocked migration is a schema verdict, and\nflattening it sends the caller after the wrong problem.\n\nThe bundle is also attached read-only now, so reading one can never write it.\n\nThe first regression I wrote for the pragma passed with the fix removed: it\nread `PRAGMA foreign_keys` on a fresh handle, and the pragma is per-connection.\nIt now holds a lease across the import the way a running Runtime Host does, on\nthe canonicalised path the import itself resolves -- without that it observes a\ndifferent connection and proves nothing.\n\n* fix(storage): land everything a Session references before publishing it\n\nThree gaps in the context half of the import, all of which let a Session\narrive without the bytes it points at.\n\n**The Session was published before its context.** The rows committed, then the\ncontext merge ran — so a failure there left a Session visible whose payloads\nnever arrived, and a retry hit `session_exists` forever because the ids were\nnow taken. The order is inverted: artifacts and context land first, and the\nSession rows are the last thing written. A failure before that leaves data\nnothing points at, which the store reclaims.\n\n**The offline authority was decided by the wrong side.** It was taken only when\nthe TARGET already had a context store, so a bundle carrying context into a\nfresh workspace failed the check with no Runtime Host anywhere — the common\ncase, and the one where the store is about to be created. It is now taken for\nwhat is being written.\n\n**Managed payloads were never copied.** They live at `sha256/\u003cprefix\u003e/\u003chash\u003e`,\nand the copy visited only immediate children and skipped directories: it saw\none directory, skipped it, and reported a successful import whose referenced\nbytes were all absent. The tree is copied whole, and the regression reads an\nimported payload rather than counting the reference that names it — a reference\nwhose bytes never arrived counts exactly the same.\n\n**Usage accounting went stale.** `context_store_usage` and\n`context_session_usage` are maintained by the context store explicitly; no\ntrigger does it. They are recomputed in the same transaction, the way the\nexport recomputes them when it filters. These numbers drive quotas and the\ncleanup consistency checks.\n\nOne more, found while testing the above: the merge now asks the same question\nof a bundle table that the export asks before emptying one. A table with no\nSession column and no referential rule describes the workspace, and the target\nhas its own. The export empties those, so this inserts nothing in practice —\nbut an import that relies on the other side having tidied up is one bundle away\nfrom writing a workspace singleton into somebody else\u0027s workspace.\n\n* fix(storage): make a failed Session import retryable\n\nA failed import left three kinds of residue that turned the second\nattempt into a permanent conflict:\n\n- Artifacts were staged before the context merge and neither rolled\n  back nor recognised on retry, so `COPYFILE_EXCL` refused the import\u0027s\n  own leftover. The copy now reports what it created, the caller removes\n  exactly those on failure, and a leftover from a crashed attempt is\n  accepted only when its bytes are identical.\n- `context_refs` insertion was not idempotent, so a failure after the\n  context transaction committed blocked the retry. Identical rows are\n  now skipped; a row naming different content is still a conflict.\n- A genuinely fresh workspace could not import context at all: the\n  snapshot lock discovered a marked Storage Root rather than resolving\n  one. A writer that is about to create the store now initialises it.\n\nAlso stop recomputing `physical_bytes` from live blobs alone. Bytes\nqueued in `context_file_deletions` are on disk and still charged, and\nthe store subtracts them when the drain completes -- so dropping them\nhere made that later subtraction underflow. The export can use the\nsimpler sum because it empties the queue on its private copy.\n\nThe context fixture now uses the real v3 schema rather than an\napproximation of it."
    },
    {
      "commit": "11b93d111a796f79a91635b00d6acd105ecea435",
      "tree": "9e78a6636e62a2f73a63ad64f33d79aa2ca4abc0",
      "parents": [
        "10269d3c2c5935618ade5834005b24a99e5b04b9"
      ],
      "author": {
        "name": "Zhang",
        "email": "96464454+me2seeks@users.noreply.github.com",
        "time": "Fri Sep 11 01:03:46 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 11 01:03:46 2026 +0800"
      },
      "message": "fix(desktop): add explicit managed WSL Host handoff (#5161)\n\n* fix(desktop): add explicit managed WSL Host handoff\n\nRefs #5143, #5144\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): fence legacy WSL handoff without status fingerprint\n\nValidate the observed source package version under the deployment lease alongside deployment and Host generation identities. Preserve the additional fingerprint fence where the source operator supports it.\n\nRefs #5143\n\nGenerated-by: OpenAI Codex\n\n* refactor(cli): derive on-demand update recovery policy\n\nKeep a failed on-demand update authoritative within the lifecycle transaction, so callers cannot accidentally restore a prior package after its successor may have opened storage.\n\nRefs #5161\n\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "10269d3c2c5935618ade5834005b24a99e5b04b9",
      "tree": "b6262092d7bf99504f26e7f7dff95fcfa7f4e5d3",
      "parents": [
        "fa0ff028e14b96bc14d987f156a2ad79d8b45151"
      ],
      "author": {
        "name": "Zhang",
        "email": "96464454+me2seeks@users.noreply.github.com",
        "time": "Thu Sep 10 22:53:31 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 10 22:53:31 2026 +0800"
      },
      "message": "fix(desktop): separate WSL setup replacement and interruption consent (#5160)\n\nRefs #5144\n\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "fa0ff028e14b96bc14d987f156a2ad79d8b45151",
      "tree": "39182cf46fb43bf737a687d296c665d74d1358f6",
      "parents": [
        "48ab8a7a903edf9c44c78f0cdb41f45d662c40c7"
      ],
      "author": {
        "name": "ChengBo Zhang",
        "email": "66726968+ARE404@users.noreply.github.com",
        "time": "Thu Sep 10 22:30:49 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 10 22:30:49 2026 +0800"
      },
      "message": "feat(workhub): add model routing foundation (#5152)\n\n* feat(workhub): add model intent and recall evaluation\n\nGenerated-by: Codex\n\n* docs(workhub): record DeepSeek routing smoke evaluation\n\nGenerated-by: Codex\n\n* feat(workhub): route with selected model\n\n* fix(desktop): label WorkHub routing calls\n\n* test(workhub): bind routing decisions in composition fixtures\n\n* fix(workhub): unify routing admission"
    },
    {
      "commit": "48ab8a7a903edf9c44c78f0cdb41f45d662c40c7",
      "tree": "4c19a5d1e2ea67470bfa0f7ea7438a1055828b93",
      "parents": [
        "851712a51464266512e078883f464cbcdc8365c9"
      ],
      "author": {
        "name": "ChengBo Zhang",
        "email": "66726968+ARE404@users.noreply.github.com",
        "time": "Thu Sep 10 22:26:10 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 10 22:26:10 2026 +0800"
      },
      "message": "fix(workhub): return delegated task results (#5150)\n\n* fix(workhub): return delegated task results\n\nGenerated-by: Codex\n\n* fix(workhub): keep internal feedback types private\n\nGenerated-by: Codex\n\n* fix(workhub): preserve delegation feedback evidence\n\nProve the target Turn boundary before caching a result, batch execution queries at the protocol limit, and fail closed when the Session catalog is unavailable.\n\nGenerated-by: Codex"
    },
    {
      "commit": "851712a51464266512e078883f464cbcdc8365c9",
      "tree": "36d96c8c8eca7b16cf9228cd723540c131edb986",
      "parents": [
        "84255571b24be678eac4aff612be5ebe50a2f89c"
      ],
      "author": {
        "name": "Zhang",
        "email": "96464454+me2seeks@users.noreply.github.com",
        "time": "Thu Sep 10 22:19:20 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 10 22:19:20 2026 +0800"
      },
      "message": "fix(desktop): release React development performance measures (#5156)"
    },
    {
      "commit": "84255571b24be678eac4aff612be5ebe50a2f89c",
      "tree": "bb02e4be836282475a2ff6412052125824260730",
      "parents": [
        "088fe009346395106f56461780eb5001c19af67b"
      ],
      "author": {
        "name": "Xinhao Xu",
        "email": "84456268+xxhZs@users.noreply.github.com",
        "time": "Thu Sep 10 18:50:00 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 10 18:50:00 2026 +0800"
      },
      "message": "feat(plugins): add scoped prompt and host context services (#5014)\n\n* feat(plugins): add scoped system prompt service\n\n* refactor(runtime): share plugin scope registry\n\n* feat(plugins): add dynamic model context contributions\n\n* feat(plugins): add agent invocation service\n\n* feat(plugins): add interaction services\n\n* feat(plugins): expose scoped resource services\n\n* feat(plugins): add metered llm service\n\n* feat(plugins): bind agent service to host runtime\n\n* fix(plugins): preserve scoped service bindings\n\n* test(plugins): cover scoped context services end to end\n\n* feat(plugins): add scoped P1 services\n\n* fix(plugins): enforce scoped prompt and agent context\n\n* fix(plugins): preserve contribution and cancellation authority"
    },
    {
      "commit": "088fe009346395106f56461780eb5001c19af67b",
      "tree": "8f099cd55f9dc090007ab3607e7fc54d0186bf88",
      "parents": [
        "63ad3d05e9af69f81f8f7e6ac1560c5626bd327c"
      ],
      "author": {
        "name": "Wang",
        "email": "m4n5terrr@gmail.com",
        "time": "Thu Sep 10 17:47:56 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 10 17:47:56 2026 +0800"
      },
      "message": "feat(desktop): use the shared composer in WorkHub progress cards (#5129)\n\n* feat(desktop): steer WorkHub from its progress composer\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): disable manual resizing for compact WorkHub\n\nGenerated-by: OpenAI Codex\n\n* fix(desktop): stabilize WorkHub fold motion without changing layout\n\nGenerated-by: OpenAI Codex\n\n* perf(desktop): keep WorkHub renderer height stable during motion\n\nGenerated-by: OpenAI Codex\n\n* fix(ui): preserve steering position through admission\n\nCapture the visible conversation boundary at Send and preserve it across pending, live, and persisted messages in ordinary sessions and WorkHub. Dim pending steering backgrounds until consumption.\n\nGenerated-by: Codex\n\n* fix(desktop): hold queued messages above the composer\n\nPresent steering and follow-up queues with distinct timing and shared edit, retract and reorder actions. Insert steering into the transcript at actual consumption and preserve queue order through durable edits and restart.\n\nGenerated-by: Codex\n\n* fix(desktop): align WorkHub follow-up submission with chat\n\nGenerated-by: Codex\n\n* fix(desktop): reconcile WorkHub queue cancellation and shortcuts\n\nGenerated-by: Codex\n\n* docs(ui): refresh queue tooltip component inventory\n\nGenerated-by: Codex\n\n* fix(workhub): preserve message admission and queue authority\n\nNormalize uploaded attachment identities at the Desktop boundary, recover coordination successors in their execution domain, and wait for durable queue edits at the provider boundary. Keep Host queue rows out of local transient state, reject ambiguous cross-mode retries, and remove the unused display anchor contract and single-owner facades.\n\nGenerated-by: Codex\n\n* fix(workhub): preserve pending messages across startup and delivery\n\nDefer recovered WorkHub turns until Desktop tools are bound, fence steering admissions at provider boundaries, and retain visible admission placeholders and exact retry identities until Host evidence settles them.\n\nGenerated-by: Codex\n\n* fix(workhub): bind recovered turns to their original Desktop authority\n\nPersist the authenticated capability provider identity with each WorkHub root and inherit it across successors. Recover only a matching principal, Client and credential owner; unrelated registrations and legacy admissions without evidence cannot select a provider.\n\nGenerated-by: Codex\n\n* fix(runtime-host): capture WorkHub binding evidence atomically\n\nReturn verified provider evidence from the same registry mutation that binds a live Session, and require it before admitting a WorkHub v2 root. Cover disconnect/reconnect followed by both cold-recovery crash cuts and reject missing or split-provider tools.\n\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "63ad3d05e9af69f81f8f7e6ac1560c5626bd327c",
      "tree": "12f5e3d9167958687a0724dfd7036be1bc296915",
      "parents": [
        "f09119884e3e640f1c10755da19a583416aed19f"
      ],
      "author": {
        "name": "AstroHan",
        "email": "lei.yuhan@outlook.com",
        "time": "Thu Sep 10 17:34:46 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 10 17:34:46 2026 +0800"
      },
      "message": "fix(ui): render message action rows with Astryx Icon and IconButton (#5134)\n\nThe action rows under user and assistant messages used Astryx IconButton and ChatMessageMetadata for the shell, but everything inside them was product-owned: lucide glyphs at a product 14px rung, styles.css resetting the button\u0027s border, radius, ink and pending/copied colours, disabled and busy expressed as aria-disabled + data-* attributes, a meta \"button\" whose click did nothing, and a positional selector that deleted Astryx\u0027s timestamp separator on the user side.\n\n- Every glyph goes through Astryx Icon at size\u003d\"sm\": copy/check by semantic name, regenerate/branch/edit as SVG components.\n- IconButton keeps its own border, radius, ink, hover, focus, disabled and busy treatment; isDisabled replaces the aria-disabled + click-guard pair, isLoading replaces data-pending/aria-busy. The .maka-turn-footer-action geometry and colour overrides are gone.\n- The turn meta (model · duration · cost) is rendered as footer text instead of an info pseudo-button; the info action id and its locale labels are removed and the derivation moves into TurnView, so the ratcheted renderer view model shrinks.\n- Both senders share one reveal rule keyed on .maka-chat-message; the user row\u0027s time and delivery status move into the footer slot so Astryx never draws a separator and the positional hide is deleted.\n\nFixes #5133\nRefs #5132\n\nGenerated-by: Claude Code"
    },
    {
      "commit": "f09119884e3e640f1c10755da19a583416aed19f",
      "tree": "579db54391e23d0f646df641c0518a574a83b077",
      "parents": [
        "638fa4854d36017374a70cef65f1abe7fb0afc41"
      ],
      "author": {
        "name": "AstroHan",
        "email": "lei.yuhan@outlook.com",
        "time": "Thu Sep 10 15:22:56 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 10 15:22:56 2026 +0800"
      },
      "message": "feat(desktop): lead About with the wordmark and offer the restart there (#5130)\n\n## Summary\n\nTwo problems with 设置 → 关于 after #4857:\n\n1. **The page was bare.** A version row, an update row and three support rows, on a surface that never said what it was about — the one page in the app whose subject is the app itself.\n2. **A downloaded update sent the user away.** The row said 在侧栏底部重启即可安装: leave Settings, find the footer button, restart. The user was already on the page that exists for exactly this.\n\nWhat changes:\n\n- **The lead is the wordmark over the build.** `MakaWordmark` (carrying the accessible name \"Maka\"), then the version as plain semibold text — not a `Heading`, so it does not rank beside the 更新 and 支持 group titles, and not prefixed with \"Maka\", which the mark already says — the channel sentence, and the provenance line that used to trail the page.\n- **更新 is its own group, and offers the restart.** `aboutUpdateRow` maps `downloaded` to an `install` action; the row renders 重启安装 as the page\u0027s one primary button. It calls the same `openUpdate` the sidebar footer\u0027s restart calls — published through the About projection as `installDownloadedUpdate`, defined only while the reminder is `downloaded` — so both entries share the active-tasks confirmation, the in-flight latch and the failure toasts. The projection also publishes `installPending`, so the button shows the request (and the open confirmation dialog) as loading instead of silently swallowing repeat clicks. A dev checkout still gets no update group.\n- **The row keeps one shape in every state.** On `main` the second line came and went and the control vanished while a download was in flight, so the page jumped from up to date to downloading to downloaded. Now the label is a short phase word (已是最新版本 / 正在下载（42%）/ 新版本已下载 / 下载更新失败…), the second line always carries the version and what happens next, and one `sm` button sits in the same slot: 检查更新, disabled while the updater works on its own, or 重启安装 once downloaded. Keeping the version out of the label is what stops it truncating against the button at narrow widths.\n- **One brand tint.** The wordmark\u0027s colour was set by two CSS rules and would have gained an inline style here; `MakaWordmark` now wears `--maka-brand` itself and the two rules are gone.\n\nNothing else moves: support rows, control faces and the row-end text edge are as #4857 left them. The App Update boundary (one provider, About the only reader) is unchanged and its tests pass as written; `updateDownloadedHint` and the version-bearing labels leave all three copy catalogs.\n\nNightly with a downloaded update, 1280 wide:\n\n![Before and after, nightly, light](https://github.com/user-attachments/assets/3d079500-2525-4dce-9cb0-f9852c00d2e6)\n\n![Before and after, nightly, dark](https://github.com/user-attachments/assets/83aa1243-e83a-4e67-944e-5479eeb59a92)\n\nThe update row in four states — measured on the built stories: row height 56px in every state for zh-CN, zh-TW and en at 640, 900 and 1280 wide, no label truncation at any width. At the 480px window floor a long nightly version wraps the second line to two (76px); that is the floor, not a state change.\n\n![After: the update row in four states, light](https://github.com/user-attachments/assets/d451077f-7d48-4b64-96f9-8cd4d0d1b035)\n\n![After: the update row in four states, dark](https://github.com/user-attachments/assets/7523f20d-f3a4-4b45-9118-ed423334bf97)\n\nDev checkout, where there is no update group:\n\n![Before and after, dev, light](https://github.com/user-attachments/assets/29d77654-fb3d-4376-9e25-7639a4f2a41a)\n\n![Before and after, dev, dark](https://github.com/user-attachments/assets/2e33a042-7712-4b33-8b11-4e2f058b4389)\n\n## Verification\n\n- `npm run format`, `npm run lint` at the root: clean.\n- `apps/desktop`: `tsc -p tsconfig.renderer.json` clean; `tsc -p tsconfig.storybook.json` reports only the pre-existing `packages/core` generated-module errors. `node scripts/check-renderer-architecture.mjs --base 8b3655a17` passes; `npm run astryx:surface-inventory` ok (inventory regenerated).\n- `node --test` on `about-update-status`, `about-settings-page`, `app-update-boundary`, `app-update-provider-scope`: 19 pass, 0 fail. On `main`: the `downloaded`/`busy` mappings and the version-on-the-second-line test fail; the provider-scope dedupe test now fires About and the sidebar together and asserts one install request, which fails without the shared handler.\n- Storybook `product-settings-pages--about`, `--about-nightly` (play: the fake refuses the guarded request with `active_tasks`, the play confirms 仍然更新 and asserts the second request carries `allowInterruptActiveTasks: true` — an About wired to its own install call never shows the dialog), `--about-release`, `--about-downloading` (new; play asserts 检查更新 is disabled), `--about-update-failed`, light and dark: screenshots above; `scripts/storybook-visual-smoke.mjs` on the built storybook passes (331 stories).\n\n## Invariants\n\nThe jumping was a broken invariant, not a layout bug, and two more were broken on the way to the fix:\n\n- **Row shape** (#4857\u0027s page model: label, one quiet line, one control at the end). The update row never kept it: the second line existed only in `error`, and the control vanished in five of the eight states. The row now satisfies it structurally in every state.\n- **`Item` labels are phrases, not variable-length facts.** The label is `nowrap` + `ellipsis`. The version only survived in the label because the `downloaded` row had no end control; give every state a button and the version truncates. Padding the second line with copy to hold the height (an earlier revision of this PR) satisfies the shape invariant through content, so it broke again per locale and width. The version now lives on the wrapping second line and the label is the phase word.\n- **Heading ladder.** `Maka v…` as `Heading 3` sat beside the 更新/支持 group titles, making the version read as a third group. It is plain text now; the wordmark carries the name.\n- **One authority for the brand tint.** `MakaWordmark` documented that callers pick the tint; all three callers picked `--maka-brand`. The component owns it now and the extension point is gone.\n- **One install handshake** (About and the sidebar call the same `openUpdate`). Held by construction but unenforced: an About wired to its own install call passed every test. The story now walks the active-tasks confirmation and the provider-scope test fires both entries and asserts one request.\n\n## Review focus\n\n- The install-failure path is unchanged: after a failed `quitAndInstall` the service reports `error`/`install` and only accepts a fresh `downloaded`, so About offers 检查更新 and the sidebar offers retry, as before this PR.\n- `installing` is an absorbing state in `app-update-service.ts` if the process does not exit and no error event follows; the row\u0027s second line there describes the phase only and promises nothing.\n\n## AI use\n\nSelect exactly one:\n\n- [ ] No generative tool made a substantive contribution\n- [x] Generative tooling made a substantive contribution\n\nTool(s) and scope: Claude Code drafted the page, the projection change, tests, stories and this description under review; three Claude reviewers (contract, design, tests) produced the findings addressed in the second commit.\n\n## Checklist\n\n- [x] Tests cover the change and fail without it\n- [x] Lint, format, typecheck and the affected suites pass locally\n\nDoes this PR entail a change in behavior?\n\n- [x] Yes — described under Summary above\n- [ ] No\n\nGenerated-by: Claude Code"
    },
    {
      "commit": "638fa4854d36017374a70cef65f1abe7fb0afc41",
      "tree": "553a2e93796eb6895b1ff400535f7ddc4e2fb578",
      "parents": [
        "a9b4f21afb17e0ef310d076382e69ddda3a441d7"
      ],
      "author": {
        "name": "Yunpei Zhou",
        "email": "Joob1n@outlook.com",
        "time": "Thu Sep 10 14:54:07 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 10 14:54:07 2026 +0800"
      },
      "message": "feat(runtime): export one Session as a portable bundle (#5113)\n\n* feat(storage): let the Session export carry a subtree and a portable scope\n\n`exportSessionBundleState()` already prepares a Session for a bundle: a\nconsistent database snapshot through `lease.backup()`, the context and\nartifact writer locks around it, a filter that deletes what the Session does\nnot own rather than selecting what it does, the context-offload closure, and\n`PRAGMA foreign_key_check` to prove the result. Nothing calls it for a\nportable bundle yet, and four things are missing before something can.\n\n**Subtree** (`includeSubtree`). A subagent child holds the result of a tool\ncall its parent made, so a bundle of the parent alone is a conversation with a\nhole in it. The walk tracks membership: `subagent_parent_session_id` is an\nordinary column and nothing stops a row from naming itself or an ancestor.\n\n**Quiescence** (`requireQuiescent`). A partial stream snapshot or an\ninvocation with no terminal event refuses the export, and one active child\nrefuses the tree. The check runs on the backed-up copy rather than the live\ndatabase, because the locks held here do not stop a turn from starting and\n`lease.backup()` is what actually freezes the content — this is the only place\nwhere what was checked and what ships are the same bytes.\n\n**Diagnostics** (`omitDiagnostics`). `core_agent_run_events` rows that describe\na request rather than the conversation are dropped. In a real Session they are\n98% of that table and none of them reach the model. The two kinds that decide\nwhat the model reads — `history_compact_checkpoint_recorded` and\n`model_projection_transition_recorded` — are deliberately not on that list, and\nneither is any type this build has never seen: an export moves rows, it does\nnot interpret them.\n\n**Schema validation.** The filter runs `DELETE` over whatever tables the\ndatabase happens to have, so a schema this build cannot read produces a bundle\nwhose shape will not match what its manifest claims. The registry the database\nkeeps about itself is now checked before the plan is made, and its versions are\nwhat the plan reports.\n\nTwo corrections to the filter itself, both of which applied before this change:\n\n- `SESSION_OWNING_COLUMNS` names each spelling the schema uses. The filter\n  recognised three, and `subagent_spawns` uses `parent_session_id` and\n  `child_session_id` — so it looked Session-less and was emptied wholesale,\n  taking with it the record of which tool call spawned each child. Nullable\n  columns count only when set.\n- A missing planned entry reports `missing_entry` rather than `invalid_root`.\n  A record naming bytes the workspace does not have and a state root that is\n  not there are different mistakes.\n\nEvery option defaults to this function\u0027s previous behaviour, so\n`production-session-snapshot` is unchanged.\n\nClaude-Session: https://claude.ai/code/session_014ajaRxC4jydavY9nYUFj5J\n\n* feat(runtime): export one Session as a portable bundle file\n\nSeal a prepared Session into a single `.maka-session` file, and expose it as\n`maka session-export` so the round trip can be exercised before any surface\ncommits to it.\n\nThe preparation is `exportSessionBundleState()`; this is the thin part on top\nof it. What it adds is the manifest the codec carries as the bundle\u0027s state\nidentity: the Sessions inside, the schema versions the SOURCE database\nregisters, the state entries the policy included and the ones it left behind,\nand the connection by slug and model.\n\nNo credential is carried. The importing side resolves the slug against its own\ncatalog, and where it cannot, the existing stale-connection state already says\nso. This means application configuration, not that no secret can appear\nanywhere in a bundle: history is carried byte for byte, and a user message or\ntool output may contain one.\n\nFailures are distinct because a script should be able to tell them apart: a\ndirectory that was never a workspace reports `workspace_not_found` rather than\n`session_not_found`, since a workspace holding no Sessions still has a database\nand a mistyped path must not read as an empty catalog.\n\nExtracting this archive is not importing a Session, so nothing here claims\nmodel-history equivalence. That acceptance test belongs with the import PR.\n\nClaude-Session: https://claude.ai/code/session_014ajaRxC4jydavY9nYUFj5J\n\n* fix(storage): separate row ownership from a lineage pointer\n\nMigration starts wherever it is pointed and takes the subtree hanging below,\nso the named Session is often not a top-level one. That exposed a conflation in\nthe filter: `session_id` says whose row this is, while `parent_session_id` on\n`session_metadata` names a DIFFERENT Session it descends from.\n\nReading the second as ownership deleted the very Session being exported. A\nbranch Session whose source lay outside the subtree failed its own export --\nits row was dropped for naming a Session the bundle does not contain, which is\nexactly what a bundle rooted here is supposed to leave behind.\n\nOwnership is `session_id` when the table has one. The other columns are Session\ncolumns only on tables that have no `session_id`: link tables, whose whole\ncontent is the pair they join and which mean nothing when one end is missing.\n`subagent_spawns` is the one that matters, and it is why those columns are read\nat all.\n\nCovered by exporting from four kinds of node -- a top-level parent, a mid-tree\nchild whose parent stays behind, a leaf, and a branch Session whose source\nstays behind -- each carrying exactly its own subtree.\n\nClaude-Session: https://claude.ai/code/session_014ajaRxC4jydavY9nYUFj5J\n\n* fix(storage): stop publishing an entrypoint nothing imports\n\n`./artifact-metadata-codec` was exported for a throwaway probe while chasing an\nartifact that would not appear in a bundle. The probe is gone; the promise it\nneeded should not outlive it.\n\nClaude-Session: https://claude.ai/code/session_014ajaRxC4jydavY9nYUFj5J\n\n* fix(storage): derive the whole export from one private copy\n\nSix findings from review, five of them blocking. All but one share a root:\nthe plan was read from the live database while a different, later copy was\nwhat actually shipped.\n\n**One moment, not two.** The backup is taken first, and the subtree, schema,\nartifact list, quiescence check and manifest are all derived from that copy.\nThe artifact and context locks do not fence ordinary Session and runtime\nwriters, so a child Session created between the plan and the backup produced a\ndatabase, a set of files and a manifest describing different instants.\n\n**A read-only export no longer migrates its source.** The default open upgrades\nthe database in place; the backup now demands a current schema instead. And the\nschema check is the operational store\u0027s own inspector rather than a private\nlist, which was missing two of the seven scopes and could report versions the\nsource did not have.\n\n**Deleted bytes leave the file.** `DELETE` frees pages without erasing them, so\nthe bundle shipped a database whose freelist still held excluded Sessions\u0027\ncontent -- invisible to SQL, plain in the bytes. The filtered copy is vacuumed.\n\n**A row whose owner is NULL owns nothing.** The nullable guard was meant for\nlink endpoints, where naming no counterpart is not the same as naming one\noutside the bundle. Applied to the owner column it kept unattributable rows.\n\n**Symlinks are refused along the whole path.** `artifacts/\u003csessionId\u003e` can\nitself be a link, and `copyFile` follows ancestors, so an artifact record that\ndecodes perfectly could pull in a file from outside the workspace. Every\nsegment is checked and the bytes are read from a descriptor opened with\n`O_NOFOLLOW`. Node has no `openat`, so a segment swapped between its check and\nthe open is narrowed, not closed; the comment says so.\n\n**An unsettled tool operation is not a complete Session.** An invocation can\ncarry a terminal `failed` event while its operation is still prepared, so an\ninvocation check does not see it. Quiescence now uses the same predicate the\nruntime store uses, so the word means one thing.\n\nThe remaining finding is in the runtime layer: the packer publishes atomically\nand can lose the race the precheck cannot cover, and its `destination_exists`\nwas being flattened into a generic IO failure, giving the CLI a different exit\ncode for the same outcome.\n\nFive adversarial tests, one per blocking finding, each verified to fail when\nits fix is removed. The freelist one inspects the bundled file\u0027s bytes rather\nthan querying it, because that is the difference the finding is about."
    },
    {
      "commit": "a9b4f21afb17e0ef310d076382e69ddda3a441d7",
      "tree": "c58b27b0044d9c9dffc546e5fd7760efe1c9e8c2",
      "parents": [
        "f60fcb13970ba221c6f62743764a35ccb8a60885"
      ],
      "author": {
        "name": "ChengBo Zhang",
        "email": "66726968+ARE404@users.noreply.github.com",
        "time": "Thu Sep 10 13:11:25 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 10 13:11:25 2026 +0800"
      },
      "message": "refactor(workhub): separate linked operations from routing (#5117)"
    },
    {
      "commit": "f60fcb13970ba221c6f62743764a35ccb8a60885",
      "tree": "7f7eaa833f93d7b44da242c9e7aba2939ee4c20b",
      "parents": [
        "9fda54e17778e29ad1a0635e7c2efae9a94018c8"
      ],
      "author": {
        "name": "Zhang",
        "email": "96464454+me2seeks@users.noreply.github.com",
        "time": "Thu Sep 10 00:14:49 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 10 00:14:49 2026 +0800"
      },
      "message": "feat(mcp): connect Desktop and TUI to Host form continuation (#5068)"
    },
    {
      "commit": "9fda54e17778e29ad1a0635e7c2efae9a94018c8",
      "tree": "60877be855dbd26a655e8c30a4e5a0cd4abca661",
      "parents": [
        "8c02f3d3288ec8d0996b74380eb7a46c818831a6"
      ],
      "author": {
        "name": "Wang",
        "email": "m4n5terrr@gmail.com",
        "time": "Wed Sep 09 23:57:00 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 23:57:00 2026 +0800"
      },
      "message": "feat(desktop): improve WorkHub floating interaction and progress (#5114)"
    },
    {
      "commit": "8c02f3d3288ec8d0996b74380eb7a46c818831a6",
      "tree": "0c2dd9ee50e7c0e0fcacf3642d23739f961fb9a6",
      "parents": [
        "3725f2bad507bc2e3f1d8a475d4db84fadc17332"
      ],
      "author": {
        "name": "Mira",
        "email": "hey2missmira@gmail.com",
        "time": "Wed Sep 09 23:26:04 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 23:26:04 2026 +0800"
      },
      "message": "fix(cli): hide cursors in unfocused editors (#4733)\n\n* fix(cli): show setup cursor only on active field\n\nStrip Editor styling from inactive onboarding fields so pi-tui\u0027s synthetic reverse-video cursor is not rendered twice. Cover the Name-to-Slug transition with field-specific cursor assertions.\n\nGenerated-by: Codex\n\n* fix(cli): hide cursors in unfocused editors\n\nShare the pi-tui cursor compatibility rendering across inline fields and the main composer. Preserve drafts, borders, and other styles when focus moves to another field or overlay.\n\nCover wizard field switching, Other answer focus and combining characters, and composer focus restoration after an overlay closes.\n\nGenerated-by: Codex\n\n* test(cli): name input keys in focus regression\n\nUse named arrow and Enter key constants so the Other answer focus test reads as user actions.\n\nGenerated-by: Codex\n\n* docs(cli): illustrate cursor wrapper removal\n\nShow the matched ANSI wrapper and captured text in an aligned diagram, and document the format-based compatibility limit.\n\nGenerated-by: Codex\n\n* refactor(cli): separate editor rendering from cursor visibility\n\nRender fields before removing their borders and hiding unfocused cursors. Keep the full rendered output for the main composer, and name the shared layout helper renderFieldRow.\n\nGenerated-by: Codex\n\n* refactor(cli): name cursor style cleanup explicitly\n\nGenerated-by: Codex\n\n* test(cli): verify cursor restoration on combining characters\n\nCompare the refocused answer row with its rendering before selecting a preset, covering the cursor and IME marker position.\n\nGenerated-by: Codex\n\n* refactor(cli): preserve field rendering label parameter\n\nGenerated-by: Codex\n\n* test(cli): describe focus changes with cursor fixtures\n\nGenerated-by: Codex\n\n* test(cli): clarify focus test names and flow\n\nGenerated-by: Codex\n\n* test(cli): simplify identity assertion and cleanup\n\nGenerated-by: Codex\n\n* fix(ci): classify the TUI cursor style helper\n\nThe new helper only transforms ANSI styles and contains no user-facing copy. Register it alongside the other rendering infrastructure so the TUI copy inventory accepts it.\n\nGenerated-by: Codex\n\n---------\n\nCo-authored-by: Jover \u003cjoverzh@gmail.com\u003e"
    },
    {
      "commit": "3725f2bad507bc2e3f1d8a475d4db84fadc17332",
      "tree": "84d60d8a0ad86997d69aa8b0d0bf168398d4b682",
      "parents": [
        "fb8b15d085425daffcf0bdc25ec4574345efa6d4"
      ],
      "author": {
        "name": "AstroHan",
        "email": "lei.yuhan@outlook.com",
        "time": "Wed Sep 09 23:06:05 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 23:06:05 2026 +0800"
      },
      "message": "fix(ui): preserve transcript intent and layout through submission (#5057)\n\n* fix(ui): separate transcript reading intent from layout changes\n\n* fix(ui): lay out the streaming frontier before tail following\n\n* test(desktop): express reader input in send viewport fixture\n\n* test(perf): establish reading intent before transcript scrolling\n\n* fix(ui): preserve tail following during Meta wheel zoom\n\n* fix(ui): synchronize controlled composer content before paint\n\n* fix(ui): preserve turn layout across message settlement\n\n* chore(ui): normalize vendor patch and clarify scroll contracts\n\n* refactor(ui): make transcript scroll ownership unconditional\n\n* chore(desktop): refresh architecture ledger after scroll cleanup"
    },
    {
      "commit": "fb8b15d085425daffcf0bdc25ec4574345efa6d4",
      "tree": "43e233cf67719ac38f763c9a5fe0b6c4d8a3c9f2",
      "parents": [
        "30346ea48bc009c339d4143c490370156d7b1946"
      ],
      "author": {
        "name": "Zhang",
        "email": "96464454+me2seeks@users.noreply.github.com",
        "time": "Wed Sep 09 22:39:42 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 22:39:42 2026 +0800"
      },
      "message": "fix(runtime-host): preserve request acknowledgement headroom (#5108)\n\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "30346ea48bc009c339d4143c490370156d7b1946",
      "tree": "a75b0bd7d4d5997f74388953d77644c96bdc23a9",
      "parents": [
        "bb2e270ee530c898a9244f9509af1d5610c5c966"
      ],
      "author": {
        "name": "Wang",
        "email": "m4n5terrr@gmail.com",
        "time": "Wed Sep 09 22:38:49 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 22:38:49 2026 +0800"
      },
      "message": "docs(architecture): rewrite Runtime Host and define Peer Mesh contracts (#5110)\n\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "bb2e270ee530c898a9244f9509af1d5610c5c966",
      "tree": "1ecdb19c426b98ac48b7d431844bf152e048f3ce",
      "parents": [
        "5dd87d2e01160775e0c0f5f64345484ed8ac529d"
      ],
      "author": {
        "name": "Wang",
        "email": "m4n5terrr@gmail.com",
        "time": "Wed Sep 09 22:37:56 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 22:37:56 2026 +0800"
      },
      "message": "docs(blog): explain Runtime Host and Peer Mesh architecture (#5074)\n\n* docs(blog): explain how Runtime Host shares work across clients\n\nGenerated-by: OpenAI Codex\n\n* docs(blog): render Runtime Host diagrams with Mermaid\n\nGenerated-by: OpenAI Codex\n\n* docs(blog): explain Peer Mesh and cross-device collaboration\n\nGenerated-by: OpenAI Codex\n\n* docs(blog): remove validation proposals from Peer Mesh outlook\n\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "5dd87d2e01160775e0c0f5f64345484ed8ac529d",
      "tree": "25f78006600931d483c59c1b8ea9f6f4c4bdae69",
      "parents": [
        "e04d52bbd80ec06c0d26b985edc70c45cab33501"
      ],
      "author": {
        "name": "Zhang",
        "email": "96464454+me2seeks@users.noreply.github.com",
        "time": "Wed Sep 09 22:37:17 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 22:37:17 2026 +0800"
      },
      "message": "fix(eval): update DeepSeek Harness security dependencies (#5084)\n\n* fix(eval): update DeepSeek Harness security dependencies\n\nUpdate Hono, sharp, and js-yaml together, then repin the rebuilt linux/amd64 toolchain fingerprint.\n\nGenerated-by: Codex\n\n* test(ci): rebuild DeepSeek Harness toolchain in CI\n\nRequire hosted CI to regenerate and verify the pinned linux/amd64 toolchain fingerprint whenever its inputs change.\n\nGenerated-by: Codex"
    },
    {
      "commit": "e04d52bbd80ec06c0d26b985edc70c45cab33501",
      "tree": "d89b6385f4e43305d5f1781f3aefdeea2756de90",
      "parents": [
        "09c73430cc7ff0d106d617cdb4a93015d49deb5b"
      ],
      "author": {
        "name": "Zhang",
        "email": "96464454+me2seeks@users.noreply.github.com",
        "time": "Wed Sep 09 22:21:02 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 22:21:02 2026 +0800"
      },
      "message": "feat(mcp): implement bounded form input_required continuation (#5067)\n\n* feat(mcp): implement bounded form input_required continuation\n\nGenerated-by: OpenAI Codex\n\n* test(release): account for MCP form fixture export\n\nGenerated-by: OpenAI Codex\n\n* fix(mcp): protect continuation state across connection diagnostics\n\nReject raw state-bearing forms before display projection and retain a bounded connection inventory for delayed stderr. Fence exhausted connections and clear projected diagnostic tails when learning new states.\n\nGenerated-by: OpenAI Codex\n\n* test(mcp): cover privacy exhaustion with an open form\n\nPin cancellation of an already displayed, uncooperative form callback when a concurrent call exceeds the continuation state limit. Verify that a late answer cannot retry.\n\nGenerated-by: OpenAI Codex\n\n* test(mcp): require prompt cancellation on privacy exhaustion\n\nAssert pending calls reject while their server response remains blocked, so post-response fencing cannot mask a missing cancellation signal.\n\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "09c73430cc7ff0d106d617cdb4a93015d49deb5b",
      "tree": "036f28e708fcb35c700052ea4b89d7e0f398abfa",
      "parents": [
        "ba849f404991af1f374df38a352f3ff5dc29d2ae"
      ],
      "author": {
        "name": "Wang",
        "email": "m4n5terrr@gmail.com",
        "time": "Wed Sep 09 20:38:43 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 20:38:43 2026 +0800"
      },
      "message": "fix(desktop): round transparent WorkHub floating windows (#5105)\n\nClip both the floating surface and global grain overlay so Windows does not rely on native rounded corners for a transparent window.\n\nGenerated-by: Codex"
    },
    {
      "commit": "ba849f404991af1f374df38a352f3ff5dc29d2ae",
      "tree": "481195347d810a104d1117e504351807c91863ca",
      "parents": [
        "b79a9946d76b725af7058e9180ea977409f7b114"
      ],
      "author": {
        "name": "Zhang",
        "email": "96464454+me2seeks@users.noreply.github.com",
        "time": "Wed Sep 09 20:21:59 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 20:21:59 2026 +0800"
      },
      "message": "fix(runtime-host): normalize missing SQLite sessions (#5099)\n\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "b79a9946d76b725af7058e9180ea977409f7b114",
      "tree": "8bc5b317fcacb9134d4cc9cc8bccc68b37f14c47",
      "parents": [
        "6de29ee2e9831b70560f51533ed948f397627f7d"
      ],
      "author": {
        "name": "Zhang",
        "email": "96464454+me2seeks@users.noreply.github.com",
        "time": "Wed Sep 09 20:21:29 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 20:21:29 2026 +0800"
      },
      "message": "fix(runtime-host): retain connection teardown failures (#5106)\n\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "6de29ee2e9831b70560f51533ed948f397627f7d",
      "tree": "b2fd48ec05abc19efec8a19a2a027f90083d6973",
      "parents": [
        "72687bc5fc2dd6a0d733162aa865a4967c728012"
      ],
      "author": {
        "name": "Zhang",
        "email": "96464454+me2seeks@users.noreply.github.com",
        "time": "Wed Sep 09 20:21:16 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 20:21:16 2026 +0800"
      },
      "message": "fix(desktop): keep inactive Graph panels hidden on read failure (#5089)\n\nFixes #5088\n\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "72687bc5fc2dd6a0d733162aa865a4967c728012",
      "tree": "19d5dfc9578223b72673ffb03a5e14ed0804c02e",
      "parents": [
        "920adead416ced8476e4879ca3fa7730d9cad3c2"
      ],
      "author": {
        "name": "Wang",
        "email": "m4n5terrr@gmail.com",
        "time": "Wed Sep 09 19:03:34 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 19:03:34 2026 +0800"
      },
      "message": "fix(runtime-host): fence shutdown admission and cancel pending startup (#5094)"
    },
    {
      "commit": "920adead416ced8476e4879ca3fa7730d9cad3c2",
      "tree": "a30fc14a1699f10af533312acc461d730e8831ed",
      "parents": [
        "fcff80f58910f4de118fd7edbf7f02068239c50a"
      ],
      "author": {
        "name": "Wang",
        "email": "m4n5terrr@gmail.com",
        "time": "Wed Sep 09 19:03:21 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 19:03:21 2026 +0800"
      },
      "message": "fix(desktop): keep local tasks available during Host recovery (#5101)"
    },
    {
      "commit": "fcff80f58910f4de118fd7edbf7f02068239c50a",
      "tree": "bace6364703d9d5245e176bfb0dc5b4d2fb8386f",
      "parents": [
        "0b2aa1a54033edd90aad82e76294942637f0bc5a"
      ],
      "author": {
        "name": "Dante.Cloud",
        "email": "chinawch_007@163.com",
        "time": "Wed Sep 09 17:36:37 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 17:36:37 2026 +0800"
      },
      "message": "fix(storage): unify atomic writes for JSON config stores (#4505)\n\nConsolidate settings, MCP configuration and credential JSON publication on the shared atomic writer while preserving each store\u0027s permission policy and platform-specific synchronization guarantees.\n\nDistinguish post-rename durability uncertainty from pre-publication failure. Reconcile MCP runtime and visible state from the authoritative published configuration without replaying mutations or credential retirement, and expose actionable localized errors.\n\nThe JSON format is unchanged. Synchronization guarantees remain conditional on the filesystem, hardware and operating system APIs.\n\nRefs #4285\n\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "0b2aa1a54033edd90aad82e76294942637f0bc5a",
      "tree": "5770131b7c99e13225dc325a778978f98655a9a5",
      "parents": [
        "30cf0beb0def57626df3fdbf8c7ab4d0d3436896"
      ],
      "author": {
        "name": "Wang",
        "email": "m4n5terrr@gmail.com",
        "time": "Wed Sep 09 17:36:20 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 17:36:20 2026 +0800"
      },
      "message": "feat(desktop): unify WorkHub conversation and floating controls (#4979)\n\n* feat(desktop): add a scoped assistant with visible UI control\n\nGenerated-by: Codex\n\n* refactor(desktop): smooth assistant cursor movement along gentle arcs\n\nGenerated-by: Codex\n\n* feat(desktop): operate application controls with a persistent assistant cursor\n\nGenerated-by: Codex\n\n* fix(desktop): recover assistant actions through a fixed overlay\n\nGenerated-by: Codex\n\n* fix(desktop): defer first-task reads until Host creation completes\n\nGenerated-by: Codex\n\n* feat(desktop): batch assistant actions against known controls\n\nGenerated-by: Codex\n\n* fix(ci): refresh desktop assistant surface inventories\n\nGenerated-by: Codex\n\n* feat(desktop): unify WorkHub conversation and floating controls\n\nKeep one durable coordination Session and one live renderer across docking, floating and hiding. Route input through its model, preserve delegated task authority, and reuse the shared composer, attachments and transcript ledger.\n\nGenerated-by: Codex\n\n* fix(desktop): keep WorkHub navigation readable and cancel observations cleanly\n\nGenerated by Codex\n\n* fix(desktop): preserve WorkHub overlays and refine floating defaults\n\n* fix(desktop): make floating WorkHub expansion respond to native clicks\n\n* fix(desktop): animate WorkHub resizing and content reveal\n\nGenerated-by: Codex\n\n* fix(desktop): preserve transcript navigation after WorkHub migration\n\nGenerated-by: Codex\n\n* fix(desktop): show WorkHub prompts immediately while agents run\n\nGenerated-by: Codex\n\n* test(desktop): register WorkHub send visibility regression\n\nGenerated-by: Codex\n\n* fix(desktop): keep WorkHub visible without interrupting on pointer motion\n\nGenerated-by: Codex\n\n* fix(desktop): preserve Dock visibility when floating WorkHub\n\n* feat(ui): drag the model wheel and snap on release\n\n* fix(workhub): show waiting feedback immediately on send\n\nGenerated-by: Codex\n\n* refactor(workhub): retire legacy routing and separate floating visibility\n\nUse active coordination Turns for task actions, share document appearance, and keep shortcut visibility separate from explicit docking.\n\nGenerated-by: Codex\n\n* fix(workhub): release retired persisted operation grants\n\nAccount for legacy act and record grants during credential migration without granting active-turn authority. Refresh the renderer inventory after rebasing onto main.\n\nGenerated-by: Codex\n\n* fix(workhub): recover crashed views and align observation and selection contracts\n\nRecreate a crashed renderer through the existing presentation lifecycle and revalidate queued IPC ownership. Keep wheel preview separate from committed accessibility selection, reuse focus tokens, and remove heuristic secret detection in favor of explicit observation boundaries.\n\nGenerated-by: Codex\n\n* fix(workhub): expose retry for a crashed docked conversation\n\nPublish unexpected renderer exits through the existing presentation owner and restore through its explicit dock action. Keep geometry notifications from triggering automatic reloads; verify recovery with an active session and unchanged dock bounds.\n\nGenerated-by: Codex\n\n* fix(workhub): reconcile pending stops and honor the enable setting\n\nRetain exact Session/Turn Stop intent across delayed or uncertain admission and retire it on interruption, rejection or terminal evidence. Gate native presentation through the existing client setting and hide on disable without discarding drafts or cancelling Host work.\n\nGenerated-by: Codex\n\n* fix(workhub): reconcile uncertain sends and recover initial reads\n\nReconcile unknown answers through the existing IPC replacement owner and Host Turn admission lookup, preserving the original payload and epoch. Keep busy and Stop bound to that attempt until Host facts settle it.\n\nUse the recovering transcript controller and observation readiness, expose a real read retry without discarding in-flight messages, and guard control presentation before opening the main window.\n\nValidation: 2,399 Desktop tests, typecheck, lint, formatting, Knip, renderer architecture and three WorkHub Electron scenarios pass. Six counterfactual recovery checks and the original-Turn busy check fail without their corrections.\n\nGenerated-by: Codex"
    },
    {
      "commit": "30cf0beb0def57626df3fdbf8c7ab4d0d3436896",
      "tree": "3f5122ecb3528bd8938bd328b17ddf4c04d7670d",
      "parents": [
        "56c1ab76c0a8b87577c744b70c63bbb2a8ade478"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Wed Sep 09 15:52:09 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 15:52:09 2026 +0800"
      },
      "message": "chore(deps): bump hono from 4.12.34 to 4.13.7 (#5077)\n\nBumps [hono](https://github.com/honojs/hono) from 4.12.34 to 4.13.7.\n- [Release notes](https://github.com/honojs/hono/releases)\n- [Commits](https://github.com/honojs/hono/compare/v4.12.34...v4.13.7)\n\n---\nupdated-dependencies:\n- dependency-name: hono\n  dependency-version: 4.13.7\n  dependency-type: indirect\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "56c1ab76c0a8b87577c744b70c63bbb2a8ade478",
      "tree": "1b1b086c41d6b011ff05f56fb9ddf585b66d0611",
      "parents": [
        "411e0c4771760831b0b29e000583eb449911a2b7"
      ],
      "author": {
        "name": "Xiao Liu",
        "email": "liuxiao2103@qq.com",
        "time": "Wed Sep 09 15:13:49 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 15:13:49 2026 +0800"
      },
      "message": "fix(desktop): keep session skill picker stable (#5045)\n\nIdentify an existing Session skill catalog by sessionId so late project metadata and new-task defaults cannot clear its settled options. Preserve explicit catalog refresh and cover the late-project-path regression.\n\nFixes #5044\n\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "411e0c4771760831b0b29e000583eb449911a2b7",
      "tree": "943d72560a8ca6e1d856960754d10354e7a95a27",
      "parents": [
        "edae35e228d8dc7d05c64a385187dc03e28b31bb"
      ],
      "author": {
        "name": "Zhang",
        "email": "96464454+me2seeks@users.noreply.github.com",
        "time": "Wed Sep 09 15:13:40 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 15:13:40 2026 +0800"
      },
      "message": "fix(mcp): default new Desktop and TUI servers to auto (#5064)\n\n* fix(mcp): default new Desktop and TUI servers to auto\n\nGenerated-by: OpenAI Codex\n\n* test(mcp): preserve both auto selection paths and clarify SSE default\n\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "edae35e228d8dc7d05c64a385187dc03e28b31bb",
      "tree": "07c6e0b9cc9d2678844ef472abe59db85464b5d8",
      "parents": [
        "331f1edbad6aacf996e342133cdd2e3606cf0149"
      ],
      "author": {
        "name": "Xiao Liu",
        "email": "liuxiao2103@qq.com",
        "time": "Wed Sep 09 15:13:25 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 15:13:25 2026 +0800"
      },
      "message": "perf(desktop): cache workspace file search (#5040)\n\nReuse workspace enumeration across nearby composer queries, coalesce same-root misses, sort once, and bound retained cache entries with TTL and LRU eviction. Do not cache degraded Git-failure results.\n\nFixes #5039\n\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "331f1edbad6aacf996e342133cdd2e3606cf0149",
      "tree": "31f83fe90459a5da4237d97fffde65457cebfd71",
      "parents": [
        "7129b19964b38cedbb150fbf8dbd0aa7ef91981a"
      ],
      "author": {
        "name": "Xiao Liu",
        "email": "liuxiao2103@qq.com",
        "time": "Wed Sep 09 15:13:03 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 15:13:03 2026 +0800"
      },
      "message": "fix(storage): reclaim upgrade residue safely (#4922)\n\nReuse artifact removal identity and real-parent containment for upgrade residue cleanup. Preserve bounded pagination and retain unsafe or failed cleanup notes without deleting live aliases.\n\nFixes #4910\n\nGenerated-by: Codex"
    },
    {
      "commit": "7129b19964b38cedbb150fbf8dbd0aa7ef91981a",
      "tree": "96f5ee026f3d83b1dd4de009667578ed706f77b3",
      "parents": [
        "a41d3ac4a76d8c5ac5154032acb9dbb123e847a6"
      ],
      "author": {
        "name": "Sun-GLiang",
        "email": "81428141+Sun-GLiang@users.noreply.github.com",
        "time": "Wed Sep 09 15:12:28 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 15:12:28 2026 +0800"
      },
      "message": "fix(runtime-host): detach composition drain from admission (#4661)\n\nDetach composition drain from inherited Session admission while preserving the kernel shutdown gate and per-Session stop serialization. Observe stop rejection immediately and retain the original failure diagnostic.\n\nFixes #4656\n\nGenerated-by: Codex"
    },
    {
      "commit": "a41d3ac4a76d8c5ac5154032acb9dbb123e847a6",
      "tree": "90a78c1d57df96d0b533ebfdfcfea55bf760e813",
      "parents": [
        "8d5c4612c46b19270f00fe7aea33c39dff23dbe5"
      ],
      "author": {
        "name": "ChengBo Zhang",
        "email": "66726968+ARE404@users.noreply.github.com",
        "time": "Wed Sep 09 14:24:53 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 14:24:53 2026 +0800"
      },
      "message": "fix(workhub): admit coordination actions through Runtime turns (#4993)"
    },
    {
      "commit": "8d5c4612c46b19270f00fe7aea33c39dff23dbe5",
      "tree": "a815aed3ad52f7a7c3a08e56d5f0e5a415253d08",
      "parents": [
        "9cb5cc93c03f8d07550e739164d5e33168892563"
      ],
      "author": {
        "name": "Wang",
        "email": "m4n5terrr@gmail.com",
        "time": "Wed Sep 09 10:30:19 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 10:30:19 2026 +0800"
      },
      "message": "fix(runtime-host): distinguish idle retention from active background work (#5060)\n\n* fix(runtime-host): include daily review in safe host handoff\n\nPause Daily Review scheduling during cooperative handoff, wait for active generation, and restore scheduling on cancellation or successor recovery. Track generation separately so completed work can unblock automatic retries.\n\nGenerated-by: OpenAI Codex\n\n* fix(runtime-host): distinguish idle retention from active background work\n\nClassify durable Daily Review schedules, scheduled tasks, and Goals as idle retention. Track review generation, scheduled dispatch, Goal evaluation/admission, and persistence as active work so startup handoff and quit probes share the same accounting. Show background activity separately in handoff copy.\n\nGenerated-by: OpenAI Codex\n\n* fix(runtime-host): retain activity throughout hosted admission\n\nAcquire the admission residency at the shared root authority before asynchronous gates, keeping it until execution takes over or admission fails.\n\nGenerated-by: OpenAI Codex"
    },
    {
      "commit": "9cb5cc93c03f8d07550e739164d5e33168892563",
      "tree": "66f3e03be121b1f879436945d1a8337ed88f233f",
      "parents": [
        "9693a5d76bea5ae8c4837c4fc38b283406f56467"
      ],
      "author": {
        "name": "AstroHan",
        "email": "lei.yuhan@outlook.com",
        "time": "Wed Sep 09 02:10:58 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 02:10:58 2026 +0800"
      },
      "message": "ci(perf): add manual frontend and protocol measurements (#5042)\n\n* ci(perf): add manual frontend and protocol measurements\n\nGenerated-by: Codex\n\n* ci(perf): temporarily validate workflows on this PR branch\n\nGenerated-by: Codex\n\n* test(perf): verify concurrent output and cold reading geometry\n\nGenerated-by: Codex\n\n* test(perf): exercise fixed-rate streams and scoped session keys\n\nGenerated-by: Codex\n\n* test(perf): use admitted sessions and retain browser diagnostics\n\nGenerated-by: Codex\n\n* test(perf): validate rendered text and visible tool activation\n\nGenerated-by: Codex\n\n* test(perf): verify stopping a fixed-rate stream\n\nGenerated-by: Codex\n\n* test(perf): calibrate the actual Electron blocking sampler\n\nGenerated-by: Codex\n\n* ci(perf): follow checkout credential policy\n\nGenerated-by: Codex\n\n* fix(perf): verify stop through interrupted consumer state\n\nGenerated-by: Codex\n\n* ci(perf): retain only manual triggers after acceptance\n\nGenerated-by: Codex\n\n* fix(perf): isolate assertions and explicitly name reports\n\nGenerated-by: Codex"
    }
  ],
  "next": "9693a5d76bea5ae8c4837c4fc38b283406f56467"
}
