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>
- 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>
* 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
* 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
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.
* 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
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>
* 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>
* 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>
* 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>
* 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>
* 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>
* 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>
* 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>
* 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>