diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index 7f30f83..089bf0b 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -34,6 +34,8 @@ The session counters come from OpenCode's cumulative session token and cost fiel | `tps` | A live token-throughput estimate while output is observable, held across tool execution and between steps, then the frozen average for the completed run. It appears only once a rate exists. | | `bgagent` | The number of running direct subagents of the session; it hides when the count is zero. | +> **Spinner color compatibility:** OpenCode 2.0.15 exposes only `accent`, `interactive`, and `neutral` hues in its public theme types. The spinner uses those hues or a hex agent color directly and falls back to the theme's categorical palette for other named colors. On older OpenCode 2 versions, the spinner color may not match the agent's color. Animation is unaffected. + While a run streams, TPS (tokens per second) is estimated from observed UTF-8 bytes using `bytesPerToken`. When the model stream ends, the last live estimate is held across tool execution and between steps; new observable output resumes the live estimate. Once a step reports its output and reasoning usage, those exact tokens replace that step's estimate, and at run end the cumulative average stays frozen until the next prompt. The label always reads `~N t/s`, so TPS has no appearance setting. The tracker shares its lineage with the standalone [opencode2-tps](https://github.com/P-Theo/opencode2-tps) plugin, minus its `display` option, but the held running display and its refresh behavior differ. See [TPS rate tuning](#tps-rate-tuning) for `refreshHz` and `bytesPerToken`. ## Appearance options diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index ce72ad0..78147e8 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -11,7 +11,7 @@ Load the checkout using [Run from source](../README.md#run-from-source). See [Ar | `npm run lint` | Run oxlint. | | `npm run check` | Check TypeScript types. | | `npm test` | Run the Bun tests. | -| `npm run check:compatibility` | Check the OpenCode SDK pin and README version floor. | +| `npm run check:compatibility` | Check that the OpenCode plugin and theme pins match and that the README minimum is no newer than the pin. | | `npm run build` | Rebuild `dist/`. | | `npm pack` | Run lint, type-checks, tests, and build, then create the publishable tarball. | @@ -21,6 +21,6 @@ Tests live in [tests/](../tests), mostly named after the source module. `layout- Local directory entries load the root `tui.tsx`. Published packages load `dist/tui.js`, built from `src/footer.tsx` by [scripts/build.mjs](../scripts/build.mjs). Test the packed artifact when changing runtime code or packaging. CI also imports it against the host's bundled runtime versions. -Keep `options.schema.json` aligned with `src/options.ts`. Update the pinned `@opencode/plugin` version and README compatibility floor together when a change requires a newer host. +Keep `options.schema.json` aligned with `src/options.ts`. Keep `@opencode/plugin` and `@opencode/theme` pinned to the same version so TypeScript checks the host's theme types. Raise the README minimum only when runtime behavior requires a newer host. A typings-only bump does not change it. The compatibility script checks these version labels, not runtime behavior. See [Release](RELEASE.md) for publishing. diff --git a/docs/RELEASE.md b/docs/RELEASE.md index b025dcb..511c9ad 100644 --- a/docs/RELEASE.md +++ b/docs/RELEASE.md @@ -4,7 +4,7 @@ Maintainer runbook. A path entry loads the `tui.tsx` source through the host's transform; an installed package loads the pre-built `dist/tui.js` through the `exports` subpath. Those are two different code paths, so the bundle gets tested before it goes out. -The pinned `@opencode/plugin` version is the build and test baseline. Move it in the same pull request as the fix or feature that needs it; CI validates the pin format and README compatibility floor, then checks GitHub for the matching official `anomalyco/opencode` release tag. +The pinned `@opencode/plugin` version is the build and test baseline. Pin `@opencode/theme` to the same version so theme types remain available to TypeScript. Move both pins in the same pull request as the change that needs them. CI checks their parity and the README compatibility floor, then looks up the matching official `anomalyco/opencode` release tag. A docs-only release skips steps 1 to 5. The bundle is unchanged, and CI already packs and imports the artifact on every push to `main`. Go straight to step 6. A README change that matters on the package page needs a patch release to reach it, because npmjs.com only refreshes the rendered README when a new version is published. diff --git a/package-lock.json b/package-lock.json index af3ca6b..e13524d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,8 @@ "devDependencies": { "@babel/core": "^7.29.7", "@babel/preset-typescript": "^7.29.7", - "@opencode/plugin": "2.0.12", + "@opencode/plugin": "2.0.15", + "@opencode/theme": "2.0.15", "@opentui/core": "^0.5.11", "@opentui/solid": "^0.5.10", "@oxlint/plugins": "^1.82.0", @@ -206,18 +207,18 @@ } }, "node_modules/@aws-sdk/core": { - "version": "3.978.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.978.0.tgz", - "integrity": "sha512-2yX9LUmxPklVjSGTb8dfnWRJSiFQ3TeH2nn7G1mdKHTfnabzF0+gfrS8rYfLWmZrQ8A3mEcxMJjRc51dL5KWaA==", + "version": "3.978.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.978.1.tgz", + "integrity": "sha512-LbY9aGsEiznDWmUc30Nwv3aIX/+dbwTx8KfS0yOC3NPYMO+O91e6jkT1azf34FwjOndq8/Q+RcVVZz5xnerwdg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.974.5", - "@aws-sdk/xml-builder": "^3.972.40", + "@aws-sdk/types": "^3.974.6", + "@aws-sdk/xml-builder": "^3.972.41", "@aws/lambda-invoke-store": "^0.3.0", - "@smithy/core": "^3.33.3", - "@smithy/signature-v4": "^5.6.12", - "@smithy/types": "^4.17.2", + "@smithy/core": "^3.35.0", + "@smithy/signature-v4": "^5.7.3", + "@smithy/types": "^4.19.0", "bowser": "^2.11.0", "tslib": "^2.6.2" }, @@ -226,16 +227,16 @@ } }, "node_modules/@aws-sdk/credential-provider-cognito-identity": { - "version": "3.972.70", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.972.70.tgz", - "integrity": "sha512-KlU89w6Hmb4oZB5zFz/MNIhPOBQGVE7KrDr3BTPCwC4W+q566YH8tGNsAML781LKATtqmNCGFry8XvsJ2XPusg==", + "version": "3.972.71", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.972.71.tgz", + "integrity": "sha512-rsxsi8tF3vMGdWdaHQNXceHBdb49442yR2Pe08K+Phoc/yICbptdsHwL25Wf0z5+hjhSS5a+hDJHP7Xul4zvHQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/nested-clients": "^3.997.45", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", + "@aws-sdk/nested-clients": "^3.997.46", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -243,16 +244,16 @@ } }, "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.972.71", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.71.tgz", - "integrity": "sha512-JN+JHruYZw3GUZB8YGAlDk4wTDPOEAEEdEzj5nS0xodWR4smzHsN7PnK2j6IeOsDIj2aqua5DSbhXl9Gtf90FQ==", + "version": "3.972.72", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.72.tgz", + "integrity": "sha512-xTKO/FWJPozTIXbozVnVGoNBhaGba8TBcx+KyUjRVeOlXE+dUc7GTR1cLvu0uTdIdmemzaFbqqCshXeZA1fZew==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.978.0", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", + "@aws-sdk/core": "^3.978.1", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -260,18 +261,18 @@ } }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.972.73", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.73.tgz", - "integrity": "sha512-uyYYnJOnlis8uQzaYGPd7N1JoioCoNpXgnkXYixsWJXHXgXyYi8WXJSDfofxJeWfQIGWLe2Nwyq60Uc7MZdVOg==", + "version": "3.972.74", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.74.tgz", + "integrity": "sha512-u91E/hT8f4d1xy0Jl7VG4nVKJ3lxbrZkoBTeSVoJdWBiSEUMwMS/9+e0H/aJVQV//Lt5wuzP+E69v4aRSsNTmw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.978.0", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/fetch-http-handler": "^5.7.2", - "@smithy/node-http-handler": "^4.11.3", - "@smithy/types": "^4.17.2", + "@aws-sdk/core": "^3.978.1", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/fetch-http-handler": "^5.8.0", + "@smithy/node-http-handler": "^4.12.1", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -279,24 +280,24 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.973.16", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.16.tgz", - "integrity": "sha512-i++ly+0Uxa+u3ebSSyr0S/3CFhFJDxCXT3+Zj+mW2bXenEx5bKGCdTIKFu39SgXBNhWDjex/8cXUx9MUTMCrTw==", + "version": "3.973.17", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.17.tgz", + "integrity": "sha512-ged4KXdBkvIC81bLvNHHuQKdKak/VXhQTR1NWYTTqW0474nlmsxy9O/vlgTIohDDWH3xpBdtVMZRyjb+DnocDA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.978.0", - "@aws-sdk/credential-provider-env": "^3.972.71", - "@aws-sdk/credential-provider-http": "^3.972.73", - "@aws-sdk/credential-provider-login": "^3.972.78", - "@aws-sdk/credential-provider-process": "^3.972.71", - "@aws-sdk/credential-provider-sso": "^3.973.15", - "@aws-sdk/credential-provider-web-identity": "^3.972.77", - "@aws-sdk/nested-clients": "^3.997.45", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/credential-provider-imds": "^4.4.16", - "@smithy/types": "^4.17.2", + "@aws-sdk/core": "^3.978.1", + "@aws-sdk/credential-provider-env": "^3.972.72", + "@aws-sdk/credential-provider-http": "^3.972.74", + "@aws-sdk/credential-provider-login": "^3.972.79", + "@aws-sdk/credential-provider-process": "^3.972.72", + "@aws-sdk/credential-provider-sso": "^3.973.16", + "@aws-sdk/credential-provider-web-identity": "^3.972.78", + "@aws-sdk/nested-clients": "^3.997.46", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/credential-provider-imds": "^4.5.2", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -304,17 +305,17 @@ } }, "node_modules/@aws-sdk/credential-provider-login": { - "version": "3.972.78", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.78.tgz", - "integrity": "sha512-eUtswnXu0+Ii9ieRK+0L7aPFV3Z/dnW2VntJzjBP9xs8s+8p5nBNuymIXtXwZ+5r5+XJP3e32nMkuZ/r0HozEA==", + "version": "3.972.79", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.79.tgz", + "integrity": "sha512-L+Z85anONJd8MaiuraO4wRxATCdEejBZ3K3eymzWI5JPXa9sOS9CkIm72PBKqXKX+Z9p9NGMX5AIMXm0LEflgw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.978.0", - "@aws-sdk/nested-clients": "^3.997.45", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", + "@aws-sdk/core": "^3.978.1", + "@aws-sdk/nested-clients": "^3.997.46", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -322,22 +323,22 @@ } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.972.83", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.83.tgz", - "integrity": "sha512-jdso7ejzfRnatxMUZK4S/U6KbaDPCvfIV4XL+IQAPFDBt5rj5Fq595euqlK8Le4lNCMFR9oUpt+1l0aMgaayOQ==", + "version": "3.972.84", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.84.tgz", + "integrity": "sha512-oHt854odINVwzwsh+c5x69j0ajm4DbqqqVJ+O1ECsCIZeMDAbzFpXItaqP7UZstJj/ATdTk/KFSH0LaNAgV+kA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/credential-provider-env": "^3.972.71", - "@aws-sdk/credential-provider-http": "^3.972.73", - "@aws-sdk/credential-provider-ini": "^3.973.16", - "@aws-sdk/credential-provider-process": "^3.972.71", - "@aws-sdk/credential-provider-sso": "^3.973.15", - "@aws-sdk/credential-provider-web-identity": "^3.972.77", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/credential-provider-imds": "^4.4.16", - "@smithy/types": "^4.17.2", + "@aws-sdk/credential-provider-env": "^3.972.72", + "@aws-sdk/credential-provider-http": "^3.972.74", + "@aws-sdk/credential-provider-ini": "^3.973.17", + "@aws-sdk/credential-provider-process": "^3.972.72", + "@aws-sdk/credential-provider-sso": "^3.973.16", + "@aws-sdk/credential-provider-web-identity": "^3.972.78", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/credential-provider-imds": "^4.5.2", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -345,16 +346,16 @@ } }, "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.972.71", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.71.tgz", - "integrity": "sha512-lYmXJa4gvq4xN1lrT5NiP5vIYYKcGWAdj8y+8o6dlcateB5eF3Dn8DtmjjHKfMBrTPAMr2pebIiX/UOj8c1/UA==", + "version": "3.972.72", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.72.tgz", + "integrity": "sha512-rLIp2xbMjX/k9/od7APpqq1ZgXXnV0pOL1Th3ZsL8Wu0TRtBsDTVS8iPqcfRFcHakFxPvR04OSTv2ka2qOb/2A==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.978.0", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", + "@aws-sdk/core": "^3.978.1", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -362,18 +363,18 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.973.15", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.15.tgz", - "integrity": "sha512-6Jhcf4v0pSFdjk1EW2kvzuEBKD+UZ2uNcHUIglKKLndD20YhvkL2kdmDOV5/j4mYuWWwe/a1FQ1aomU86/Cg5Q==", + "version": "3.973.16", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.16.tgz", + "integrity": "sha512-IGihaJfFZYacJJr/odqILCoK7W/mvrZ7cuK7ECn3sAu4vLC6u0V8bS7mCGbdugJ8Aum2tnvqmx0F2MRFp2rn9g==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.978.0", - "@aws-sdk/nested-clients": "^3.997.45", - "@aws-sdk/token-providers": "3.1129.0", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", + "@aws-sdk/core": "^3.978.1", + "@aws-sdk/nested-clients": "^3.997.46", + "@aws-sdk/token-providers": "3.1138.0", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -381,17 +382,17 @@ } }, "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.972.77", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.77.tgz", - "integrity": "sha512-uylIQSUWpfLuH2LovxEEfwzJGM/SabLOfLMg6YXu/E8jJEKUdpdILCVCQCdFvHyu/7dLJOHPMfrSwduxO56NkQ==", + "version": "3.972.78", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.78.tgz", + "integrity": "sha512-/y9WvNtlcPBGLR0qc1a+9J/xtYZfVczvLUOuXaVWylzttH7ewsxwHtjmiJSolNrVSDorIxHGHMU61CbonRkmwA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.978.0", - "@aws-sdk/nested-clients": "^3.997.45", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", + "@aws-sdk/core": "^3.978.1", + "@aws-sdk/nested-clients": "^3.997.46", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -428,19 +429,19 @@ } }, "node_modules/@aws-sdk/nested-clients": { - "version": "3.997.45", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.45.tgz", - "integrity": "sha512-mooq9Q+jLa18VoM7HouczmslZU60iiB0aKc/Ztnq/luIL1ud0z4DnYprLR/ZO1gp331S9tJctM1HZr7u6YKBXQ==", + "version": "3.997.46", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.46.tgz", + "integrity": "sha512-oRxtBcka/JGHGs9l9p9IVajGoTP8vTPmoAzdHGy4Qcy9P5vPnDf6nhIeM/COQNY9k/OahImTRaLkHftoXvfcmQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.978.0", - "@aws-sdk/signature-v4-multi-region": "^3.996.46", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/fetch-http-handler": "^5.7.2", - "@smithy/node-http-handler": "^4.11.3", - "@smithy/types": "^4.17.2", + "@aws-sdk/core": "^3.978.1", + "@aws-sdk/signature-v4-multi-region": "^3.996.47", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/fetch-http-handler": "^5.8.0", + "@smithy/node-http-handler": "^4.12.1", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -448,15 +449,15 @@ } }, "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.996.46", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.46.tgz", - "integrity": "sha512-L+2xZTye/2T96f3lwCws0Zw6GG2JHZW9e8FpVgGBeeExSKyeoZ6CWRpBml/7DNiK/O26jrgPM9F+Ay8VkgzUWQ==", + "version": "3.996.47", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.47.tgz", + "integrity": "sha512-Zk08macMvQTHzQJCLJVkOlviVoqwYMrpXv4lmLN7b7sAbiMoOK7Go0NYdR5UeF+MW8LIbRmwrNy9u/5VvX1U5g==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.974.5", - "@smithy/signature-v4": "^5.6.12", - "@smithy/types": "^4.17.2", + "@aws-sdk/types": "^3.974.6", + "@smithy/signature-v4": "^5.7.3", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -464,17 +465,17 @@ } }, "node_modules/@aws-sdk/token-providers": { - "version": "3.1129.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1129.0.tgz", - "integrity": "sha512-Sbl3rpzQdsG4ZK2zh0JWUYyZPKKorJlVOddA2T0DVbKJFrsW8J6wgnslxxUH04+WaBMr4A1HzJZvZX0xUvkniA==", + "version": "3.1138.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1138.0.tgz", + "integrity": "sha512-GpyAr0DD63YOEmYFM6Df+gJuIgC92MMTiBK4FTKfxii5MJ9ge20epR7LyroulscYlG89J+ZB2ivFDPjvfQhzdw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.978.0", - "@aws-sdk/nested-clients": "^3.997.45", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", + "@aws-sdk/core": "^3.978.1", + "@aws-sdk/nested-clients": "^3.997.46", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -482,13 +483,13 @@ } }, "node_modules/@aws-sdk/types": { - "version": "3.974.5", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.974.5.tgz", - "integrity": "sha512-LkwLL2BLbC6wNNm4JaH9mbEqBMdOZCct6VAYqhdN4U1xrWM+fUJQEfbHwQgDypapOWTRtlk25akb5afM0P8CIQ==", + "version": "3.974.6", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.974.6.tgz", + "integrity": "sha512-v/clNZzZnDxGyvpHMOGpJKVXFAExJzUNAAjaWGdcx8QAcXLGwTaOkw33p5SHAi0YAioK32xB3hWwOekRVfmfKg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.17.2", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -509,13 +510,13 @@ } }, "node_modules/@aws-sdk/xml-builder": { - "version": "3.972.40", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.40.tgz", - "integrity": "sha512-wlFmCIGUlwF4zx/kncw+bmxTQh1HeSJq4mYV/V5cZUSJadDP3kXvGW8Rn21cimj/7y9ju+47oYWXi97vF7czaA==", + "version": "3.972.41", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.41.tgz", + "integrity": "sha512-ctjVSyCMegrWfXlx6VqzSBFI6UqmQ5ZlnfMhdLIiWmhoH8UAQxSCP5N3OpG7X3k4LnS7ou74C4mt20+bfTW2aQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.17.2", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -1625,14 +1626,14 @@ } }, "node_modules/@opencode/ai": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/@opencode/ai/-/ai-2.0.12.tgz", - "integrity": "sha512-3ODFv7a3mKHZ92uUgJDKUM8wY2akNwpvC6YDck0U2gwkc6zfXwNXXpWAEjhdlHPujmQub6dNb0FS5St4oKpSNQ==", + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@opencode/ai/-/ai-2.0.15.tgz", + "integrity": "sha512-dY3HG6bp+UMJOi+m1nfzvQaTPpCSmMNDswAOLQq/MJghGrD54WrcEC4IhAQ1hJY7b/hhQYOzPAMeJsvF4aRYYQ==", "dev": true, "license": "MIT", "dependencies": { "@aws-sdk/credential-providers": "3.1057.0", - "@opencode/schema": "2.0.12", + "@opencode/schema": "2.0.15", "@smithy/eventstream-codec": "4.2.14", "@smithy/util-utf8": "4.2.2", "aws4fetch": "1.0.20", @@ -1641,14 +1642,14 @@ } }, "node_modules/@opencode/client": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/@opencode/client/-/client-2.0.12.tgz", - "integrity": "sha512-WxZLWIv0Sx9NwoCDmkEqKPnn+NOpk3Kt9FWh5gMgrl1mDbCI+6EQtFOsgrhqJSrFZXMzFqgLMAiTTIYD7wZWpA==", + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@opencode/client/-/client-2.0.15.tgz", + "integrity": "sha512-Lu3Pb6Z/lJ797VryQrsdqEgVBXjtYZWOxLNZKyBUDgXhO/GpzOpXi1H1Uo4g+qWrH8LwUISDBdxHHOWJy5HcqQ==", "dev": true, "license": "MIT", "dependencies": { - "@opencode/protocol": "2.0.12", - "@opencode/schema": "2.0.12" + "@opencode/protocol": "2.0.15", + "@opencode/schema": "2.0.15" }, "peerDependencies": { "effect": "4.0.0-rc.112", @@ -1664,24 +1665,24 @@ } }, "node_modules/@opencode/plugin": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/@opencode/plugin/-/plugin-2.0.12.tgz", - "integrity": "sha512-eUO61AEruyxK6wrL82XhjRuZ5zvoWpLdhzAWbFgoLe3/8IgwrY/4SUKGEou5WgXtzh0zWNDQQqMpaVMe66n8cQ==", + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@opencode/plugin/-/plugin-2.0.15.tgz", + "integrity": "sha512-TsSXd2g/433De7ViY+5d/tlLtkZCSmYKo8ScnhtcmPVoM/U5ptQDFXEXx5psTlAfkKcISJh+5vMSOe4u3uCqUQ==", "dev": true, "license": "MIT", "dependencies": { "@ai-sdk/provider": "3.0.8", - "@opencode/ai": "2.0.12", - "@opencode/client": "2.0.12", - "@opencode/protocol": "2.0.12", - "@opencode/schema": "2.0.12", - "@opencode/util": "2.0.12", + "@opencode/ai": "2.0.15", + "@opencode/client": "2.0.15", + "@opencode/protocol": "2.0.15", + "@opencode/schema": "2.0.15", + "@opencode/util": "2.0.15", "@standard-schema/spec": "1.1.0", "effect": "4.0.0-rc.112", "zod": "4.1.8" }, "peerDependencies": { - "@opencode/theme": "2.0.12", + "@opencode/theme": "2.0.15", "@opentui/core": ">=0.5.10", "@opentui/solid": ">=0.5.10", "solid-js": ">=1.9.0" @@ -1702,20 +1703,20 @@ } }, "node_modules/@opencode/protocol": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/@opencode/protocol/-/protocol-2.0.12.tgz", - "integrity": "sha512-YYp9ElZMW8UG7cV9kSd9j3svPTEt0sTP7G4tXeQ2icbCIwFki28x+fCiuF8wBGcpYMEcLg1GrF3aEqxPAZOpWA==", + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@opencode/protocol/-/protocol-2.0.15.tgz", + "integrity": "sha512-fFi3VYdgNQzT4TswfKGul7DzseOyhA4b/hE/elUe3xxm5iki4tP/pjT8CU3rRWX8sK/75ICr36NAUhSayFtJuw==", "dev": true, "license": "MIT", "dependencies": { - "@opencode/schema": "2.0.12", + "@opencode/schema": "2.0.15", "effect": "4.0.0-rc.112" } }, "node_modules/@opencode/schema": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/@opencode/schema/-/schema-2.0.12.tgz", - "integrity": "sha512-T3RJb371gH813pdaWpAvXAgZ3GSHpPcHSkP8nRbPsSKYOlfmNId2s8Js9aLCJHeVfIKmW3+I9poa3Bx+aiiROQ==", + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@opencode/schema/-/schema-2.0.15.tgz", + "integrity": "sha512-D0JDwF4uTNmFA2MyiSnZ5DlT/t2PF1EEwVbRPulB/Ppcss/z5Fcn6VybHrapki2bKDVQu1Mnn8zBW3G6KP5I6g==", "dev": true, "license": "MIT", "dependencies": { @@ -1723,10 +1724,166 @@ "effect": "4.0.0-rc.112" } }, + "node_modules/@opencode/theme": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@opencode/theme/-/theme-2.0.15.tgz", + "integrity": "sha512-xmdf4xlm9IFX+8zE0Z6J9NuUdotkN27Tj1tbCmgicI3SVddHpRKTa7IATsaqzQMegKYZEVrYqNglnGRAyPTrCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@opentui/core": "0.5.10", + "effect": "4.0.0-rc.112" + } + }, + "node_modules/@opencode/theme/node_modules/@opentui/core": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@opentui/core/-/core-0.5.10.tgz", + "integrity": "sha512-C3a2UbmefeAjIxAgm4BqjuSxKT4oqutfvYFwVvUgMxmGRHkNbBc/s7sukV0JgwcxFcV3uMFrXxo+E+BQtvuOiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bun-ffi-structs": "0.3.1", + "diff": "9.0.0", + "marked": "17.0.1", + "string-width": "7.2.0", + "strip-ansi": "7.1.2" + }, + "optionalDependencies": { + "@opentui/core-darwin-arm64": "0.5.10", + "@opentui/core-darwin-x64": "0.5.10", + "@opentui/core-linux-arm64": "0.5.10", + "@opentui/core-linux-arm64-musl": "0.5.10", + "@opentui/core-linux-x64": "0.5.10", + "@opentui/core-linux-x64-musl": "0.5.10", + "@opentui/core-win32-arm64": "0.5.10", + "@opentui/core-win32-x64": "0.5.10" + }, + "peerDependencies": { + "web-tree-sitter": "0.25.10" + } + }, + "node_modules/@opencode/theme/node_modules/@opentui/core-darwin-arm64": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@opentui/core-darwin-arm64/-/core-darwin-arm64-0.5.10.tgz", + "integrity": "sha512-Vyb+nTbhab8ZcRy5gg1loEEGwRcIbjAeVRIBfHBcbFDqmITBOg7x2gqJ+x/TnoOy4uwMhCmICUN2wiyREw3r1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@opencode/theme/node_modules/@opentui/core-darwin-x64": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@opentui/core-darwin-x64/-/core-darwin-x64-0.5.10.tgz", + "integrity": "sha512-tTFLcM7Oj1gTyhm/bUdAt3C6grZdCxPk6+/g2azcZBUlI3/62LwbeRS6HbQKFFmm+1fUmX8cq6kWrtul885mVg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@opencode/theme/node_modules/@opentui/core-linux-arm64": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@opentui/core-linux-arm64/-/core-linux-arm64-0.5.10.tgz", + "integrity": "sha512-ncJXcgudhBf2GdJyF3xVQN/Ec+1F7GOL+pRrURmgBYSj2v1w6EyoDQFAACtPTK2c3R38W6fvZwL4JSLlm4EFXQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@opencode/theme/node_modules/@opentui/core-linux-arm64-musl": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@opentui/core-linux-arm64-musl/-/core-linux-arm64-musl-0.5.10.tgz", + "integrity": "sha512-dGMphDKexSdeYqwl0wgoFBP88Ta/cdi1Zc1mk29/ENkSCGz+74zlCHgqTHRNGLmI8W5TfuUtCyktQH11/Z+TBQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@opencode/theme/node_modules/@opentui/core-linux-x64": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@opentui/core-linux-x64/-/core-linux-x64-0.5.10.tgz", + "integrity": "sha512-5qtYaOgwVycZD1GaGshTRsi0rXPAmVExO03N1JQaHu+NYxK/vXSOc7Bu4QW0sPXx3Sp0SpzpP+FHjXABfoK66g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@opencode/theme/node_modules/@opentui/core-linux-x64-musl": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@opentui/core-linux-x64-musl/-/core-linux-x64-musl-0.5.10.tgz", + "integrity": "sha512-Oj4H9hApuvuTKPWxh4SoZAgGJorR7vbvnrZA/cAkSMAk2VGSoHRRcqeXQbcH8IcdjVZ0KFpv8Zkl/D5Ye+2mew==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@opencode/theme/node_modules/@opentui/core-win32-arm64": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@opentui/core-win32-arm64/-/core-win32-arm64-0.5.10.tgz", + "integrity": "sha512-A9VhgvTxQoUdZ+8LmUumEng1sQNbj9QQQT3NYG9mSxI54qTANi7vOWNSphMiY6RMVsr22pgm6nUvSSvJXv7Jog==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@opencode/theme/node_modules/@opentui/core-win32-x64": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@opentui/core-win32-x64/-/core-win32-x64-0.5.10.tgz", + "integrity": "sha512-u3KHa7kEeWrmKVDRJYpxSGO+g5E9cMGlrmTsPN3GVPHUmQMiREUawLXUvsU8+IHaQnqG3Q5nuE1yf4fPBzS+Qw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@opencode/util": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/@opencode/util/-/util-2.0.12.tgz", - "integrity": "sha512-LgecrvN4dhsbdgG7Lt6+Cp/+0+VswyV8RJsE/mjjJ6Ns39EwFVTnZYMHT4bkR+vRL/w3IF0VCFg8Ohnfwkn3lw==", + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@opencode/util/-/util-2.0.15.tgz", + "integrity": "sha512-s0Z+2rxb+2Tif+ZV1EvTiGQ0tRiemIZq3WOOjBw2XPBSBt2Sfv9rWXJhTzSpkOZucfTyymuIVXslXPGFF7aaQA==", "dev": true, "license": "MIT", "dependencies": { @@ -2747,13 +2904,13 @@ } }, "node_modules/@smithy/core": { - "version": "3.34.1", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.34.1.tgz", - "integrity": "sha512-dLcOUxz8YCv1RZUMKq6GbyUf95pLbrqh34bPvpCZ1+CByFF31BEAFewZjsGCnVsZTKdThNENfGyAgk2TJqVwSw==", + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.35.0.tgz", + "integrity": "sha512-zRMhfkByhT2snNdr1si24vJitU6Cr9ix2MikUfWmkAgp4jrNP0GcKSP5YvwQ+TlI8AZXER5QOGJn3JsVtSD9/A==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.18.0", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -2850,9 +3007,9 @@ } }, "node_modules/@smithy/types": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.18.0.tgz", - "integrity": "sha512-CgB6HHWer/vrKps24ulRIbpcpb7K4xAU7SkZ7YHzBPlwHsvsrCJFEXK421s+cJzX+ZrqtA/TuU5w1HzI7k9N8A==", + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.19.0.tgz", + "integrity": "sha512-r7jh49VJxGerfAcTQA6gXcKc+98zOp/tqRwzYjgOE+iSQsP6cEU1hq2QzbuipmP68QtYdY9wKEhiCQZIzHgZ4Q==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -5806,9 +5963,9 @@ } }, "node_modules/undici": { - "version": "8.10.2", - "resolved": "https://registry.npmjs.org/undici/-/undici-8.10.2.tgz", - "integrity": "sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.11.0.tgz", + "integrity": "sha512-AdzuGcAkzhbha3GgCSoUBx2P0quwym6qdFNCQz/fDGZc8w9XJ741wHUbt2kTmfPz+ZIOMkySFkiY7RXmiDDC8w==", "dev": true, "license": "MIT", "engines": { diff --git a/package.json b/package.json index 14677b8..bf04fbb 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,8 @@ "devDependencies": { "@babel/core": "^7.29.7", "@babel/preset-typescript": "^7.29.7", - "@opencode/plugin": "2.0.12", + "@opencode/plugin": "2.0.15", + "@opencode/theme": "2.0.15", "@opentui/core": "^0.5.11", "@opentui/solid": "^0.5.10", "@oxlint/plugins": "^1.82.0", diff --git a/scripts/check-compatibility.mjs b/scripts/check-compatibility.mjs index bed4a6c..f17b681 100644 --- a/scripts/check-compatibility.mjs +++ b/scripts/check-compatibility.mjs @@ -6,7 +6,7 @@ const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.me const readme = readFileSync(new URL("../README.md", import.meta.url), "utf8") -const packages = ["@opencode/plugin"] +const packages = ["@opencode/plugin", "@opencode/theme"] const versions = packages.map((name) => packageJson.devDependencies[name]) diff --git a/src/footer.tsx b/src/footer.tsx index de0257e..19a008a 100644 --- a/src/footer.tsx +++ b/src/footer.tsx @@ -416,7 +416,6 @@ const definition: Plugin.Definition = { readonly sessionID: string } - /** Mirrors the host's `local.agent.color`, including its palette fallback. */ function spinnerBaseColor(sessionID?: string): RGBA { const fallback: RGBA = context.theme.border.base const session = sessionID ? context.data.session.get(sessionID) : undefined @@ -433,19 +432,19 @@ const definition: Plugin.Definition = { if (!agent) return fallback + const step = context.themeMode === "light" ? 800 : 200 + if (agent.color) { - const step = context.themeMode === "light" ? 800 : 200 + if (/^#[0-9a-f]{6}$/iu.test(agent.color)) return RGBA.fromHex(agent.color) - // Hex from `cli.json`, or one of the config's theme color names. - const declared: RGBA | undefined = /^#[0-9a-f]{6}$/iu.test(agent.color) - ? RGBA.fromHex(agent.color) - : context.theme.hue?.[agent.color]?.[step] + if (agent.color === "accent" || agent.color === "interactive" || agent.color === "neutral") { + const declared = context.theme.hue?.[agent.color]?.[step] - if (declared) return declared + if (declared) return declared + } } const palette: RGBA[] = [] - const step = context.themeMode === "light" ? 800 : 200 for (const scale of context.theme.categorical ?? []) { const color: RGBA | undefined = scale?.[step] diff --git a/tests/footer.test.ts b/tests/footer.test.ts index 5e7ca0d..3248dbf 100644 --- a/tests/footer.test.ts +++ b/tests/footer.test.ts @@ -222,6 +222,8 @@ interface FakeContext { readonly theme: { readonly text: { readonly muted: string } readonly border: { readonly base: RGBA } + readonly hue?: { readonly accent: { readonly 200: RGBA } } + readonly categorical?: readonly { readonly 200: RGBA }[] } readonly storage: { readonly memory: ( @@ -242,7 +244,7 @@ const setupWithFakeContext = definition.setup as unknown as ( context: FakeContext, ) => ReturnType -function createHarness(options: StatusOptionsInput & TpsOptionsInput = {}) { +function createHarness(options: StatusOptionsInput & TpsOptionsInput = {}, agentColor?: string) { const claims: CapturedClaim[] = [] const handlers = new Map void)[]>() const generation: Generation = { active: 0 } @@ -313,7 +315,10 @@ function createHarness(options: StatusOptionsInput & TpsOptionsInput = {}) { }, }, model: { list: () => state.models }, - agent: { list: () => [] }, + agent: { + list: () => + agentColor ? [{ id: "test", mode: "primary", hidden: false, color: agentColor }] : [], + }, }, } @@ -322,7 +327,12 @@ function createHarness(options: StatusOptionsInput & TpsOptionsInput = {}) { location: state.defaultLocation, app: { version: "test" }, renderer: { widthMethod: "unicode" }, - theme: { text: { muted: "#888888" }, border: { base: RGBA.fromHex("#ff8800") } }, + theme: { + text: { muted: "#888888" }, + border: { base: RGBA.fromHex("#ff8800") }, + hue: { accent: { 200: RGBA.fromHex("#3388ff") } }, + categorical: [{ 200: RGBA.fromHex("#e57837") }], + }, storage: { memory: () => [generation, (mutation: (draft: Generation) => void) => mutation(generation)] as const }, data, ui: { @@ -1387,6 +1397,28 @@ describe("built render", () => { } }) + test.each([ + ["#12ab34", "#12ab34"], + ["accent", "#3388ff"], + ["custom", "#e57837"], + ] satisfies ReadonlyArray)("uses agent color %s for the block spinner", async (agentColor, expected) => { + const h = createHarness({ appearance: { spinner: "blocks" } }, agentColor) + + seed(h, { status: "running" }) + + const app = await renderClaim(h, "composer", { sessionID: "ses_test" }, 60, 2) + + try { + const spans = app.captureSpans().lines[0]?.spans ?? [] + + expect(spans.some((span) => span.text.includes("■") && span.fg.equals(RGBA.fromHex(expected)))).toBe(true) + } finally { + app.renderer.destroy() + h.cleanup() + h.restore() + } + }) + test("holds the live rate across tools and steps until new output arrives", async () => { const h = createHarness()