{
  "markdown": "# opencode-tools\n\n> [!NOTE]\n> Heavily inspired by:\n> - [the upstream project](https://github.com/slkiser/opencode-quota)\n> - [farrukh2002/opencode-glm-reset](https://github.com/farrukh2002/opencode-glm-reset)\n> - [Hotakus/opencode-subagent-magazine](https://github.com/Hotakus/opencode-subagent-magazine)\n> - [njbraun/opencode-plugin-session-token-summary](https://github.com/njbraun/opencode-plugin-session-token-summary)\n\nOpenCode TUI plugins that show quota usage, reset countdowns, rate-limit\nstatus, compact homepage summaries, MCP server health, active-session context\nand spend, LSP status, synchronized session TODOs, complete session-tree token\ntotals, direct-child SubAgent activity, and `/tokens_*` reports for **Z.AI\n(GLM)**, **OpenAI (ChatGPT Plus/Pro)**, and **OpenCode Go**.\n\n![opencode-tools homepage bottom](img/img0.jpg)\n\n<table>\n  <tr>\n    <td width=\"50%\">\n      <img src=\"img/new-img1.jpg\" alt=\"Old TUI sidebar panel\" />\n    </td>\n    <td width=\"50%\">\n      <img src=\"img/new-img2.jpg\" alt=\"New TUI sidebar panel\" />\n    </td>\n  </tr>\n</table>\n\n## Quick Install\n\nRequires OpenCode 1.18.1 or newer, Git, and Node.js with npm.\n\n```bash\ngit clone https://github.com/aamkye/opencode-tools.git\ncd opencode-tools\nnpm ci\nnpm run deploy:global\n```\n\nFully restart OpenCode after deployment.\n\n## Features\n\n### Z.AI (`zai-coding-plan`)\n\n- **5H token quota** — remaining %, live countdown to next reset, and absolute\n  token counts (`used / total`) when the plan exposes them (Max/Pro).\n- **7D weekly limit** — same bar + countdown; shows \"Unlimited (Legacy)\"\n  when the plan has no weekly cap.\n- **Peak/off-peak indicator** — Peak (14:00–18:00 SGT, 3x usage)\n  vs Off-Peak.\n- **Limited indicator** — shows when the 5H quota is exhausted.\n- **Heuristic fallback** — if the API is unreachable, scans the session's\n  message parts for a reset time and falls back to a clock-based estimate.\n\n### OpenAI (ChatGPT Plus/Pro)\n\n- **API-reported quota windows** — primary and optional secondary windows use\n  compact labels derived from their API-reported duration, such as `5H`, `7D`,\n  or `1M`, and show remaining percentage plus reset countdown.\n- **Plan type** — Plus / Pro / Pro Lite / Team.\n- **Limited indicator** — shows when rate limit is reached.\n\n### OpenCode Go\n\n- **Subscription windows** — exact remaining usage for rolling 5H, weekly 7D,\n  and subscription month 1M windows.\n- **Shared refresh behavior** — uses the configured polling interval,\n  one-second countdowns, reset-boundary refresh, and a ten-minute stale horizon\n  without exhausted backoff.\n\n### MCP\n\n- **Reactive server health** — shows OpenCode's synchronized MCP server list in\n  source order without polling.\n- **Native status roles** — connected, disabled, failed, authentication, and\n  client-registration states use compact labels and status-colored bullets.\n- **Session-local collapse state** — resets to the configured default whenever\n  the active session changes. The collapsed header shows a\n  `success/warning/error` health rollup (connected, disabled, and error-state\n  counts) that stays compact as a colored `0/0/0` summary when the server list\n  is empty.\n\n### Context\n\n- **Reactive active-session metrics**: updates context and spend values from\n  synchronized session and message state without polling.\n- **Newest positive assistant token selection**: sums finite detailed `input`,\n  `output`, `reasoning`, `cache.read`, and `cache.write` buckets and uses the\n  newest assistant message whose sum is positive.\n- **Cumulative finite assistant spend**: sums finite assistant-message costs for\n  the active session and ignores missing or non-finite costs.\n- **Unavailable values**: shows `Tokens -`, `Used -`, and `Spent $0.00` when the\n  host has not supplied usable context data. When consumed tokens are known but\n  the model context limit is unavailable, the panel preserves the known `Tokens`\n  value and accumulated `Spent`, while `Limit`, `Used`, and the collapsed summary\n  remain `-`.\n- **Session-local collapse state**: resets to the configured default whenever\n  the active session changes.\n\n### LSP\n\n- **Reactive server list** — shows OpenCode's synchronized LSP IDs in source\n  order without polling.\n- **Operating directory** — each row shows the basename of the server's `root`\n  (the directory where it operates), right-aligned in the muted label color.\n  Servers with an empty `root` show the id alone.\n- **Status-colored bullets** — successful servers use the success color,\n  failed servers use the error color, and unknown statuses remain in the list\n  with a muted bullet.\n- **Session-local collapse state** — resets to the configured default whenever\n  the active session changes and shows `LSPs will activate as files are read`\n  when the expanded list is empty.\n\n### TODO\n\n- **Synchronized session scope** — shows the active session's TODO records in\n  source order without polling.\n- **Status markers** — uses `[✓]` for completed, `[•]` for in-progress, `[ ]`\n  for pending or unknown, and `[-]` for cancelled records.\n- **Aligned wrapped rows** — reserves four cells for each marker so continuation\n  lines align beneath the content column. An empty list shows\n  `No TODOs for this session`.\n- **Session-local collapse state** — resets to the configured default whenever\n  the active session changes and summarizes `done/working/todo` counts\n  (cancelled excluded) in the collapsed header.\n\n### SesTokens\n\n- **Assistant-only full-tree totals**: aggregates assistant messages across the\n  selected root session and its complete descendant tree.\n- **All detailed token buckets**: reports input, output, reasoning, cache read,\n  and cache write. Total is input + output + reasoning + cache read + cache\n  write; cache hit ratio is cache read / (input + cache write).\n- **Compact absolute counts**: uses K/M/B suffixes with up to two decimal places\n  and trimmed zeroes. The collapsed summary shows only the aggregate total.\n- **Event-driven refresh**: uses a 200 ms event debounce and 2, 4, and 8 second\n  retries. It does not poll or calculate cost.\n- **Stale recovery**: retains the last successful snapshot as stale and\n  recovers it to ready after a successful refresh.\n- **Memory-only data**: Snapshots and collapse choices are memory-only. Selecting\n  another session resets the panel to its configured or built-in default.\n\n### SubAgent\n\n- **Direct-child monitoring**: monitors direct child sessions of the selected\n  parent, ordered newest first. The newest five stay in the primary group and\n  older children appear under `Rest`.\n- **Status precedence**: failed takes precedence over running and successful;\n  busy or retry is running; idle or a completed assistant message is\n  successful; otherwise the child remains running.\n- **Duration and details**: each row shows a live duration for running children\n  and a terminal duration for successful or failed children. Expanding a row\n  shows its agent, status, time, model, and `Open Session` action.\n  Compact durations and expanded time values use the child's status color.\n  Compact titles are grapheme-safe and end-truncated beside a fixed seven-cell,\n  right-aligned duration box with a two-cell structural margin. Expanded titles\n  wrap in full without a duration reservation.\n  The Rest disclosure and title are muted, and its divider is two muted three-dash segments separated by flexible space.\n- **Session-local interaction state**: panel collapse, `Rest` collapse, and an\n  expanded child reset whenever the active session changes. Retained failure\n  evidence remains persistent per parent session.\n- **Stale and empty behavior**: a failed refresh after ready data retains the\n  complete entry body and marks the panel stale. Loading, unavailable, and\n  unselected states emit no panel output; a ready parent without direct children\n  shows `No subagents`.\n\n### Shared\n\n- **Homepage summary** — each provider plugin also registers a compact homepage\n  line, such as `Z.AI: Max; 93%/84%` or `OpenAI: Pro Lite; 96%/84%`.\n- **`/tokens_*` commands** — server plugin providing token usage and cost\n  reports: `/tokens_today`, `/tokens_daily`, `/tokens_weekly`, `/tokens_monthly`,\n  `/tokens_all`, `/tokens_session`, `/tokens_session_all`, `/tokens_between`.\n  Reads from `opencode.db` with full models.dev pricing resolution.\n- **Color-coded bars** — green above 30% remaining, amber at ≤30%,\n  red at ≤10% remaining.\n- **Provider names, plan types, and bar labels** use the theme foreground\n  colour; only the bar fills and percentages are colour-coded.\n- **Smart polling (Z.AI and OpenAI)** — checks the quota API every 10s by\n  default, backing off to 5min when the primary window is exhausted.\n- **Expandable** — click the header to show weekly / tool / absolute details.\n- **Stale handling** — keeps showing the last known data through transient\n  fetch failures and marks `stale` in the right-aligned provider header.\n\n## Local-only usage\n\nThe plugins are built and loaded only from local files. This package is not\npublished to npm, and OpenCode is never configured with an npm package spec.\nOpenCode 1.18.1 or newer is required for the standalone TUI plugin and\nsynchronized MCP, Context, LSP, TODO, session-tree, and SubAgent state APIs.\n\n### Configuration\n\nNative TUI options can be supplied with the local plugin entry:\n\n```json\n{\n  \"$schema\": \"https://opencode.ai/tui.json\",\n  \"plugin\": [\n    \"./opencode-tools-home.js\",\n    \"./opencode-tools-token-report.js\",\n    \"./opencode-tools-context.js\",\n    \"./opencode-tools-ses-tokens.js\",\n    \"./opencode-tools-subagent.js\",\n    [\n      \"./opencode-tools-quota.js\",\n      {\n        \"quota\": {\n          \"refreshIntervalSeconds\": 10,\n          \"progressColors\": {\n            \"enabled\": true,\n            \"errorBelow\": 10,\n            \"warningBelow\": 30\n          },\n          \"percentageMode\": \"remaining\",\n          \"hideInactive\": false,\n          \"openai\": { \"hideInactive\": false },\n          \"zai\": { \"hideTools\": false, \"hideInactive\": false },\n          \"opencodego\": {\n            \"workspaceId\": \"wrk_TESTWORKSPACE\",\n            \"workspaceToken\": \"TOKEN_TEST_ONLY_DO_NOT_USE\",\n            \"hideInactive\": false\n          },\n          \"otherProviders\": { \"sortDirection\": \"desc\" }\n        }\n      }\n    ],\n    \"./opencode-tools-mcp.js\",\n    \"./opencode-tools-lsp.js\",\n    \"./opencode-tools-todo.js\"\n  ],\n  \"plugin_enabled\": {\n    \"internal:sidebar-context\": false,\n    \"internal:sidebar-mcp\": false,\n    \"internal:sidebar-lsp\": false,\n    \"internal:sidebar-todo\": false\n  }\n}\n```\n\nContext ships as a separate opt-in artifact. Enable it by adding\n`./opencode-tools-context.js` to the `plugin` array.\n\nThe entries must remain standalone and in manifest order. Quota accepts the\nquota options object; each sidebar panel (Context, SesTokens, SubAgent, MCP,\nLSP, TODO) optionally accepts an options object with `defaultState` and `chip`.\nHome and token-report use string entries.\n\n#### Default collapse state\n\nAny sidebar panel can be configured with `defaultState`. Whenever the active\nsession ID changes, including returning to a previously opened session, every\npanel resets to that configured state. A missing or invalid value uses the\nbuilt-in `\"expanded\"` default. Header and secondary-section toggles remain local\nto the currently selected session and are not persisted.\n\n| Plugin                             | Accepted values                                           |\n| ---------------------------------- | --------------------------------------------------------- |\n| Context, SesTokens, MCP, LSP, TODO | `\"expanded\"` (default), `\"collapsed\"`                     |\n| SubAgent, Quota                    | `\"expanded\"` (default), `\"semi-collapsed\"`, `\"collapsed\"` |\n\n`\"semi-collapsed\"` starts the panel expanded with the secondary section (Rest /\nOther Providers) collapsed; it is ignored for panels without a secondary section.\n\n```json\n[\"./opencode-tools-context.js\", { \"defaultState\": \"collapsed\" }]\n```\n\nMCP, Context, LSP, and TODO have no built-in panel override to disable.\nSesTokens has no built-in panel override. The SubAgent has no built-in panel\noverride. The other external panels do not deactivate their built-in\ncounterparts. Users must disable `internal:sidebar-mcp`, `internal:sidebar-lsp`,\nand `internal:sidebar-todo` themselves, as shown by `plugin_enabled`, to avoid\nduplicate panels.\n\n`quota.opencodego.workspaceId` identifies the OpenCode Go workspace.\n`quota.opencodego.workspaceToken` authenticates the console request;\nworkspaceToken is the plaintext auth cookie value. Keep both values only in\nlocal `.opencode/tui.json`: they must not be committed or shared, and you must\nrotate the console session when it expires, is revoked, or is exposed.\n\nThe provider sends these workspace credentials only to the fixed\n`https://opencode.ai` origin; they do not replace the OpenCode-managed\ninference API key. The sidebar reports exact remaining usage for rolling 5H,\nweekly 7D, and subscription month 1M windows. OpenCode Go reads the\nundocumented Solid hydration contract from the authenticated page and fails\nclosed if that contract changes. It does not scrape visible text, save page\nHTML, or estimate quota from local cost.\n\nOpenCode Go uses the shared default/custom polling interval, one-second\ncountdowns, reset-boundary refresh, and a ten-minute stale horizon without\nexhausted backoff.\n\nDefaults are `quota.refreshIntervalSeconds: 10`,\n`quota.progressColors.enabled: true`, `quota.progressColors.errorBelow: 10`,\n`quota.progressColors.warningBelow: 30`,\n`quota.percentageMode: \"remaining\"`, `quota.hideInactive: false`,\n`quota.zai.hideTools: false`, and `quota.otherProviders.sortDirection: \"desc\"`.\nProvider `hideInactive` overrides resolve as\n`providerOverride ?? quota.hideInactive ?? false`. Inactive controls affect\nonly configured providers that are not selected; the selected provider remains\nvisible. Set `quota.zai.hideTools` to `true` to remove every Z.AI tool-limit\nrow and its quantities.\n\nPolling defaults to 10 seconds when its value is invalid or non-positive.\nColor thresholds are clamped to `0-100`, and `errorBelow` cannot exceed\n`warningBelow`. Set `quota.progressColors.enabled` to `false` to disable\nsemantic bar and percentage colors.\n\n#### Breaking configuration migration\n\nThe root-level `refreshIntervalSeconds` and `progressColors` paths are ignored.\nMove them to `quota.refreshIntervalSeconds` and `quota.progressColors`\nrespectively. The legacy root-level `otherProviders` object is also ignored:\nmove `otherProviders.percentageMode` to `quota.percentageMode` and\n`otherProviders.sortDirection` to `quota.otherProviders.sortDirection`.\n\n#### Configuration reference\n\nEvery configurable option accepted by the plugins and host-level files is\nlisted below. Options are supplied through the tuple form\n`[\"./plugin.js\", { ... }]` in `tui.json` (or `opencode.json`). Unknown keys\nin an options object are ignored.\n\n**Per-plugin options**\n\n| Plugin                             | Option         | Type     | Default       | Accepted values                                             |\n| ---------------------------------- | -------------- | -------- | ------------- | ---------------------------------------------------------- |\n| Context                            | `defaultState` | string   | `\"expanded\"`  | `\"expanded\"`, `\"collapsed\"`                                |\n| SesTokens                          | `defaultState` | string   | `\"expanded\"`  | `\"expanded\"`, `\"collapsed\"`                                |\n| SubAgent                           | `defaultState` | string   | `\"expanded\"`  | `\"expanded\"`, `\"semi-collapsed\"`, `\"collapsed\"`            |\n| Quota                              | `defaultState` | string   | `\"expanded\"`  | `\"expanded\"`, `\"semi-collapsed\"`, `\"collapsed\"`            |\n| MCP                                | `defaultState` | string   | `\"expanded\"`  | `\"expanded\"`, `\"collapsed\"`                                |\n| LSP                                | `defaultState` | string   | `\"expanded\"`  | `\"expanded\"`, `\"collapsed\"`                                |\n| TODO                               | `defaultState` | string   | `\"expanded\"`  | `\"expanded\"`, `\"collapsed\"`                                |\n\n`defaultState` resets every sidebar panel when the active session ID changes.\n\"semi-collapsed\" starts the panel expanded with the secondary section (Rest\nor Other Providers) collapsed; it is ignored for panels without a secondary\nsection. Missing or unrecognized values fall back to `\"expanded\"`.\n\n**Input chips (`chip` option)**\n\nThe seven sidebar-panel plugins (Quota, Context, MCP, LSP, TODO, SesTokens,\nSubAgent) also render a compact status chip through `session_prompt_right`, on\nthe right of the in-session prompt's agent/model row. Each chip reuses its\npanel's collapsed summary and semantic status colors — e.g.\n`Q 46%`, `Ctx 64%`, `MCP 4/0/0`, `LSP 2`, `TODO 4/3/2`, `Tok 29.11M`,\n`Sub 7/1/3`. A plugin renders no chip when its panel has no data. Home and\ntoken-report do not render chips. Chips are display-only and do not affect the\nsidebar panels.\n\n| Option  | Type   | Default     | Accepted values           | Applicable plugins                                             |\n| ------- | ------ | ----------- | ------------------------- | ------------------------------------------------------------- |\n| `chip`  | string | `\"enabled\"` | `\"enabled\"`, `\"disabled\"` | Quota, Context, MCP, LSP, TODO, SesTokens, SubAgent           |\n\n`chip: \"disabled\"` suppresses only that plugin's input chip. Missing or\nunrecognized values fall back to `\"enabled\"`.\n\nFor example, disable only the LSP chip while keeping its sidebar panel enabled:\n\n```json\n[\"./opencode-tools-lsp.js\", { \"defaultState\": \"collapsed\", \"chip\": \"disabled\" }]\n```\n\n**Quota plugin options (`quota` object)**\n\n| Path                                   | Type    | Default | Accepted values                             | Effect                                                                |\n| -------------------------------------- | ------- | ------- | ------------------------------------------- | --------------------------------------------------------------------- |\n| `quota.refreshIntervalSeconds`         | number  | `10`    | finite, positive                            | Provider polling interval in seconds. Invalid or non-positive falls back to 10. |\n| `quota.progressColors.enabled`         | boolean | `true`  | `true`, `false`                             | Enables semantic bar and percentage colors.                           |\n| `quota.progressColors.errorBelow`      | number  | `10`    | `0`–`100`; must be ≤ `warningBelow`         | Remaining percentage at or below which the bar turns error color.    |\n| `quota.progressColors.warningBelow`    | number  | `30`    | `0`–`100`                                   | Remaining percentage at or below which the bar turns warning color.  |\n| `quota.percentageMode`                 | string  | `\"remaining\"` | `\"remaining\"`, `\"used\"`               | Whether bars and collapsed summaries show remaining or used percentage. |\n| `quota.hideInactive`                  | boolean | `false` | `true`, `false`                             | Global default for hiding inactive providers in Other Providers.     |\n| `quota.openai.hideInactive`            | boolean | *(inherit)* | `true`, `false`                        | Overrides `hideInactive` for OpenAI. Resolves as `providerOverride ?? quota.hideInactive ?? false`. |\n| `quota.zai.hideTools`                 | boolean | `false` | `true`, `false`                             | Removes every Z.AI tool-limit row and its quantities from the panel. |\n| `quota.zai.hideInactive`              | boolean | *(inherit)* | `true`, `false`                        | Overrides `hideInactive` for Z.AI.                                    |\n| `quota.opencodego.workspaceId`         | string  | *(none)* | `wrk_` followed by alphanumeric characters | Identifies the OpenCode Go workspace. Required to activate OpenCode Go. |\n| `quota.opencodego.workspaceToken`      | string  | *(none)* | non-empty, no line breaks                   | Auth cookie value for the console request. Required to activate OpenCode Go. |\n| `quota.opencodego.hideInactive`        | boolean | *(inherit)* | `true`, `false`                        | Overrides `hideInactive` for OpenCode Go.                             |\n| `quota.otherProviders.sortDirection`   | string  | `\"desc\"` | `\"desc\"`, `\"asc\"`                           | Sort direction for secondary providers inside Other Providers.       |\n\nWhen `progressColors.errorBelow` exceeds `progressColors.warningBelow`, both\nrevert to their defaults (`10` and `30`).\n\n**Host-level configuration**\n\n| Key                              | Type   | Effect                                                                          |\n| -------------------------------- | ------ | ------------------------------------------------------------------------------- |\n| `plugin`                         | array  | Ordered list of plugin entries. Each entry is a string spec or `[spec, options]` tuple. Specs are relative file paths, `file://` URLs, or npm package names. Relative paths resolve against the config file that declared them. |\n| `plugin_enabled`                 | object | Keyed by plugin ID. Set a key to `false` to disable an internal built-in panel. |\n\nBuilt-in panel overrides:\n\n| Key                          | Disables                  |\n| ---------------------------- | ------------------------- |\n| `internal:sidebar-context`   | Built-in Context panel    |\n| `internal:sidebar-mcp`       | Built-in MCP panel        |\n| `internal:sidebar-lsp`       | Built-in LSP panel        |\n| `internal:sidebar-todo`      | Built-in TODO panel       |\n\nSet these to `false` in `plugin_enabled` when the corresponding opencode-tools\nplugin is loaded, to avoid duplicate sidebar panels.\n\n### MCP sidebar layouts\n\nMCP names truncate before the right-aligned status label. Every line remains\nwithin the 37-cell sidebar width and contains no trailing whitespace.\n\n#### Expanded\n\n```text\n▼ MCP\n-------------------------------------\n• codegraph-global          Connected\n• context7-global           Connected\n• postgres-test-vendsystem   Disabled\n• postgres-test-vendsystem…  Disabled\n-------------------------------------\n```\n\n#### Collapsed, all connected\n\n```text\n▶ MCP                           4/0/0\n-------------------------------------\n```\n\n#### Collapsed, mixed health\n\n```text\n▶ MCP                           2/1/1\n-------------------------------------\n```\n\n#### Collapsed, empty\n\n```text\n▶ MCP                           0/0/0\n-------------------------------------\n```\n\nThe collapsed summary shows `success/warning/error` counts: connected servers,\ndisabled servers, and servers in any error state (failed, needs authentication,\nneeds client registration, or unknown). Each number uses its bucket color —\nsuccess, warning, or error — including when it is zero, and both separators are\nmuted. For the empty `0/0/0` summary, each zero keeps its bucket color.\n\n### Context sidebar layouts\n\nContext values come from the active session. The expanded panel uses\n`Limit -`, `Tokens -`, `Used -`, and `Spent $0.00` when context values are\nunavailable; the collapsed summary uses `-`. The expanded `Used` value and\ncollapsed summary are green below 40%, yellow from 40% through 60%, and red\nabove 60%. Only a `$0.00` value in the `Spent` row is muted.\n\n#### Expanded\n\n```text\n▼ Context\n-------------------------------------\nLimit                            500K\nTokens                        322.12K\nUsed                              64%\nSpent                           $0.00\n-------------------------------------\n```\n\n#### Collapsed\n\n```text\n▶ Context                         64%\n-------------------------------------\n```\n\n### LSP sidebar layouts\n\nLSP IDs stay in synchronized source order. Each row also shows the basename of\nthe server's operating directory (`root`), right-aligned in the muted label\ncolor; a server with an empty `root` shows the id alone. Long IDs truncate with\nan ellipsis so expanded lines fit within 37 cells and collapsed lines fit within\n36 cells.\n\n#### Expanded\n\n```text\n▼ LSP\n-------------------------------------\n• typescript           opencode-tools\n• yaml-ls              opencode-tools\n-------------------------------------\n```\n\n#### Expanded, empty\n\n```text\n▼ LSP\n-------------------------------------\nLSPs will activate as files are read\n-------------------------------------\n```\n\n#### Collapsed\n\n```text\n▶ LSP                               2\n-------------------------------------\n```\n\nThe collapsed count uses normal header text. Successful servers use a success\nbullet, failed servers use an error bullet, and unknown statuses remain present\nwith a muted bullet. Header clicks affect only the current session selection.\n\n### TODO sidebar layouts\n\nTODO records stay in synchronized source order. Status markers occupy four\ncells, so wrapped content continues beneath the content column without trailing\nwhitespace. TODO continuation lines align under the content column, and the\ncollapsed summary rolls records into `done/working/todo` counts that exclude\ncancelled records.\n\n#### Expanded\n\n```text\n▼ TODO\n-------------------------------------\n[✓] Explore existing panel patterns\n[•] Implement synchronized TODO\n    state and wrapped rows\n[ ] Verify build and deployment\n[-] Superseded task\n-------------------------------------\n```\n\n#### Expanded, empty\n\n```text\n▼ TODO\n-------------------------------------\nNo TODOs for this session\n-------------------------------------\n```\n\n#### Collapsed\n\n```text\n▶ TODO                          4/3/2\n-------------------------------------\n```\n\n### SesTokens sidebar layouts\n\nThese examples preserve the current SesTokens layout semantics from\n`AGENTS.md`. Fenced lines omit right-padding; OpenTUI flex alignment supplies\nthe visual spacing at runtime. Values remain right-aligned within the 37-cell\nsidebar.\n\n#### Expanded\n\n```text\n▼ SesTokens\n------------------------------------\n↻ turns                           97\n↑ in                           4.41M\n↓ out                         18.69K\n▤ cache write                      0\n▤ cache read                  24.77M\nø cache hit ratio              5.68×\n✦ think                        2.87K\n---                              ---\nΣ total                       29.11M\n------------------------------------\n```\n\n#### Expanded, stale\n\n```text\n▼ SesTokens                    stale\n------------------------------------\n↻ turns                           97\n↑ in                           4.41M\n↓ out                         18.69K\n▤ cache write                      0\n▤ cache read                  24.77M\nø cache hit ratio              5.68×\n✦ think                        2.87K\n---                              ---\nΣ total                       29.11M\n------------------------------------\n```\n\n#### Collapsed\n\n```text\n▶ SesTokens                   29.11M\n------------------------------------\n```\n\n#### Collapsed, stale\n\n```text\n▶ SesTokens             stale 29.11M\n------------------------------------\n```\n\nWhile the first snapshot loads, the expanded body and collapsed summary show\n`Loading...` without zero metrics. If the initial attempt and all three retries\nfail, they show `Usage unavailable`. A failed refresh after ready data retains\nthe last successful snapshot as stale and recovers it to ready when a later\nrefresh succeeds. The panel does not poll. Snapshots and collapse choices are\nmemory-only, and the panel does not calculate cost.\n\n### SubAgent sidebar layouts\n\nThese examples preserve every canonical SubAgent layout from `AGENTS.md`.\nRows show the newest five direct children first; older entries appear in the\nseparate `Rest` group. Fenced lines omit runtime right-padding and contain no\ntrailing whitespace.\n\n#### Expanded, one detail\n\n```text\n▼ SubAgent\n------------------------------------\n▶ SubAgent11 with super lo…   9m 45s\n▶ SubAgent10                  1h 15m\n▼ SubAgent9\n  agent:                     general\n  status:                    running\n  time:                       15m 4s\n  model:                 gpt-4o-mini\n  Open Session\n▶ SubAgent8                   2h 18m\n▶ SubAgent7                   2h 18m\n---                              ---\n▼ Rest\n▶ SubAgent6                   9m 45s\n▶ SubAgent5                   1h 15m\n▶ SubAgent4                      15s\n▶ SubAgent3                      25s\n▶ SubAgent2                       5s\n▶ SubAgent1                    1h 2m\n------------------------------------\n```\n\n#### Expanded, one detail wrapping\n\n```text\n▼ SubAgent\n------------------------------------\n▶ SubAgent11 with super lon\n  g name that would normall\n  y wrap but is too long to\n   fit.\n  agent:                     general\n  status:                    running\n  time:                       9m 45s\n  model:                 gpt-4o-mini\n  Open Session\n▶ SubAgent10                  1h 15m\n▼ SubAgent9                   15m 4s\n▶ SubAgent8                   2h 18m\n▶ SubAgent7                   2h 18m\n---                              ---\n▼ Rest\n▶ SubAgent6                   9m 45s\n▶ SubAgent5                   1h 15m\n▶ SubAgent4                      15s\n▶ SubAgent3                      25s\n▶ SubAgent2                       5s\n▶ SubAgent1                    1h 2m\n------------------------------------\n```\n\n#### Expanded\n\n```text\n▼ SubAgent\n------------------------------------\n▶ SubAgent11 with super lo…   9m 45s\n▶ SubAgent10                  1h 15m\n▶ SubAgent9                   15m 4s\n▶ SubAgent8                   2h 18m\n▶ SubAgent7                   2h 18m\n---                              ---\n▼ Rest\n▶ SubAgent6                   9m 45s\n▶ SubAgent5                   1h 15m\n▶ SubAgent4                      15s\n▶ SubAgent3                      25s\n▶ SubAgent2                       5s\n▶ SubAgent1                    1h 2m\n------------------------------------\n```\n\n#### Expanded, stale\n\n```text\n▼ SubAgent                     stale\n------------------------------------\n▶ SubAgent11 with super lo…   9m 45s\n▶ SubAgent10                  1h 15m\n▶ SubAgent9                   15m 4s\n▶ SubAgent8                   2h 18m\n▶ SubAgent7                   2h 18m\n---                              ---\n▼ Rest\n▶ SubAgent6                   9m 45s\n▶ SubAgent5                   1h 15m\n▶ SubAgent4                      15s\n▶ SubAgent3                      25s\n▶ SubAgent2                       5s\n▶ SubAgent1                    1h 2m\n------------------------------------\n```\n\n#### Semi-collapsed\n\n```text\n▼ SubAgent\n------------------------------------\n▶ SubAgent11 with super lo…   9m 45s\n▶ SubAgent10                  1h 15m\n▶ SubAgent9                   15m 4s\n▶ SubAgent8                   2h 18m\n▶ SubAgent7                   2h 18m\n---                              ---\n▶ Rest\n------------------------------------\n```\n\n#### Collapsed\n\n```text\n▶ SubAgent                     7/1/3\n------------------------------------\n```\n\n#### Collapsed, stale\n\n```text\n▶ SubAgent               stale 7/1/3\n------------------------------------\n```\n\n#### Expanded, empty\n\n```text\n▼ SubAgent\n------------------------------------\nNo subagents\n------------------------------------\n```\n\nThe collapsed summary reports successful/running/failed counts. A stale refresh\nretains the complete entry body and marks the panel stale; it does not replace\nrows with a loading message. Before a selected parent has ready data, the plugin\nemits no panel output.\n\n### Build and deploy\n\nBuild the nine standalone minified ESM plugins and their imported shared\nartifact:\n\n```bash\nnpm run build:plugins\n```\n\nDeploy to this repository's `.opencode/` directory or the resolved global\nOpenCode config directory (`$XDG_CONFIG_HOME/opencode`, defaulting to\n`~/.config/opencode`):\n\n```bash\nnpm run deploy:local\nnpm run deploy:global\n```\n\nEach deploy command rebuilds first and automatically migrates managed\nconfiguration entries to the nine standalone entries in manifest order. It\npreserves unrelated plugin entries and preserves existing per-plugin options\n(quota and `defaultState`); quota options remain attached only to the quota\nentry. Local deployment also\nremoves managed source entries from the project-root `tui.json`, because\nOpenCode loads it together with `.opencode/tui.json`; options in the selected\n`.opencode` config take precedence. Repeating either command produces the same\nfiles and configuration. Deployment does not edit `plugin_enabled` or disable\nthe built-in MCP, LSP, or TODO panel. Set the overrides in the configuration\nexample yourself when replacing any built-in panel. Fully restart OpenCode after\ndeployment.\n\nDeployment replaces stale managed SubAgent artifacts and removes stale managed\nsource entries while preserving unrelated files and configuration entries.\n\nThe normalized quota runtime ID is now `aamkye/opencode-tools-quota`. This is\nan intentional ID change, so host-managed plugin state may reset during\nmigration; the deployer still preserves quota's configuration options.\n\n#### Rollback\n\nTo remove the Context panel, remove `./opencode-tools-context.js` from the\n`plugin` array and restart OpenCode. To remove the SesTokens panel, remove\n`./opencode-tools-ses-tokens.js` from the `plugin` array and restart OpenCode.\nTo remove the SubAgent panel, remove `./opencode-tools-subagent.js` from the\n`plugin` array and restart OpenCode. To return to OpenCode's built-in MCP panel,\nremove `./opencode-tools-mcp.js`\nfrom the `plugin` array, then remove the `\"internal:sidebar-mcp\": false`\noverride (or set it to `true`) to re-enable `internal:sidebar-mcp`, then restart\nOpenCode. To return to OpenCode's built-in LSP panel, remove\n`./opencode-tools-lsp.js` from the `plugin` array, then remove the\n`\"internal:sidebar-lsp\": false` override (or set it to `true`) to re-enable\n`internal:sidebar-lsp`, then restart OpenCode. To return to OpenCode's built-in\nTODO panel, remove `./opencode-tools-todo.js` from the `plugin` array, then\nremove the `\"internal:sidebar-todo\": false` override (or set it to `true`) to\nre-enable `internal:sidebar-todo`, then restart OpenCode. To roll back the\ncomplete standalone migration, optionally restore the prior composed release\nand its configuration before restarting.\n\n### Artifact layout\n\n```text\ndist/\n├── opencode-tools-shared.js\n├── opencode-tools-home.js\n├── opencode-tools-token-report.js\n├── opencode-tools-context.js\n├── opencode-tools-ses-tokens.js\n├── opencode-tools-subagent.js\n├── opencode-tools-quota.js\n├── opencode-tools-mcp.js\n├── opencode-tools-lsp.js\n├── opencode-tools-todo.js\n└── session-rename.ts\n```\n\n| File                             | Runtime ID                           | Responsibility                                                      |\n| -------------------------------- | ------------------------------------ | ------------------------------------------------------------------- |\n| `opencode-tools-shared.js`       | Not registered                       | Imported-only provider, presentation, and token-report logic.       |\n| `opencode-tools-home.js`         | `aamkye/opencode-tools-home`         | Compact homepage provider summary.                                  |\n| `opencode-tools-token-report.js` | `aamkye/opencode-tools-token-report` | TUI `/tokens_*` commands and reports.                               |\n| `opencode-tools-context.js`      | `aamkye/opencode-tools-context`      | Reactive active-session context and spend panel.                    |\n| `opencode-tools-ses-tokens.js`   | `aamkye/opencode-tools-ses-tokens`   | Complete descendant-session-tree assistant token aggregation panel. |\n| `opencode-tools-subagent.js`     | `aamkye/opencode-tools-subagent`     | Direct-child SubAgent activity panel.                               |\n| `opencode-tools-quota.js`        | `aamkye/opencode-tools-quota`        | Quota sidebar panel and provider polling.                           |\n| `opencode-tools-mcp.js`          | `aamkye/opencode-tools-mcp`          | Reactive MCP sidebar health panel immediately after quota.          |\n| `opencode-tools-lsp.js`          | `aamkye/opencode-tools-lsp`          | Reactive LSP sidebar status panel.                                  |\n| `opencode-tools-todo.js`         | `aamkye/opencode-tools-todo`         | Synchronized session TODO sidebar panel immediately after LSP.      |\n| `session-rename.ts`              | `aamkye/session-rename`              | Manual global session rename command.                               |\n\n`solid-js`, `@opentui/*`, `@opencode-ai/plugin`, host SDK modules, and\nNode/Bun built-ins remain external and are provided by the OpenCode host.\n\n### Session rename plugin\n\nThe global session rename plugin is manual-only. It changes a session title\nonly when the command is invoked. Use `/session-rename Project planning notes`\nto set an explicit, validated 3-8 word title. Use `/session-rename` without a\ntitle to generate one from recent user text and the latest selected user model.\nThe plugin adds success or failure feedback as an ignored message and disables\nOpenCode's built-in title agent.\n\nBuild the plugin with `npm run build:session-rename`. Deploy it with\n`npm run deploy:global`; this installs `dist/session-rename.ts` as\n`~/.config/opencode/plugins/session-rename.ts`. Deployment installs the new file\nbefore it removes the previously managed legacy artifact. Fully restart OpenCode\nafter deployment.\n\n### Source files\n\n| File                                    | Purpose                                                                                       |\n| --------------------------------------- | --------------------------------------------------------------------------------------------- |\n| `tui/quota.tsx`                         | Standalone quota sidebar adapter                                                              |\n| `tui/home.tsx`                          | Standalone compact homepage adapter                                                           |\n| `tui/token-report.tsx`                  | Standalone TUI token-report command adapter                                                   |\n| `tui/mcp.tsx`                           | Standalone reactive MCP sidebar adapter                                                       |\n| `tui/context.tsx`                       | Standalone reactive active-session context and spend sidebar adapter                          |\n| `tui/lsp.tsx`                           | Standalone reactive LSP sidebar adapter                                                       |\n| `tui/todo.tsx`                          | Standalone synchronized session TODO sidebar adapter                                          |\n| `tui/ses-tokens.tsx`                    | Standalone SesTokens sidebar adapter                                                          |\n| `tui/features/ses-tokens.ts`            | Assistant token aggregation and panel model                                                   |\n| `tui/services/session-tree-snapshot.ts` | Bounded complete descendant-tree snapshot loader                                              |\n| `tui/services/ses-tokens-source.ts`     | Debounced event refresh, retry, and stale-state source                                        |\n| `tui/subagent.tsx`                      | Standalone SubAgent sidebar component and adapter                                             |\n| `tui/features/subagent.ts`              | SubAgent status, duration, grouping, and panel model                                          |\n| `tui/services/subagent-snapshot.ts`     | Bounded direct-child snapshot loader                                                          |\n| `tui/services/subagent-source.ts`       | Event refresh, retry, stale-state, and failure persistence source                             |\n| `tui/providers/`                        | Z.AI, OpenAI, and OpenCode Go provider adapters                                               |\n| `lib/tokens/`                           | Vendored token reporting library ([upstream](https://github.com/slkiser/opencode-quota), MIT) |\n| `lib/session-rename.ts`                 | Manual session rename command behavior                                                        |\n| `session-rename.ts`                     | Global manual session rename plugin entry point                                               |\n| `plugin-manifest.json`                  | Manifest order, runtime IDs, artifacts, slots, and option ownership                           |\n| `build-session-rename.mjs`              | Builds the bundled global session rename plugin                                               |\n| `build-plugins.mjs`                     | Builds the shared artifact and nine standalone local ESM plugins                              |\n| `deploy-plugins.mjs`                    | Idempotently migrates nine local/global plugins and `tui.json` entries                        |\n\n### Edit workflow\n\nEdit the relevant source, redeploy, then fully restart OpenCode to reload.\n\n```bash\nnpm install       # install/refresh deps in node_modules\nnpm run typecheck # tsc --noEmit (informational; runtime resolves via Bun)\nnpm run build:plugins # rebuild all nine standalone plugins plus shared code\nnpm run deploy:local # rebuild and deploy into this repository\nnpm test          # run tests\n```\n\n## Breaking migration\n\nThis project was renamed to `opencode-tools`. Replace every prior project path,\nTUI entry, package name, token plugin filename, and build command with the paths\nshown above. Legacy files and aliases are intentionally not provided.\n\n## How it works\n\n### Z.AI\n\n1. Reads the API key from the `zai-coding-plan` provider (falls back to\n   `~/.local/share/opencode/auth.json`, then `~/.config/opencode/auth.json`\n   and the older `account.json` locations).\n2. Polls `https://api.z.ai/api/monitor/usage/quota/limit` every 10s (5min\n   when the 5H quota is exhausted).\n3. Renders bars + countdowns in the sidebar; expands for absolute counts.\n\n### OpenAI\n\n1. Reads the OAuth access token from the `openai` provider entry in\n   `auth.json` (also checks `codex`, `chatgpt`, `opencode` keys).\n2. Extracts the `chatgpt_account_id` from the JWT for the\n   `ChatGPT-Account-Id` header.\n3. Polls `https://chatgpt.com/backend-api/wham/usage` every 10s (5min\n   when the primary window is exhausted).\n4. Renders the plan type and available primary/secondary quota windows with\n   compact labels derived from each API-reported duration.\n\n### OpenCode Go\n\n1. Sends the configured workspace credentials only to the fixed\n   `https://opencode.ai` origin.\n2. Reads quota data from the authenticated page's undocumented Solid hydration\n   contract and fails closed when that contract changes.\n3. Renders the rolling 5H, weekly 7D, and subscription month 1M windows with\n   shared polling, countdown, reset, and a ten-minute stale horizon without\n   exhausted backoff.\n\n### `/tokens_*` reports\n\n1. Reads assistant messages from `opencode.db` (SQLite, via `bun:sqlite`).\n2. Aggregates token usage by model, provider, and session.\n3. Resolves USD costs using a bundled models.dev pricing snapshot.\n4. Formats a markdown report with summary, model breakdown, and top sessions.\n5. Injects the report into the session via `noReply` prompt (no model invocation).\n",
  "bytes": 43322,
  "sha": "43e41841e181fd4f142644cf8bea8bc706a79a604d878cc925ddc9310d3e5528",
  "repo_slug": "aamkye/opencode-tools",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/okf_aamkye_opencode_tools_okf_bundle_index_m_c984f8c8/readme"
}