mirror of
https://github.com/Gitlawb/openclaude.git
synced 2026-11-06 20:58:14 -04:00
v0.31.0
26
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
2e687df4ec |
fix(image): allow large/metadata-less screenshots through on resize failure (#1964) (#1970)
* fix(image): allow large/metadata-less screenshots through on resize failure (#1964) Stop Alt+V paste from falling through to "No image found in clipboard" when the native image connector returns undefined metadata or a screenshot exceeds 1568px. - Reorder the metadata guard so an undefined metadata object is handled before reading metadata.format (previously threw TypeError and was swallowed into a "no image" result). Fall back to magic-byte format detection. - Drop the `!overDim` gate from the catch-block allow-through so a dimensionally-large but base64-small image passes through. The API resizes images >1568px server-side; only the base64 size is a hard limit. - Keep IMAGE_MAX_WIDTH/HEIGHT at 1568; only the crash and gate logic changed. - Add imageResizer.test.ts covering the undefined-metadata path, the overDim<=5MB allow-through regression, the >5MB throw, and the happy path. * fix(image): enforce many-image dimension limit in resize-failure fallback (#1970) When the native image processor crashes, the fallback previously returned the original buffer unchanged whenever its base64 size was <= 5MB, with no dimension check. That let oversized images (e.g. 3840x2160 PNG/JPEG/WebP) stay in conversation history and later break many-image requests with a 400 "image dimensions exceed ... many-image" error. - Add IMAGE_MANY_IMAGE_MAX_WIDTH/HEIGHT (2000px) to apiLimits. - In the resize-failure fallback, detect images exceeding the 2000px many-image limit via magic-byte dimension parsing (PNG IHDR, WebP VP8/ VP8L, JPEG SOF0/2/3, GIF screen descriptor) and, when possible, downsample with platform Canvas APIs (awaiting a fully-decoded source). If downsample is unavailable or the result still exceeds the 5MB payload budget, reject with ImageResizeError instead of returning the oversized original. - Unknown/unparseable dimensions fail safe (treated as exceeding the limit). - Correct two pre-existing WebP dimension-offset bugs surfaced during review. Adds regression tests for PNG/JPEG/WEBP/GIF over the many-image limit. * fix(image): address review - media-type subtype, WebP offsets, Canvas DOM resolve, metadata-less budget - ResizeResult.mediaType is the subtype ('png'/'jpeg'), not a full MIME type. The Canvas downsample branch wrongly returned 'image/png'/'image/jpeg'; corrected to 'png'/'jpeg' to match every other return in the file. - WebP dimension parser corrected against real sharp-encoded frames: VP8L transform header reads from byte 21 (bits[0..13] width, [14..27] height); VP8 lossy width/height read from bytes 26/28. Previous offsets were off and produced wrong dimensions. - Canvas fallback now resolves createElement/Image from document (browser/ Electron) with a globalThis fallback, so it actually engages where Canvas is available. - metadata-less + oversized branch now tries progressive JPEG quality [80,60,40,20] and only returns an in-budget result; otherwise fails via the user-facing limit error instead of returning an oversized buffer that validateImagesForAPI would reject (the regression the PR recovers from). - Add WebP/VP8L fixtures and tests asserting exact parsed dimensions and in-limit acceptance. * fix(image): address 4 P1 review findings in resize-failure fallback - Metadata-less branch now enforces the many-image 2000px limit via a shared enforceManyImageDimensionLimit helper (extracted from the catch-path guard), instead of letting compact high-resolution screenshots pass through unchecked. - VP8 lossy WebP dimensions are stored directly (no -1 bias per RFC 6386); only VP8L uses minus-one encoding. Fixed parser and test fixture. - Add VP8X (extended WebP) dimension parsing, needed for alpha/animation. - DOM Image fallback now constructs with no args and assigns src after installing onload/onerror, since the Image constructor takes width/height, not a URL. * fix(image): require raw dimensions before canvas downsample in many-image guard readImageDimensions can return null for unparseable buffers; falling back to 0,0 made tryDownsampleToManyImageLimit treat the image as 1x1 and silently downsample to a single pixel instead of throwing ImageResizeError. * fix(image): keep in-budget 4K pastes when Canvas resize fallback is unavailable The many-image 2000px guard rejected Windows clipboard screenshots whenever image_processor_napi failed and Canvas was absent, recreating #1964. Pass those images through, invoke DOM canvas methods with their owners, and skip JPEG fill/TEM bytes before reading segment lengths. * fix(image): reject API-hard 8000px edges and surface paste resize errors Passthrough after a processor crash was sending images the API hard-rejects and still mapping ImageResizeError to "No image found". Keep 4K single-image paste, fall through from createImageBitmap to Image, and show the real resize error on Alt+V. * fix(image): document paste resize errors and test native rethrow Clipboard ImageResizeError was still easy to treat as a missing reader on the native path, and the Alt+V vs generic notification contract had no focused tests. Share the paste error helpers, document the 5MB/8000px prompt, and cover native resize rejection without enabling NATIVE_CLIPBOARD_IMAGE. * test(image): stabilize clipboard mock module identity * fix(image): close resize fallback review gaps * test(image): cover JPEG canvas fallback subtype * fix(image): downsample before enforcing API edge * fix(paste): settle rejected image path reads * test(paste): isolate rejection regressions * fix(image): report payload limit after fallback * test(image): restore mocked modules after suites Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * fix(images): enforce many-image limits at Anthropic request boundary Count retained history and tool-result images, verify resized payload dimensions, and report actionable failures before dispatch. Exercise mock restoration deterministically. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * fix(images): preserve resize failure diagnostics at request boundary The many-image validation catch replaced the original image-processing error with a generic RequestImageDimensionsError without logging it or keeping a cause chain, so logAPIError and the assistant error path only ever saw the wrapper message. - Log the underlying processing failure via logError before wrapping. - Rethrow an existing RequestImageDimensionsError unchanged instead of reconstructing it. - Attach the original error as the wrapper's cause; ImageResizeError and RequestImageDimensionsError now forward ErrorOptions to super. - Expand usesAnthropicImageLimits coverage to the reachable isFirstPartyBaseUrl:false input for bedrock/vertex/foundry. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * fix: count partner documents in request image limits --------- Co-authored-by: jatmn <the@jat.mn> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> |
||
|
|
ec850d2d1a |
docs(web): add llms.txt for LLM discovery (#2205) (#2209)
* docs(web): add llms.txt for LLM discovery (#2205) Hosts an llmstxt.org-spec summary of OpenClaude at the website root so LLMs (ChatGPT et al.) have an authoritative source and stop conflating the project with unrelated tools named "Openclaw". * docs(web): address review feedback on llms.txt - Clarify the License entry: MIT applies only to OpenClaude contributors' modifications, not the underlying Claude Code (Anthropic proprietary). Addresses Greptile's misstatement flag. - Convert the bare npm one-liner in the Install section into a Markdown linked list entry per the llmstxt.org spec. Addresses CodeRabbit's "link-only sections" note. * fix(web): make AUR entry in llms.txt hyperlink-first The 'AUR package: [openclaude](...)' entry put text between the list marker and the hyperlink, which makes the reference llms.txt parser fail with AttributeError ('NoneType' has no attribute 'groupdict') and aborts parsing of the whole document. Use link-first syntax preserving destination and meaning. Verified with the reference parser (parse_llms_file): 4 sections, 21 links, all URLs correct. web:build passes and web/dist/llms.txt matches source byte-for-byte; web:typecheck clean. --------- Co-authored-by: Gravirei <gravirei@users.noreply.github.com> |
||
|
|
1e56d4e7b2 |
feat(providers): add focused LLMTR hybrid gateway (#2150)
* feat: add LLMTR hybrid gateway * feat: support LLMTR_API_KEY * fix: allow LLMTR provider env files * fix: protect LLMTR credential routing * fix: protect LLMTR profile credentials * fix: complete LLMTR env lifecycle * fix: select LLMTR model before client setup * fix: address LLMTR review findings * fix: route LLMTR auxiliary models correctly * fix: complete LLMTR credential boundaries * fix: clear persisted LLMTR startup keys * fix: normalize LLMTR generic credentials * fix: scope LLMTR credential support * fix: align LLMTR credential boundaries * fix: close LLMTR credential boundaries * fix: clear stale LLMTR auth state * fix: clear persisted LLMTR credentials * fix: complete LLMTR setup contracts * fix: close LLMTR lifecycle gaps * fix(providers): close LLMTR credential boundaries * fix(providers): preserve saved LLMTR profile keys |
||
|
|
6e3590303b |
feat(partners): add Concentrate and Exa to partner roster (#2141)
Adds Concentrate (concentrate.ai) and Exa (exa.ai) to the README partners table and the web landing page, with light/dark logo variants self-hosted under docs/assets/ and web/public/partners/. Co-authored-by: OpenClaude <openclaude@gitlawb.com> |
||
|
|
09eba26d30 |
feat(cost): support exact custom model pricing (#2131)
* feat(cost): support exact custom model pricing * fix(cost): address custom pricing review feedback |
||
|
|
575b407275 |
feat(partners): add ApiSmart, refresh Novita AI logo (#2121)
- Add ApiSmart (https://www.apismart.ai) to the README partners table and the web partner strip, with a dark-theme logo variant (near-black wordmark recolored to white, white matte removed). - Replace the Novita AI PNG logo with the new SVG wordmark plus a generated dark variant, wired through the same prefers-color-scheme <picture> pattern (README) and logoDark field (web). Co-authored-by: OpenClaude <openclaude@gitlawb.com> |
||
|
|
7cae4089d6 |
feat(xai): add Grok 4.6/4.5 to catalog, xAI provider, and gateways (#2117)
* feat(xai): add Grok 4.6/4.5 and hybrid catalog discovery xAI's current flagship is Grok 4.6; keep shared capability flags so gateways can reference the new models, and let /v1/models surface later Grok IDs without another catalog bump. * fix(xai): authenticate hybrid discovery for OAuth and keep gateway aliases aligned OAuth xAI sessions had no /v1/models credential, so hybrid refresh failed; also drop curated alias IDs from discovery and map grok-build-latest on Atlas/Hicap to Grok 4.5. * fix(xai): align OAuth hybrid discovery cache with runtime metadata OAuth-only xAI sessions hashed the access token into discovery writes, but runtime limit lookups only used env credentials, so uncataloged Grok IDs fell back to default windows. Mirror stored OAuth on cache reads and isolate discovery tests from the shared config home. * fix(xai): keep Grok 4.6 PR on catalog and hybrid discovery Move OAuth /v1/models auth and cache-key alignment out of this branch so the catalog, xAI hybrid vendor, and gateway references stay reviewable on their own. * fix(xai): read discovered model context length * fix(xai): preserve OAuth discovery metadata * fix(xai): tolerate malformed discovery models * fix(discovery): harden credential cache partitions * fix(xai): unify discovery OAuth cache handling * fix(xai): preserve OAuth discovery cache identity * fix(discovery): use native cache namespace hashing * fix(xai): keep OAuth discovery nonblocking * fix(discovery): use opaque cache fingerprints |
||
|
|
c40d663b70 |
fix(web): link release notes to GitHub (#2114)
* fix(web): link release notes to GitHub * test(web): verify release link safety contract |
||
|
|
5f8e7d101b |
Revert "fix(release): synchronize web changelog entries (#2088)" (#2113)
This reverts commit
|
||
|
|
ff91642364 |
feat(integrations): add ApiSmart OpenAI-compatible gateway provider (#2109)
* feat(integrations): add ApiSmart OpenAI-compatible gateway provider
Add a hybrid-catalog ApiSmart gateway with dedicated APISMART_API_KEY/APISMART_MODEL
env wiring, route detection, profile persistence, and regression tests so the
provider works via --provider, env-only setup, and saved profiles.
* fix(apismart): protect dedicated credentials
* fix(apismart): enforce route credential boundaries
* fix(apismart): honor explicit competing route models
* fix(apismart): validate credentials and default profiles
* test(apismart): isolate env-only client tests
* fix(apismart): align routing and validation contracts
* fix(apismart): centralize route capability contracts
* Revert "fix(apismart): centralize route capability contracts"
This reverts commit
|
||
|
|
7743cf280e |
fix(release): synchronize web changelog entries (#2088)
* fix(release): sync web changelog entries from release please * fix(release): provide sync push credentials * fix(release): gate and finalize web release sync * fix(release): make web release sync recoverable * fix(release): target release PR commands explicitly * fix(release): honor manifest release configuration * fix(release): recover failed web sync retries * ci(release): run full sync preflight * fix(release): validate synchronized PR head * fix(release): validate bot sync in release job * fix(release): harden bot-owned web sync * fix(release): validate exact bot PR head * fix(release): isolate and bind PR synchronization * fix(release): isolate validation from write credentials * fix(release): reject non-regular generated inputs * fix(release): require a valid forward version bump * fix(release): scope sync artifacts to run attempts * fix(release): reuse validated artifacts across retries * fix(release): resume readiness after a completed push * fix(release): bind retries to the validated commit * fix(release): address synchronization review findings * fix(release): support CRLF changelog recovery * fix(release): keep validation transitions fail-closed * fix(release): restore scoped web sync and marker ownership Cut the multi-job finalize state machine back to a single draft-until-push sync path, and fix consecutive releases leaving stacked automation markers by stripping leftover draft ownership when inserting the next version. * fix(release): keep web sync from blocking npm publish Move pending Release Please web sync into its own job so a sync failure cannot skip install-verify, npm, or docker after a release tag is already created. * fix(release): close web-sync trust and policy gaps Remove hand-curation escape hatches, split read-only validation from write-only push, discover bot PRs by branch identity, and run the full local gate suite before marking the release PR ready. * fix(release): validate gates against synchronized commit Commit the synced releases.ts in the read-only validate job before typecheck, security scan, and whitespace checks so those gates inspect the content that will be marked ready, not the pre-sync HEAD. * fix(release): harden web-sync trust boundary and draft gating Run sync from trusted main with only changelog/manifest overlaid from the bot PR, re-draft after release-please, serialize sync without canceling in-flight pushes, and require an explicit sync base. * fix(release): restore overlaid inputs before validate cleanliness gate Fetching changelog/manifest from the bot PR dirtied tracked files on the trusted main checkout and made the final git-diff gate fail on every pending release. Restore those overlays after sync and fetch origin/main for the security/whitespace checks. * fix(release): reuse validated sync artifacts on retry * fix(release): validate release sync inputs and retries * fix(release): recover web sync state transitions * fix(release): protect generated release ownership * fix(release): repair web sync recovery gates * fix(release): bind sync artifacts to validated base * fix(release): verify synchronized file mode * fix(release): paginate bot PR discovery |
||
|
|
95eeb0bde3 |
feat(cli): add --yolo alias for --dangerously-skip-permissions (#2097)
Register the alias on the main command and the ssh stub. Recognize it in the cc:// and ssh raw-argv scans, and in both skills pre-parse boolean sets (leading and trailing), so and route correctly. Update the web flags docs. Includes source-scan + help-text tests proving the alias is wired through. The SSH/argv refactor remains on the existing feat/yolo-flag branch for a separate follow-up PR. |
||
|
|
63fda83d55 |
fix(web): add v0.27.0 changelog entry and clarify release-data ownership (#2075)
* fix(web): add 0.27 release entry * test(web): cover 0.27 release entry * fix(web): clarify 0.27 permission-timeout highlight * docs: ban drive-by edits to web/src/data/releases.ts Tell agents and contributors that the curated changelog is owned by the release/web process, and stop verify-dist from instructing unrelated PRs to patch it when npm publishes ahead of the site. * test(web): locate curated release by version * test(web): enforce newest-first release order |
||
|
|
56a920196d |
feat(web): replace favicon/logo with Ember Block O brand mark (#2065)
The site icon was still the 2026-06 terminal-face + git-fork circuit
mark, predating the ember identity the product now leads with (the
ANSI-Shadow startup logo and the orange pixel wordmark in the README).
Replace it with the Ember Block O: the startup screen's figlet "O"
letterform re-plotted as pure SVG rects — five ember gradient bands
(#ffb15f → #be5008, the exact stops from StartupScreen.palettes.ts)
with the wordmark's thin offset outline shadow, on a dark rounded tile.
Reads as a crisp orange O at 16px and matches CLI, README, and site.
- openclaude-logo.svg: new mark (same filename, Head.astro untouched)
- openclaude.png: 512px transparent-corner render (PNG favicon and the
nav/footer images, which already reference this path)
- og/{default,docs,commands,buddy}.png: all four social cards
regenerated with the new mark; layout, copy, and grid unchanged
Co-authored-by: OpenClaude <openclaude@gitlawb.com>
|
||
|
|
c2030bbb2b |
fix(web): make web/ build standalone — stop importing the repo-root p… (#2061)
* fix(web): make web/ build standalone — stop importing the repo-root package.json vercel --prod deploys only the web/ directory, so site.ts importing ../../../package.json (and verify-dist.ts reading it) broke every Vercel build with ts(2307) while local builds passed. - SITE.version now derives from latestVersion, the newest entry in src/data/releases.ts — committed data inside web/, so builds are deterministic and need nothing outside the directory - verify-dist gains a best-effort npm freshness guard: fails the build only when registry.npmjs.org reports a newer @gitlawb/openclaude than releases.ts; unreachable registry or malformed responses skip the check, and site-ahead-of-npm is allowed for release PRs - verify-dist.test.ts covers the guard via injected fetch (no network) Co-Authored-By: OpenClaude <openclaude@gitlawb.com> * fix(web): reject leading-zero semver from the npm registry Number() would normalize a malformed '01.2.3' to 1.2.3; require strict semver components so malformed registry values skip the freshness check instead of being silently coerced. Co-Authored-By: OpenClaude <openclaude@gitlawb.com> --------- Co-authored-by: OpenClaude <openclaude@gitlawb.com> |
||
|
|
0f76b5490b |
feat(web): v0.26 refresh — buddy page, changelog, partners, provider … (#2060)
* feat(web): v0.26 refresh — buddy page, changelog, partners, provider catalog - Single-source the site version from the root package.json (never stale again) - New /buddy/ page: all 7 hero sprites rendered as animated SVGs generated from src/buddy/pixelSprites.ts, attack descriptions, commands, hatch lore, plus a dedicated 1200x630 OG image composed from the real sprites - New /changelog/ page: curated release highlights 0.19 -> 0.26 from a typed releases.ts data file - Landing: buddy teaser section, partners strip (GitLawb, Bankr, Atomic Chat, Xiaomi MiMo, Atlas Cloud, AI/ML API, Novita AI) with self-hosted logos, community links, refreshed provider strip, node >= 22 fix - Providers docs rebuilt as grouped catalog (39 providers: subscriptions, gateways, vendors, local, custom) incl. xAI OAuth, AI/ML API, Cloudflare Workers AI, NVIDIA NIM, Kimi K3, GPT-5.6, Opengateway free models - Data refresh vs v0.26.0 source: 16 new slash commands, pdf skill, new CLI flags + 10 subcommands, modelLimits/providerFallbackChain/agentRouting settings, corrected env vars (GEMINI_API_KEY, OPENGATEWAY_API_KEY, ...) - Nav/footer/docs sidebar link the new pages; JSON-LD breadcrumbs on both Co-Authored-By: OpenClaude <openclaude@gitlawb.com> * fix(web): address CodeRabbit review — flag description + dist verification - Correct --disable-slash-commands description: the flag empties the entire slash-command list (REPL.tsx filters all commands), not just skills; the upstream help string "Disable all skills" is the misleading one - Add scripts/verify-dist.ts, wired into `bun run build` (so the existing CI web job runs it): asserts SITE.version matches the root package.json in the rendered pages, nav exposes /buddy/ and /changelog/, every release renders with its GitHub URL, every hero renders with its sprite asset, partner and community links render on the landing page, and the sitemap covers the new routes Co-Authored-By: OpenClaude <openclaude@gitlawb.com> * fix(web): harden verify-dist per review — empty-page guard, rendered-nav check, tests - page() now records a failure for a present-but-empty file, so '' is only ever returned alongside a recorded failure and skipped assertions can no longer mask a blank page - assert the rendered docs sidebar (dist/docs/) links every docsNav route, not just the source data array and the landing nav - extract pure verifyDist(dist) and add 9 fixture-based bun tests covering missing/empty pages, lost sidebar links, missing sprites, stale partner links, missing release URLs, and sitemap regressions; discovered by the root `bun test` run in CI, no workflow changes needed Co-Authored-By: OpenClaude <openclaude@gitlawb.com> * test(web): derive the missing-sprite fixture from heroes data Hard-coding robinhood.svg would make the test throw during fixture mutation if that hero were renamed, instead of exercising verifyDist(). Co-Authored-By: OpenClaude <openclaude@gitlawb.com> --------- Co-authored-by: OpenClaude <openclaude@gitlawb.com> |
||
|
|
a5b277971d |
feat(settings): add settings-based subscription override and agy terminal support (#1731)
* feat(settings): add settings-based subscription override and agy terminal support * feat(provider): rebrand Gemini wizard setup steps to Google AI / Gemini * fix(settings): restrict subscription override to trusted sources Addresses jatmn's CodeRabbit review on #1731. P1 — untrusted settings sources could spoof subscriber state: Reads subscriptionType only from policy/flag/user/local settings, excluding project and repository settings which can be checked into shared repos. Adds getTrustedSubscriptionType() helper used by both isClaudeAISubscriber() and getSubscriptionType(). P2 — subscriptionType: "free" did not short-circuit OAuth-detected subscriber state. With a valid Claude AI OAuth token and subscriptionType: "free" in settings, isClaudeAISubscriber() still returned true. Now "free" is authoritative and returns false. P3 — test isolation: added afterEach(mock.restore()) to auth.test.ts so Bun's module mocks cannot leak into subsequent tests. Also splits the antigravity askpass test into focused cases for "agy" and "antigravity" substrings. * fix(settings): restrict subscriptionType override to user settings and return false early for free * fix(auth): clean up unused import and return type matching in tests * fix(provider): align Gemini chooser copy with the wizard's actual auth methods Addresses jatmn's review on #1731. The /provider chooser advertised "Google AI / Gemini Subscription" and "Use your Google AI Premium plan, …", but the Gemini setup wizard only offers three auth methods — API key, access token, and local ADC — with no subscription/Premium sign-in flow. Drop the "Subscription" label and "Google AI Premium plan" framing so the chooser matches the wizard (and the "Google AI / Gemini" wording used elsewhere in the file). No OAuth/subscription sign-in is planned: using Google AI/Gemini subscriptions via third-party tools violates Google's Terms of Service. * fix(pr1731): resolve review follow-ups * fix(pr1731): close review follow-ups * fix(pr1731): close antigravity and gemini follow-ups --------- Co-authored-by: jatmn <the@jat.mn> |
||
|
|
e2bbb0295a |
feat: smart auto-routing (per-turn simple-vs-strong model selection) (#1734)
* feat(smart-routing): add smartRouting settings schema and reader * feat(smart-routing): resolve role keys to a SmartRoutingConfig * feat(smart-routing): wire per-user-turn routing into the query loop Classify once per user turn (transition===undefined), pin the decision in a loop-local, and apply the model-only route before the blocking-limit math. Enforce the org allowlist by calling isModelAllowed directly (coerce disallowed to strong; disable for the session if strong is also disallowed). Strip thinking history on a model change only under the provider gate (preserve-reasoning providers are left untouched). Export stripThinkingBlocksIfProviderAllows. * feat(smart-routing): add routed-error fallback to the strong model A simple-routed turn whose model call hits a retryable error retries once on the strong model, reusing the existing attemptWithFallback retry loop. Aborts and 4xx client errors propagate. Adds a session routing tally (simple/strong counts and simple->strong escalations) for the observability surface. * feat(smart-routing): add /smartroute command and env defaults /smartroute shows status and sets/toggles the simple and strong roles from agentModels keys, warning when the simple model is not first-party-cheaper than the strong one. OPENCLAUDE_SMART_ROUTING(_SIMPLE/_STRONG) provide startup defaults; an explicit settings block overrides env. * feat(smart-routing): show routing summary in /cost Appends a session routing summary (turns simple/strong, simple->strong escalations) to /cost, with an estimated-savings line gated on first-party pricing and annotated unavailable for unknown third-party pricing. Per-turn cost is already attributed to the routed model via the existing per-model breakdown. * fix(smart-routing): re-pin to strong after a routed-error fallback Without this, a turn's later continuation passes re-applied the pinned simple model after a fallback, re-triggering the same failure each pass. Re-pinning to strong keeps the rest of the turn on the recovered model. * fix(review): provider-swap guard, tally reset, notice-storm, env docs - Add the KTD6 provider-swap guard: drop the per-turn routing pin when a mid-turn provider-fallback swap changes the active provider, so the old provider's model id is not replayed at the new endpoint (adversarial P1). - Reset the routing tally in resetCostState() so /cost does not show stale cross-session counts. - Don't emit the disabled-for-session notice on every turn when no sessionId is available (suppress instead of storm). - Document OPENCLAUDE_SMART_ROUTING* in the openaiShim env-var header. - Add tests: provider-swap-safe pin, undefined-session silence, /smartroute strong arm and no-value guard. * docs(smart-routing): document /smartroute, settings, and env vars Register /smartroute in the web command catalog, add the smartRouting setting and OPENCLAUDE_SMART_ROUTING* env vars to the configuration reference, add a docs/smart-routing.md usage guide, and link it from the README. * fix(review): clear tally on /login, extract+test swap predicate, cap disabled set - /login used the raw bootstrap resetCostState, leaking the routing tally across an account switch; switch it to the cost-tracker wrapper. - Extract the provider-swap drop check as a pure, tested shouldDropPinForProviderSwap() and use it in the query loop. - Cap the disabledSessions set so a long-lived host can't grow it unbounded. - Document the 404/429 retry-by-design rationale; add tests for it. - Clarify the routedFallbackUsed per-turn scope and the apply-after-guard comment; document cross-provider role rejection and the re-enable path. * test(smart-routing): make allowlist tests robust to cross-file module mocks The decideTurnModel allowlist tests spied the global settings singleton, which let another file's leaked mock.module of modelAllowlist (agent.test.ts) flip isModelAllowed out from under them in the full suite. Spy isModelAllowed directly and restore it in afterEach so the tests are deterministic regardless of suite ordering. * fix(smart-routing): address CodeRabbit review and green CI - index.test.ts: pin the allowlist in the three happy-path decideTurnModel tests so they no longer inherit a leaked cross-file isModelAllowed mock (the CI test failure) - smartroute/index.test.ts: narrow the LocalCommandResult union via an expectText helper instead of reading .value off the union (the CI typecheck failure) - conversationRecovery.ts: route deserialize's thinking-strip gate through stripThinkingBlocksIfProviderAllows, removing the duplicated provider detection - conversationRecovery.test.ts: replace the two as-any fixtures with a shared typed factory * fix(smart-routing): scope cost claims to first-party reference pricing Smart routing's savings estimate and "simple isn't cheaper" warning were derived from the static first-party MODEL_COSTS table via getKnownInputCost, with no knowledge of the active provider, gateway, or account pricing. For a multi-provider user whose model ids happen to exist in that table but bill differently, the /cost summary and /smartroute warning stated a savings figure as if it reflected what they are actually charged. Narrow the copy instead of inventing provider-aware pricing the code cannot verify: the /cost line, the /smartroute warning, and docs/smart-routing.md now label the numbers as first-party reference pricing and note the active provider may bill differently. Tests assert the qualifier on every reworded branch so it cannot silently regress. No routing logic changed. * fix(smart-routing): clarify simple role wording * Fix smart routing review findings * fix(smart-routing): honor env roles and non-text turns * test(smart-routing): cover non-text skip path --------- Co-authored-by: jatmn <the@jat.mn> |
||
|
|
77c0a0d780 |
feat(ux): honest feedback pass — visible retries, statusline truncation marker, hint grace period (#1862)
* feat(ux): honest feedback pass — visible retries, statusline truncation marker, hint grace period
Three fixes with one principle: never look frozen, never silently hide state.
- SystemAPIErrorMessage: retries were fully hidden until attempt 4, so
transient rate limits / overloads were indistinguishable from a hang.
Attempts 1-3 now render a compact dim line ("Rate limited — retrying
in 4s… (attempt 2/10)") with a live countdown; the full error block
is unchanged at attempt >= 4. The transcript already keeps only the
last api_error message and hides it on the next non-error message,
so early visibility adds no stacking. New briefAPIErrorReason()
classifies 429/529/5xx/connection failures, including the
OpenAI-compat shim's plain-text transport errors that carry no cause
chain. Component rewritten from react-compiler output to plain React.
- BuiltinStatusLine: fitSegments dropped rate-limit -> cost -> context
silently on narrow terminals. Segments now degrade to short forms
first (ctx 37% -> 37%, $1.23 -> $1), and anything still dropped is
marked with a trailing dim "…" so hidden data is visible as hidden.
The marker is best-effort: at extreme widths the bare model name
beats showing nothing.
- PromptInputFooter: "? for shortcuts" was suppressed whenever a status
line rendered — the default state since the builtin statusline
shipped, killing the hint's discoverability path entirely. New users
(numStartups <= 10) keep the hint alongside the status line;
established users get the quieter footer.
- docs: BASH_MAX_OUTPUT_LENGTH env var documented on the website env
reference (default 30000, cap 150000).
Verified live in the TUI (tmux + mock OpenAI endpoint): compact retry
line from attempt 1 against a dead endpoint, full block at attempt 4,
Esc interrupts cleanly; statusline at 100/32/24 cols shows full /
degraded / "test-model · 2% · …"; hint present at numStartups=2,
suppressed at 50.
Co-Authored-By: OpenClaude <openclaude@gitlawb.com>
* fix(review): address CodeRabbit feedback — custom statusline yields immediately, timeout test, docs wording
- shouldSuppressShortcutsHint: a custom status line is explicit user
configuration, so it now always wins over the discoverability grace
period; only the builtin status line grants new users the hint.
Test added to lock the semantics.
- Test the ETIMEDOUT -> "Request timed out" branch. Note: CodeRabbit's
suggested test shape (plain object with a cause) would not exercise
the branch — extractConnectionErrorDetails only walks Error
instances — so the error itself carries the code.
- Docs: soften "full output saved" to reflect the persisted-file cap.
Co-Authored-By: OpenClaude <openclaude@gitlawb.com>
---------
Co-authored-by: OpenClaude <openclaude@gitlawb.com>
|
||
|
|
5b1db554fd | feat(lsp): expose captured diagnostics (#1813) | ||
|
|
8023356841 |
feat(session): harden fork-session branching (#1801)
* feat(session): harden fork-session branching Add explicit fork-session branching metadata, preserve fork-owned transcript state, and seed retained content replacement records for forked resumes. Document --fork-session behavior and cover forked resume transcript/materialization behavior with focused tests. * fix(session): respect print persistence for fork seeding |
||
|
|
2aad6fc93e |
feat(config): add OPENCLAUDE_CONFIG_DIR override (#1683)
* feat(config): add OPENCLAUDE_CONFIG_DIR env var as preferred alias for CLAUDE_CONFIG_DIR (#454) The legacy CLAUDE_CONFIG_DIR name was the only way to point openclaude at a non-default config home, which leaked Anthropic branding for a fork that has otherwise rebranded to OpenClaude. Add OPENCLAUDE_CONFIG_DIR as the preferred name. CLAUDE_CONFIG_DIR continues to work for backward compatibility; when both are set with different values, OPENCLAUDE_CONFIG_DIR wins and a one-time warning is logged. - src/utils/envUtils.ts: introduce resolveConfigDirEnv() that picks OPENCLAUDE_CONFIG_DIR over CLAUDE_CONFIG_DIR and emits a conflict warning. Memoize cache key now tracks both env vars so changing either invalidates the cached result. - src/utils/env.ts: getGlobalClaudeFile() previously read CLAUDE_CONFIG_DIR directly, missing the new alias. Route through resolveConfigDirEnv() so the global config file path follows the same precedence. - src/utils/secureStorage/macOsKeychainHelpers.ts: the "is default dir" check used by keychain service-name scoping now considers both env vars. - src/utils/swarm/spawnUtils.ts: forward OPENCLAUDE_CONFIG_DIR to teammate processes alongside the legacy var. - src/utils/openclaudePaths.test.ts: +6 unit tests covering the new alias, fallthrough, conflict warning, and resolveConfigDirEnv() in isolation. - .env.example: document both env vars and the precedence rule. Verified locally on Linux: with only OPENCLAUDE_CONFIG_DIR set, with only CLAUDE_CONFIG_DIR set (legacy still works), with both set matching (silent), with both set conflicting (warn once + OPENCLAUDE wins), with neither set (default ~/.openclaude). Memo cache invalidates across 4 sequential env transitions. Built dist/cli.mjs honors the new var and emits the conflict warning to the user. * Fix config-dir warning and docs review findings Only mark the config-dir conflict warning as emitted when a warning callback actually receives it, add coverage for warn-once and silent callers, and update web configuration docs for OPENCLAUDE_CONFIG_DIR precedence. # Conflicts: # web/src/data/configuration.ts * Align configuration docs with openclaude paths Update the configuration page settings-file table to point default users at .openclaude settings and keybindings paths, matching the new config home behavior. * Align keybindings docs with openclaude config home Update the keybindings page, keybindings docs data, and skill index to point default users at ~/.openclaude/keybindings.json. * Align skill and hook labels with openclaude paths Update bundled config/keybindings skill prompts, public skills docs, hook/trust labels, and the user memory selector to use the active OpenClaude config home paths. # Conflicts: # src/components/TrustDialog/utils.ts # src/components/hooks/SelectEventMode.tsx # src/skills/bundled/updateConfig.ts # src/utils/hooks/hooksSettings.ts * Resolve config-home paths dynamically in skill prompts Use runtime settings/keybindings path helpers for bundled skill prompts and the restricted-hooks banner so custom OPENCLAUDE_CONFIG_DIR values are reflected in user-facing guidance. * Update active command prompts for openclaude paths Point statusline, setup/onboarding prompts, plugin messages, and the external user-memory warning at the active OpenClaude settings and memory paths. # Conflicts: # src/commands/auto-fix.ts # src/commands/onboard-github/onboard-github.tsx # src/commands/plugin/ManagePlugins.tsx # src/commands/statusline.tsx * Fix remaining config path review findings * Cover dynamic config paths in UI and storage tests * Fix config path smoke failures after rebase * Fix remaining config path review findings --------- Co-authored-by: gnanam1990 <gnanasekaran.sekareee@gmail.com> |
||
|
|
544b857876 |
fix(settings): correct stale settings path references (#1666)
* fix(settings): correct OpenClaude settings paths * fix(settings): address review path clarity * fix(sandbox): protect OpenClaude settings in changed cwd |
||
|
|
d08593de92 |
feat(web): rebuild landing as Astro static site with gitlawb theme and full docs (#1606)
* feat(web): rebuild landing as Astro static site with gitlawb theme and full docs Replaces the Vite+React SPA in web/ with a fully static Astro 6 site: - gitlawb-aligned design system: dark-default monochrome surface tokens, Geist Mono, hairline grids, [light]/[dark] toggle — keeping the orange #ff7a1a openclaude accent (#e85d00 in light mode for AA contrast) - 9-page docs section: installation, quickstart, providers, slash commands (all 69 user-facing commands with argument hints), CLI reference (every non-hidden flag), configuration, keybindings, skills — rendered from typed data files seeded from the CLI source - SEO: per-page canonicals/OG/Twitter, JSON-LD (SoftwareApplication, TechArticle, BreadcrumbList), @astrojs/sitemap, robots.txt, and generated 1200x630 OG cards, all on https://openclaude.gitlawb.com - zero framework JS: theme toggle, copy buttons, mobile nav, and TOC highlighting are small vanilla scripts - CI-compatible: same typecheck/build script names, bun.lock regenerated Co-Authored-By: OpenClaude <openclaude@gitlawb.com> * feat(web): redesign logo as gitlawb-aligned circuit mark White terminal face (hollow node eyes, >_ prompt mouth) on a black square with an orange git-fork trace descending to two commit nodes — same stroke language as the gitlawb mark. Adds the SVG source as the favicon and regenerates all three OG cards with the new logo. Co-Authored-By: OpenClaude <openclaude@gitlawb.com> * fix(web): address review feedback on copy button a11y and css lint - CopyCommand: generic aria-label (component is reusable, not install-specific) and a visually-hidden role="status" live region so screen readers announce the copied state - global.css: lowercase text-rendering keyword, blank line before color-scheme, kebab-case fade-up keyframe name Co-Authored-By: OpenClaude <openclaude@gitlawb.com> --------- Co-authored-by: OpenClaude <openclaude@gitlawb.com> |
||
|
|
f3d41c6161 |
fix(release): verify npm latest tag and document @latest install (#1378)
* fix(release): verify npm latest tag and document @latest install * fix(auto-updater): use @latest for global installs |
||
|
|
4eb486ef83 |
Feat/web landing refresh (#958)
* feat(web): openclaude landing — runs anywhere, uses anything A new marketing site for openclaude under web/, plus the minimal root infrastructure to build, ignore, and gate it without affecting the published npm package. Landing page (web/) - Vite + React 19 with monospace gitlawb typography (sf mono / fira code). - Hero: pill, two-line wordmark "runs anywhere. / uses anything.", copy-to-clipboard install command, github cta. - Six feature rows in hermes-style "title — sentence" format on hairline dividers (any model, real tools, profiles per repo, streaming, gateway routing, editor + server modes). - Install block: same copyable command + three numbered steps. - One-line footer with brand, version, gitlawb link, and license. - Light theme is the default with a no-flash bootstrap script and a ☀ / ☾ toggle persisted to localStorage. - New orange terminal-face logo at 36px in the nav. - Body wash: dual orange radial gradients for warmth on both themes. Root infra - web/ excluded from npm publish via .npmignore (belt-and-suspenders alongside the existing files whitelist). - web/ excluded from docker context (.dockerignore). - web:dev / web:build / web:preview / web:typecheck scripts in package.json that delegate via --cwd web (no root deps added). - web typecheck + build added to the pr-checks workflow. - web/dist/ and web/*.tsbuildinfo ignored. Co-Authored-By: OpenClaude <openclaude@gitlawb.com> * added vercel in .gitignore --------- Co-authored-by: OpenClaude <openclaude@gitlawb.com> |