50f17b1300
Google Docs can hold a tree of tabs, each with its own body and its own 1-based character index space; the legacy top-level `body` only carries the first tab. `docs get` was silently dropping every other tab's content, and `docs append` computed its insert index from the first tab's body and sent the write with no tabId — so on a tabbed doc the append could land at a wrong offset in the wrong tab. - Requests now pass includeTabsContent=true (both gws and SDK paths). - `docs get` returns a `tabs` array (preorder flattening of the tabs/childTabs tree, nested tabs included); single-tab docs keep the `body` field so existing callers work, and `--tab <tabId>` reads one tab. Legacy no-tabs responses are unchanged. - `docs append` targets exactly one tab: the insert location carries the tabId, the end index is computed inside that tab's own body, an unknown `--tab` errors instead of falling back to the first tab, and a multi-tab doc without `--tab` errors with the tab list rather than guessing. Tabs are never merged — index spaces are independent. Adapted from cloudflare/cloudflare-os#450 (gatekeeper-google), which fixed the same provider behavior: reads must traverse Document.tabs and every write Location must carry the immutable tabId. Two pre-existing bare read_text/write_text in the touched test file gained encoding="utf-8" (windows-footgun sweep rule).