Compare commits

..
Author SHA1 Message Date
hanzo-devandClaude Opus 4.8 899779ca45 build(@hanzo/ai): raise Node heap to 8GB for the SDK vite build (CI OOM)
CI runner OOM'd bundling @hanzo/ai (exit 134). Add --max-old-space-size=8192.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 22:40:16 +00:00
hanzo-devandClaude Opus 4.8 96e2622c0c release(@hanzo/ai): 0.1.1 — brand-agnostic SDK + workspace build fixes
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 21:58:25 +00:00
hanzo-devandClaude Opus 4.8 7a117ac024 build: declare missing external deps across workspace packages
The monorepo relied on hoisting and never declared many externals; a clean CI
install (bun, no hoisting guarantees) failed to resolve them when bundling
@hanzo/ai. Declare them on the owning packages (net-ui +49, net-artifacts +33,
net-state, net-i18n, net-message-ts, …). @hanzogui/* workspace deps untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 21:36:46 +00:00
hanzo-devandClaude Opus 4.8 65066010ac build(@hanzo/ai): declare missing runtime deps (immer, zod, ethers, …)
@hanzo/ai imported ~25 externals (immer, zod, ethers, framer-motion, axios,
react-hook-form, sonner, pyodide, …) not in its package.json — a clean install
(CI) failed to resolve them (local hoisting masked it). Declare them; move
test-only deps (vitest, testing-library, react-scan) to devDependencies.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 21:25:43 +00:00
hanzo-devandClaude Opus 4.8 354a05b813 build: fix workspace build (green 163/163)
- net-i18n: useChain/@hanzo_network/chain-config -> useBrand/brand-config
  (chain-config was renamed to brand-config; this import was never updated).
- loader: drop now-unused @ts-expect-error (TS2578) in GuiPlugin.ts.
Pre-existing breakage that gated the @hanzo/ai publish.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 21:18:09 +00:00
hanzo-dev 9918993e83 rename: claude.md → CLAUDE.md
Canonical casing per durable rule. Filesystem is case-insensitive
on macOS but git tracks the lowercase variant; uppercase is the
project convention.
2026-06-07 13:38:06 -07:00
hanzo-devandClaude Opus 4.8 3ac5e45f68 build: add missing per-package tsconfig.json (unblocks workspace build/publish)
10 leaf TS packages (recipes, net-brand-config, examples, *-test) lacked a
committed tsconfig.json, so the workspace build died with ENOENT on the first
one (pkgs/recipes). Add them on the standard pattern (extends root + composite).
Pre-existing breakage, gates the @hanzo/ai publish.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 20:27:45 +00:00
hanzo-devandClaude Opus 4.8 b4ece03b05 refactor(brand): brand-agnostic SDK — no hardcoded brands, apps own config
- net-brand-config bundles ZERO brands: registry (registerBrands) + injection
  (setBrand/useBrand/getBrand); add company + machinesEnabled to BrandConfig.
- Brand type: drop 'hanzo'|'zoo'|'lux' union -> string (open/extensible).
- Delete hardcoded BRAND/CHAIN consts -> proxy the active brand (16 call sites
  unchanged, now read the live brand).
- isMachinesEnabled: config field, not a hardcoded brand check.
- Examples each ship their own brand.config.ts (apps do the same downstream).
- Neutral test (fixture brands, no bundled assumptions).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 19:45:16 +00:00
hanzo-devandClaude Opus 4.8 fb2a9a46a1 refactor(iam): brand-neutral login hook (config-driven, PKCE, per-brand)
Replace hardcoded-hanzo useHanzoLogin (hanzo.id, placeholder clientId, shipped
client secret, wrong oauth-deep-link event) with brand-neutral useIamLogin that
reads the active brand's iam config (baseUrl/clientId/redirectUri/callbackEvent)
from @hanzo_network/brand-config and uses public-client PKCE. Adding a brand is
now a config entry; nothing is hardcoded to one brand.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 18:46:40 +00:00
hanzo-devandClaude Opus 4.8 3fa033bb6a fix(iam): real OAuth client IDs (hanzo-app/lux-app/zoo-app) for desktop login
Per-brand iam used placeholder clientIds not registered in Hanzo IAM. Domains
(hanzo.id/lux.id/zoolabs.id), redirect URIs, and callbackEvents were already
correct. Pairs with desktop redirects added to IAM init_data.json.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 18:28:36 +00:00
hanzo-devandClaude Opus 4.8 8eb8749f9d feat(@hanzo/ai): desktop build variant — converged frontend with full native
Add `@hanzo/ai/desktop` (vite.desktop.config.ts → dist-desktop): same converged
app as the web build, but it EXTERNALIZES @tauri-apps (14 modules) instead of
aliasing them to web shims — so a desktop consumer gets the REAL native APIs
(window/fs/dialog/updater/node-sidecar), full parity with the standalone forks.

This is the reusable foundation for converging the desktops locally: a desktop
shim is `import HanzoAI, { getBrand } from '@hanzo/ai/desktop'; <HanzoAI
{...getBrand()}/>` (VITE_BRAND selects hanzo/zoo/lux), loaded by the repo's Tauri
shell (which provides @tauri-apps + the node-manager handlers). hanzo/zoo have
full shells; lux's bespoke shell needs those handlers added.

build now emits both dist (web) + dist-desktop; exports['./desktop'] added.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 07:38:48 +00:00
hanzo-devandClaude Opus 4.8 2506356903 fix(@hanzo/ai web): per-brand document title + favicon (was hardcoded Hanzo)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 07:15:39 +00:00
hanzo-devandClaude Opus 4.8 a9825b5e21 build(@hanzo/ai): make publishable — drop workspace deps, public types, access
Prep for `npm publish @hanzo/ai` (the @hanzo scope):
- Drop the `@hanzo_network/* : workspace:*` runtime deps — they're bundled into
  the self-contained dist (aliased to src at build), and workspace:* can't be
  installed by consumers. Real 3rd-party deps stay.
- `publishConfig.access = public` (scoped package).
- Ship a hand-authored, self-contained public-API `dist/index.d.ts`
  (types/public.d.ts; the build copies it). Raw tsc would emit a broken tree of
  internal/@hanzo_network imports for a bundled lib.

Verified: `npm pack --dry-run` → valid tarball with dist + index.d.ts.
Note: 14 MB (bundles streamdown→shiki's ~200 grammars); a follow-up can
externalize shiki to slim it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 06:45:23 +00:00
hanzo-devandClaude Opus 4.8 bc16705b98 ci(@hanzo/ai): run the SDK tests in CI; fix libsodium path portability
- Add `test:web` to @hanzo/ai so the existing Checks `unit-tests` job
  (`turbo run test:web`) includes the 63 SDK unit/regression tests
  (verified: `turbo run test:web --filter=@hanzo/ai` → 63 passed).
- Replace the hardcoded /home/z libsodium alias in web/vite.config.ts with a
  __dirname-relative resolve so the web build works off this machine (CI).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 06:37:52 +00:00
hanzo-devandClaude Opus 4.8 0c75ac97b7 fix(@hanzo/ai): clean the web console — host shims, CORS, auth timing, motion
Every console error/warning from the running web app, fixed and guarded by the
e2e (which now asserts the console stays clean):

- react-query "Query data cannot be undefined": web host `invoke` returns null
  (not undefined) for no-op native calls.
- "isPermissionGranted is not a function": complete the notification host shim
  (isPermissionGranted/requestPermission/sendNotification via the browser API).
- CORS on direct :36900/v1/engine/models: route the hanzo-engine client through
  a same-origin `/engine-api` vite proxy (set VITE_ENGINE_BASE_URL=/engine-api).
- "ws://localhost:1501 failed": the app derives ws port = httpPort+1; add
  local-runtime/ws-proxy.js (:1501 → node WS :3701).
- 401 /v1/node/available_models: gate useGetLLMProviders on auth — it mounted
  during onboarding and fired with an empty Bearer.
- framer-motion `motion()` deprecation → `motion.create()` (2 sites).

Tests: unit 63/63, e2e 2/2 (now also asserts no CORS / "is not a function" /
react-query-undefined / available_models / :1501 in the console). Remaining: a
rare intermittent static-asset 404 + a node-side embedding warning — neither
affects chat (documented in CHAT.md).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 06:33:23 +00:00
hanzo-devandClaude Opus 4.8 172edb1948 test(@hanzo/ai): vitest unit/regression + Playwright e2e + TDD setup
Establish the test harness and lock in every bug found this session as a
regression test (TDD going forward — see TESTING.md):

- vitest.config.ts: jsdom + the web build's alias graph (@/, @tauri-apps→host
  shims, @hanzo_network→src), streamdown stub, @testing-library/jest-dom setup.
  `bun run --cwd pkgs/ai test` → 61 tests green (4 new + the 7 pre-existing).
- src/__tests__/ regressions:
  • brand-store — useBrand/getBrand are plain getters callable outside render
    (the invalid-hook-call that blocked the web app)
  • host-shims — getCurrentWindow().emit etc. exist; host adapter web↔tauri
  • resizable — react-resizable-panels v3 API present + net-ui renders
  • no-missing-imports — critical screens import every <Component> they use
    (the dropped Box/Boxes/Coins lucide imports)
- e2e/chat.e2e.test.ts (vitest.e2e.config.ts): Playwright drives the real
  browser — onboarding smoke + connect→register→send→assert zen-coder reply.
  Skips cleanly when the local runtime isn't up. `test:e2e` → 2 passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 05:38:57 +00:00
hanzo-devandClaude Opus 4.8 3f9f668692 feat(@hanzo/ai): chat works end-to-end in the browser (verified local)
The web app now chats with zen-coder-24b through a real hanzo-node, fully in the
browser (Playwright e2e: "Reply with exactly: E2E CHAT OK" → zen-coder generated
exactly that). Fixes uncovered by driving the real UI:

- main-layout.tsx: restore missing lucide imports Box/Boxes/Coins (the chat
  screens crashed with "Box is not defined").
- react-resizable-panels: the merge pulled v4 (Group/Separator), but the app
  uses the v3 API (PanelGroup/PanelResizeHandle) — pin ^3.0.2 in net-ui so the
  chat conversation view renders.
- web/vite.config.ts: proxy /v1 (the node's API is /v1/node/*, 135 endpoints) in
  addition to /v2 + /ws, so the browser reaches the node same-origin (no CORS).

local-runtime/ holds the reproducible inference wiring (see CHAT.md):
- responses-proxy.py: the node's OpenAI provider POSTs /v1/engine/responses, but
  hanzo-engine serves the Responses API at /v1/responses — rewrite the path
  (+ enable_thinking:false). This was the "AI Provider API Error" root cause.
- run-node.sh: a standalone /v1 node wired to the engine + embeddings. Uses
  127.0.0.1 everywhere (localhost → IPv6 ::1 → instant connection failure).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 05:03:49 +00:00
hanzo-devandClaude Opus 4.8 35a492d22a Merge origin/main into @hanzo/ai SDK — land the AI app on main
Reconciles the 140 upstream commits with the @hanzo/ai SDK (pkgs/ai +
pkgs/net-*, purely additive). Only bun.lock conflicted; regenerated fresh from
the merged package.json. The markdown dep skew that this exposed is fixed by
the prior commit (shiki@^3 override + dev streamdown stub).

Verified post-merge: fresh `bun install` exit 0, turbo build passes, web prod
build (rollup, 13MB) renders the Hanzo onboarding screen, dev server renders.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 00:49:52 +00:00
hanzo-devandClaude Opus 4.8 b04a5d329d fix(@hanzo/ai): harden markdown deps — clean install now renders
The committed lock had a latent skew that only surfaced on a clean `bun install`
(earlier session renders used an ephemeral node_modules):

- shiki: `@vxrn/mdx` pins shiki 1.3.0 *exact*; bun hoisted it over
  `@streamdown/code`'s `shiki@^3` (no `engine/javascript` export → build fails).
  Fix: `overrides.shiki = ^3.19.0`. Deterministic; @vxrn/mdx is docs-only, not
  in the app graph. This alone makes the PROD and LIB builds (rollup) clean —
  rollup resolves the rest of the nested micromark stack correctly.

- micromark: a v1↔v4 generation skew (16 v1 consumers from the remark/MDX docs
  stack vs 1 v2 consumer = streamdown). The two APIs (util@1 subpath exports vs
  util@2 root) must coexist nested, and rollup handles it — but esbuild's DEV
  pre-bundle flattens the bare `micromark-util-symbol` to the hoisted @1
  ("Missing '.' specifier"). Fix: a DEV-ONLY (command==='serve') stub of the
  streamdown stack (streamdown-stub.tsx); the prod build uses the real packages
  so chat markdown/code/math/mermaid are unaffected in production.

Verified clean: web dev server renders the onboarding screen, web prod build
(rollup, 13MB) renders, self-contained lib dist builds.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 00:46:14 +00:00
hanzo-devandClaude Opus 4.8 d77c97ffbe feat(@hanzo/ai): web→node proxy + chat wiring recipe
Add an env-configurable same-origin dev proxy (/v2 + /ws → VITE_NODE_API/
VITE_NODE_WS) so the browser reaches a hanzo-node without CORS: the app's
nodeAddress becomes its own origin and vite forwards to the node.

CHAT.md documents the verified state: the zen engine answers on :36900
(zen-coder-24b), and a healthy node (:2000, v1.1.20) already has the zen_engine
provider wired to it. Remaining blocker is API-version alignment — the app
client speaks /v1/node/*, the healthy node serves /v2/* only, and the
/v1-compatible desktop node (:3690) is currently hung. Recipe for both paths
included.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 00:11:54 +00:00
hanzo-devandClaude Opus 4.8 4990fb7ebf docs(@hanzo/ai): CONVERGENCE.md — one surface, web⇄desktop parity, verification matrix
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 23:54:57 +00:00
hanzo-devandClaude Opus 4.8 b81ad520a9 feat(@hanzo/ai): self-contained dist + brand re-export → thin shims work
Make @hanzo/ai consumable as a published APP-as-SDK so each app collapses to
a ~10-line shim (the luxfi/exchange model, for AI):

- Lib build now bundles EVERYTHING (the app, net-* libs, @tauri-apps host
  shims, all 3rd-party deps) and externalizes ONLY react/react-dom as peers.
  Previously every dep was external, so a consumer installing just @hanzo/ai
  was missing libsodium/framer-motion/radix/etc. (pinned libsodium's CJS build
  in the lib config too, now that it's bundled rather than external).
- Re-export getBrand/getBrandFromHostname from the package, so a shim needs no
  separate brand package for the default case:
    import HanzoAI, { getBrand } from '@hanzo/ai'
- Shims (hanzo/zoo/lux/web) aligned to the proven pattern: brand is a build
  axis (VITE_BRAND), platform an injected prop (host={tauriHost}), app is
  @hanzo/ai. Added a runnable web shim (index.html + vite.config) that imports
  @hanzo/ai from its built dist providing only react.

Verified: the external web shim (only react/react-dom provided, everything
else from dist) renders the full Hanzo onboarding screen on :1503.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 23:54:10 +00:00
hanzo-devandClaude Opus 4.8 20c58fa38b fix(@hanzo/ai): web app renders — break the dist self-import cycle
The web app threw `Cannot read properties of null (reading 'useContext')`
(invalid hook call) and never painted. Root cause was NOT React duplication
from a dep: 7 migrated app modules imported `useBrand` from the `@hanzo/ai`
PACKAGE name, which resolves to the built `dist/index.js`. That pulled the
whole minified library (a second React + a second copy of the app) back into
the source graph — a module cycle with a dual React dispatcher.

Fix: the injectable brand store lives in `@hanzo_network/brand-config`
(`setBrand`/`useBrand`, plain module getters — not hooks — so the app's
non-component call sites are safe), aliased to src so there is ONE copy and
no cycle. The 7 app files now import `useBrand` from there; `@hanzo/ai`'s
`brand-context` just re-exports it. Rule: app code never imports the
`@hanzo/ai` package by name.

Also completed `src/host/window.ts` to the full Tauri Window surface
(`emit`/`listen`/`once`/`onCloseRequested`/geometry) — the missing `emit`
was the next crash after the cycle was broken. Production web entry cleaned
up with a real ErrorBoundary.

Verified: dev server on :1500 paints the real Hanzo onboarding screen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 23:46:13 +00:00
hanzo-devandClaude Opus 4.8 14b66ceb24 feat(@hanzo/ai): decomplect the AI app into one declarative SDK
The entire shinkai-fork AI app (280 files) + its 7 @hanzo_network/* libs,
lifted into @hanzo/ai as <HanzoAI {...brand} host={}/> — brand is a prop,
platform is an injected HostAdapter (web / tauri / expo). One unified surface
for hanzo/zoo/lux desktop + mobile + web (hanzo.chat). Library build green
(2.8MB) and production web build green (14MB). Shims in examples/.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 22:31:02 +00:00
Antje WorringandClaude Opus 4.8 80429c8532 Commit local working changes
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 12:39:47 -07:00
hanzo-dev f8c232829d chore: scrub last 2 bento refs (planning docs)
plans/new-checkout-flow.md: 'Bento' product column → 'Recipes'
next.md: 'site/bento' → 'site/recipes' (route was renamed earlier)
2026-05-28 00:33:43 -07:00
hanzo-dev bbe58ed97d chore: rip supabase + stripe from cloud UI — migrate to @hanzo/{iam,base} + hanzoai/commerce
- Auth: @supabase/{ssr,supabase-js,auth-js} → @hanzo/iam (server JWT
  validation via JWKS, browser session via IAM SDK). `features/iam/{server,client}`
  expose `authenticate(req)` + `useIamSession()`. `useSupabaseClient` is now
  a thin compat shim so the login + auth + user.tsx flows keep compiling.
- DB: supabaseAdmin.from(...) → @hanzo/base via a small adapter at
  `features/db` that mimics the .from/.select/.insert/.update/.delete shape
  used across ~60 files. supabaseAdmin re-exports the adapter so legacy
  call sites keep working; storage moved to `features/db/storage` (bucket
  `bento` → `recipes`).
- Subscriptions: stripe.* → commerce.subscriptions.* via a typed REST
  client at `features/commerce/client`. cancel-subscription,
  remove-subscription-item, upgrade-subscription, create-subscription,
  add-team-seats, enable-v2-renewal, handle-failed-payment-subscription
  rewritten as commerce pass-throughs.
- Deleted: app/api/stripe/webhook+api.ts — commerce owns the webhook
  surface; gui should never terminate Stripe traffic.
- V2 checkout, admin impersonate, test-user fixture: replaced with
  501-not-implemented stubs + TODO(supabase-rip). These flows now belong
  in commerce + @hanzoai/pay + IAM admin assume-identity.
- Stripe UI: StripePaymentModal (1447 lines) and AddTeamMemberModal
  collapsed to thin redirect stubs that bounce to commerce.hanzo.ai/checkout.
- Deps: remove @supabase/ssr, @supabase/supabase-js, @stripe/react-stripe-js,
  @stripe/stripe-js, stripe. Add @hanzo/iam ^0.9.4, @hanzo/base ^0.2.0.
  Drop matching entries from vite.config optimizeDeps + ssr externals.
- Rename SUPABASE_AUTH_SUCCESS postMessage event → HANZO_AUTH_SUCCESS.

Build status: bun install clean, `tsc --noEmit` zero app errors, 40/40
vitest tests passing.

TODO(supabase-rip) markers flag the remaining deep-rewrite work
(V2 purchase flow, OG image upload, admin user impersonation, IAM admin
user lookup for unclaim flows). Each one is a clean handoff to a sibling
service rather than a hidden coupling.
2026-05-28 00:32:02 -07:00
hanzo-dev e8c3b4ee27 fix(hanzogui): drop dead exports — ./react-native-web + native-test rn
Both subpaths reference dist files the build doesn't produce:
- ./react-native-web/*: no src/react-native-web.{ts,tsx} exists, gui-build
  has nothing to bundle. Consumers use @hanzogui/react-native-web
  (scoped pkg) instead.
- ./native-test had `react-native: ./dist/test.native.js` but
  bundle-native.mjs only emits test.cjs. Drop the dead
  react-native condition — the require+default both correctly point
  at test.cjs.

Smoke-test was correctly catching this. Forwards-only fix per
"no backwards-compat shims" — if anyone was depending on the broken
subpath, they were getting MODULE_NOT_FOUND already.
2026-05-27 18:42:50 -07:00
hanzo-dev 0c7652dc01 ci: rewrite smoke-test to metadata-only (extract from tarball)
The previous npm-install-based smoke fails on first release because
hanzogui's @hanzogui/* workspace deps aren't on npm at the new version
yet (chicken-and-egg — we publish hanzogui umbrella first, primitives
publish after via bun release). \`--silent\` also hid the actual error
making attempt 4's failure opaque.

New shape: tar -xzf the tgz, then check tarball contents directly:
- name === 'hanzogui' (literal token static extractor scans for)
- no leftover 'workspace:*' specs (pack step must rewrite all of them)
- every ./path referenced in exports/main/module/types exists in tarball

Catches: broken exports map, wrong main/module paths, missing files
in `files` glob, Gui→gui rename leaks, workspace:* not rewritten.
Doesn't catch: actual runtime resolution / peer dep mismatch — those
are validated by downstream consumers after publish, not here.
2026-05-27 18:35:15 -07:00
hanzo-dev c1f3a53376 ci: NPM_TOKEN resolution fallback chain + fix umbrella working-dir
Two fixes to unblock release/gui-v7.3.0 publish attempt 3 (which
failed at the KMS auth step because KMS_CLIENT_ID/SECRET aren't
configured on the hanzoai/gui repo secrets, and HANZO_API_KEY isn't
either).

1. Add fallback chain in token resolution:
   KMS Universal Auth → KMS HANZO_API_KEY → direct repo secret
   NPM_TOKEN. Keeps the KMS path as the preferred future state while
   unblocking publishes today using the repo-secret NPM_TOKEN that
   release.yaml + the rest of the org's workflows already use.

2. Fix the Publish step's working-directory: pkgs/ui/gui →
   pkgs/ui/hanzogui. The umbrella package lives at pkgs/ui/hanzogui
   (Artem's prefix-drop commit renamed the file/identifier content but
   not the directory itself). pkgs/ui/gui is an orphan dir holding
   just dist/ + types/ — untracked, can be deleted later.
2026-05-27 18:27:03 -07:00
hanzo-dev 1c73766955 fix: tsconfig refs ../../packages/X → ../../X (second flatten fallout)
Last batch of flatten side-effects: tsconfig.json `references` arrays
in packages at pkgs/{compiler,core,ui}/<X>/ that had `"path":
"../../packages/<Y>"` (correctly resolving to pkgs/packages/<Y> in the
old layout). After flatten those targets are at pkgs/<Y>, so the path
needs to be `"../../<Y>"`.

10 tsconfig.json files updated:
- pkgs/ui/hanzogui/, ui/tabs/, ui/input/, ui/focus-scope/
- pkgs/core/web/
- pkgs/compiler/{loader,next-plugin,static,static-tests,vite-plugin}/

This was the root cause of the CI failure on release/gui-v7.3.0
attempt 2 — vite-transform's tsconfig resolver looked up
`/home/runner/_work/gui/gui/pkgs/packages/element` (stale path) when
bundling the hanzogui umbrella's native target. Local repro: same
error; same fix; `bun run build` for pkgs/ui/hanzogui now succeeds.
2026-05-27 18:21:14 -07:00
hanzo-dev b326f69aaf chore: rebrand bento → recipes in gui.hanzo.ai cloud UI
Drops Tamagui-era "Bento" naming from the cloud UI app and adopts
"Recipes" — the vernacular already in use across the gui stack
(@hanzogui/recipes pkg, gui_recipes Base collection).

Scope: apps/gui.hanzo.ai/ only.

Changes:
- 5 directories renamed (app/(site)/bento, app/api/bento,
  features/bento, components/bento-showcase, public/bento)
- 14 code files renamed (Bento*.tsx → Recipes*.tsx, etc.)
- 5 public asset files renamed (bento-box.svg, bentoduck.svg, etc.)
- 2 scripts renamed (generate-bento-proxy.mjs,
  insert-bento-product-ownership.mjs)
- ~93 files string-replaced (identifiers, JSX text, CSS classes,
  routes, marketing copy, vite aliases)

External-system refs left alone (need separate migration):
- Supabase storage bucket .from('bento') and bento-bundle.zip
- Supabase RPC public.has_bento_access + the matching type
- Supabase migration SQL (live DB schema)
- Stripe product name value 'Bento' (ProductName.GuiRecipes still
  resolves to 'Bento' — Stripe-side rename TBD)
- Stripe product slug value 'bento' (ProductSlug.Recipes still
  resolves to 'bento')

Drops the hasRecipesAccess backwards-compat alias — forwards-only.
2026-05-27 18:19:56 -07:00
hanzo-dev f7ede33a01 fix: tsconfig depth + bun.lock regen after pkgs/packages flatten
Side-effects of the pkgs/packages/* → pkgs/* flatten that
broke the CI publish:

1. **tsconfig depth (18 files)**: packages at pkgs/packages/X/tsconfig.json
   had \`"extends": "../../../tsconfig.json"\` pointing 3 levels up to the
   monorepo root. After flatten they're at pkgs/X/tsconfig.json (2 levels
   deep) — need \`"../../tsconfig.json"\`. Failure surface: gui-build
   crashed with "TS5083: Cannot read file '../../../tsconfig.json'" on
   every flattened package (cli-color was just the first one turbo hit).

2. **bun.lock regen**: lockfile still referenced pkgs/packages/* paths
   throughout the workspace map. \`bun install\` regenerated it cleanly
   (652 ins / 1433 del). Required so CI's \`bun install\` doesn't try
   to resolve stale paths.

Now \`bun run build\` succeeds for cli-color (was the first failure in
the turbo build order on the release/gui-v7.3.0 CI run).
2026-05-27 18:08:37 -07:00
hanzo-dev 6133e014b4 ci: drop publish-on-tag (stale: code/ paths, @hanzo/gui scope); publish-gui.yml supersedes 2026-05-27 17:53:47 -07:00
hanzo-dev b12fa73c91 chore: remove admin from hanzoai/gui — extracted to hanzoai/admin
Companion to hanzoai/admin@fd68af5 (filter-repo extraction, history
preserved). admin no longer ships from this monorepo.

Removed:
- apps/admin-{agent,auto-stub,base,base-go,bot,commerce,tasks}/
- pkgs/ui-admin/ (became pkgs/admin/ in hanzoai/admin)
- package.json workspaces: drop ./apps/admin-{base,bot,commerce,tasks}
- .github/workflows/publish-gui.yml: drop @hanzogui/admin
  typecheck/pack/publish steps, narrow smoke-test to gui only, retitle

@hanzogui/admin@7.3.0+ now publishes from hanzoai/admin via its own
release pipeline (separate npm publish lane). Existing 7.3.x and below
on npm continue to resolve fine; new versions just come from a
different repo.

ONE WAY ONLY: hanzoai/gui = primitives, hanzoai/admin = admin SPAs +
shell. Each repo owns one concern.
2026-05-27 17:51:47 -07:00
hanzo-dev 200208eb2a chore: rename @hanzo/recipes → @hanzogui/recipes (consolidate scope)
@hanzogui is the canonical scope for all GUI surface — recipes is GUI
content, so it moves under @hanzogui. Also fixes lingering
repository.directory paths from the earlier flatten that still said
pkgs/packages/{get,recipes} (they should have updated alongside the
mv but git did not detect the rename because the file content had
diverged too much for the heuristic).

- pkgs/recipes/package.json: name @hanzo/recipes → @hanzogui/recipes
- pkgs/recipes/{build.ts,readme.md}: rebrand log line + docs
- pkgs/get/package.json: dep @hanzo/recipes → @hanzogui/recipes
- pkgs/get/src/commands/{add,init,list,pick}.ts: 4 import sites
- scripts/seed-recipes.ts: server-side seed import
- pkgs/{get,recipes}/package.json: repository.directory pkgs/packages/X → pkgs/X
2026-05-27 17:38:19 -07:00
hanzo-dev e9811d0ad3 chore: flatten pkgs/packages/* → pkgs/* (one canonical pkgs dir)
ONE WAY ONLY: 'pkgs' is the canonical name for any directory holding
packages. The redundant 'pkgs/packages/' sub-level is dropped — every
package now lives at pkgs/<name>/ (with categorical sub-groups
pkgs/compiler/, pkgs/core/, pkgs/ui/ unchanged since they are
sub-systems, not just 'packages').

- mv pkgs/packages/* → pkgs/* (24 packages)
- rm pkgs/packages/hanzogui-dev-config (orphan: only had dist/ artifacts,
  no source; gui-dev-config is the canonical @hanzogui/dev-config)
- package.json workspaces: drop pkgs/packages glob, add ./pkgs/*
- tsconfig.json: rewrite paths + 15 references entries
- apps/{demos,kitchen-sink,gui.hanzo.ai}/tsconfig.json: reference paths
- .github/workflows/publish-gui.yml: directory walk list
- pkgs/{get,recipes}/package.json: repository.directory

bun.lock will regenerate on next install.
2026-05-27 17:33:42 -07:00
hanzo-dev ac7ea90e55 chore: rename @hanzo/gui-get → @hanzogui/get (consolidate scope)
ONE WAY ONLY: lean CLI installer lives under the @hanzogui scope alongside the rest of the GUI primitives. The redundant "gui-" prefix is dropped (already in the scope name).

- mv pkgs/packages/gui-get → pkgs/packages/get
- package.json: name @hanzo/gui-get → @hanzogui/get, bin gui-get → hanzo-gui-get (matches @hanzogui/build's hanzo-gui-build), repository.directory updated
- src/constants.ts: CLI_NAME → hanzo-gui-get
- build.ts: log line rebrand
- readme.md: rewrite around @hanzogui/get + hanzo-gui-get binary

Removed: empty pkgs/packages/bento-get scaffold (orphan from old Tamagui Bento fork).

Companion actions outside this commit:
- hanzogui/get GitHub repo archived (was the renamed bento-get fork, now dead)
- @hanzogui/bento-get to be deprecated on npm pointing at @hanzogui/get
- Publish @hanzogui/get@7.3.0 via 'bun release' (manual, requires npm auth)
2026-05-27 16:51:47 -07:00
hanzo-dev dc17af4a3b chore(release): bump @hanzogui/* to 7.3.0
Minor bump covering the TAMA→GUI rip + Hanzogui→Gui file/identifier
rename. Public API (`@hanzogui/*` namespace, exported `GuiProvider`/
`createGui`/`Gui`/`Text`/`View`/`styled`/...) unchanged from 7.0.0
on npm; this release brings source artifacts in line with what was
already shipped in dist and removes all upstream brand references.

Internal-only breaking surface: compiler env vars (`TAMAGUI_TARGET`,
`TAMAGUI_IS_SERVER`, etc.) renamed to `GUI_*`. Affects only consumers
piping flags into the static extractor.
2026-05-26 20:20:24 -07:00
hanzo-dev c0c143a6f5 chore: drop 'hanzo' prefix from file/identifier names, use 'gui'/'Gui'
Internal renames so source matches the published @hanzogui/web@7.0.0 dist
(Gui.ts, createGui.ts, views/GuiProvider.mjs, views/GuiRoot.mjs).

Renames applied:
- Files: Hanzogui.ts -> Gui.ts, createHanzogui.ts -> createGui.ts,
  HanzoguiProvider.tsx -> GuiProvider.tsx, HanzoguiRoot[.native].tsx ->
  GuiRoot[.native].tsx, HanzoguiPlugin.ts -> GuiPlugin.ts,
  withHanzogui.ts -> withGui.ts, loadHanzogui.ts -> loadGui.ts,
  v4-hanzogui.ts -> v4-gui.ts, *.d.ts mirrors, hanzogui.config.ts ->
  gui.config.ts, hanzogui.build.ts -> gui.build.ts, hanzogui.css ->
  gui.css, hanzogui-build.js -> gui-build.js, etc.
- Directories: pkgs/core/create-hanzogui -> pkgs/core/create-gui,
  apps/sandbox/config/hanzogui -> apps/sandbox/config/gui.
- Identifiers: Hanzogui* -> Gui*, createHanzogui -> createGui, withHanzogui
  -> withGui, loadHanzogui -> loadGui, HANZOGUI_* env -> GUI_*,
  __hanzogui* globals -> __gui*, hanzoguiOptions/hanzoguiConfig/
  hanzoguiPlugin etc. -> guiOptions/guiConfig/guiPlugin, CSS vars
  --hanzogui-* -> --gui-*, data-hanzogui-* -> data-gui-*, [hanzogui]
  log prefix -> [gui].
- Removed duplicate pkgs/packages/hanzogui-dev-config; the canonical
  pkgs/packages/gui-dev-config (@hanzogui/dev-config) already existed
  with the correct shape. apps/demos now consumes @hanzogui/dev-config.

Preserved (public npm names):
- "hanzogui" umbrella package (pkgs/ui/hanzogui/package.json)
- "@hanzogui/*" namespace
- "hanzogui-loader" package name (pkgs/compiler/loader)
- "hanzogui-build-test-*" test fixture names
- "hanzogui-publish-smoke" workflow id
- pkgs/core/helpers-hanzogui dir (not on rename list)
- apps/gui.hanzo.ai/ marketing site directory
- AGENTS.md symlink restored after perl -i clobbered it

Smoke build (turbo run build): 169/169 workspaces successful.
Sample tests: pkgs/core/core-test getSplitStyles.android* + createGui.web
all green.
2026-05-26 18:25:52 -07:00
hanzo-dev f5c6771e5c chore: rip remaining TAMA — zero references in tracked files
Continuation of the chore/rip-tama sweep. The earlier pass left
9 compromises that violated the zero-tolerance directive; this
removes them and brings the tree to 0 tamagui refs (verified
via `git ls-files | xargs grep -l tamagui` excluding deleted).

Removed:
- .tamagui cache-dir entries from .gitignore/.dockerignore/.oxfmtrc.jsonc
  and three sub-gitignores (apps/sandbox, apps/tests/next-turbopack,
  templates/{expo-router,remix}). No backwards-compat for the old cache dir.
- scripts/rename-from-tama.sh migration script (no migration path).
- pkgs/ui/switch/src/Switch.draggable-tmp scratchpad with @tamagui/* imports.
- assets/banners.sketch binary (uneditable; designer can redo from
  current branding if needed).
- @take-out/cli devDependency + its upgradeSets entry (third-party
  CLI whose transitive @tamagui/constants was the only tamagui ref
  in bun.lock).

Renamed (asset metadata):
- SVG <title>/<g id="tamagui-words"> in gui-words.svg / logo-white.svg
  → "hanzogui-words" (Sketch artboard names left over from the fork).
- favicon.svg "Tamagui"/"tamagui" → "hanzogui".
- iOS bundle ID `dev.tamagui.kitchensinkgo` → `ai.hanzo.kitchensinkgo`
  in Info.plist and project.pbxproj.

LICENSE files (~120, all packages):
- Replaced explanatory line "Portions of this software are derived
  from Tamagui, originally licensed under..." with "Portions of
  this software are derived from upstream code originally licensed
  under...". Copyright lines (Wienert, Gallagher, Facebook, Radix,
  Pullara, Framer, WorkOS) preserved verbatim per MIT terms — those
  are legal attribution, not brand references.

Regenerated:
- Root bun.lock after dropping @take-out/cli. 1 package removed,
  zero tamagui refs remain.
- templates/expo-router/bun.lock deleted; the template uses
  workspace:* deps and consumers regenerate on first `bun install`.

Verified: `git ls-files | xargs grep -lE 'tamagui|TAMAGUI|Tamagui'`
returns no results.
2026-05-26 17:54:12 -07:00
hanzo-dev b0705cf342 chore: rip all TAMAGUI/Tamagui/tamagui refs, replace with HANZOGUI/Hanzogui/hanzogui
Eradicate every upstream-fork token from source. Scope is the published
hanzogui ecosystem — the artifacts on npm (@hanzogui/*@7.0.0) are already
clean; this sweep brings the source tree to parity.

Categories handled (in sed precedence order to avoid token collisions):
- URL rewrites: github.com/tamagui/tamagui -> github.com/hanzoai/gui,
  tamagui.dev -> gui.hanzo.ai
- Package namespace: @tamagui/X -> @hanzogui/X (imports, package.json deps,
  __tests__ fixtures, build scripts)
- Env vars: NEXT_PUBLIC_IS_TAMAGUI_*, IS_TAMAGUI_*, DEBUG_TAMAGUI_*,
  TAMAGUI_* (TARGET, IS_SERVER/CLIENT, ENVIRONMENT, OPTIMIZE_THEMES,
  HEADLESS, DEBUG, KEEP_THEMES, PACKAGE_EXPORTS, PRO_SECRET, etc.) all
  collapse to GUI_* prefix (short, matches @hanzogui/ namespace ergonomics)
- Vite envPrefix: ['TAMAGUI_'] -> ['GUI_'] in pkgs/compiler/vite-plugin
- PascalCase identifiers: Tamagui -> Hanzogui (any remaining
  TamaguiCustomConfig, TamaguiInternalConfig, etc. in source)
- Lowercase strings/comments/log labels: tamagui -> hanzogui
- Filename: scripts/rename-from-tamagui.sh -> scripts/rename-from-tama.sh
  (and the script's internal rules were rewritten to be self-consistent —
  it still consumes upstream tamagui sources and produces hanzogui output)
- Dockerfile.local ARG names: ARG IS_TAMAGUI_DEV -> ARG IS_GUI_DEV,
  ARG TAMAGUI_PRO_SECRET -> ARG GUI_PRO_SECRET, etc.
- .env.development: NEXT_PUBLIC_IS_TAMAGUI_DEV -> NEXT_PUBLIC_IS_GUI_DEV
- bun.lock regenerated via bun install

Decisions on edge cases:
- .gitignore / .dockerignore / .oxfmtrc.jsonc / templates: kept .tamagui
  entries alongside the new .hanzogui entries as safety so legacy cache
  directories from older installations are still ignored. Net additive.
- pkgs/packages/build/__tests__/fixtures/{simple,watch}-package: the fixture
  + builder (hanzogui-build.js) + integration.test.ts all reference
  TAMAGUI_TARGET symmetrically (test asserts builder DCE-eliminates it).
  Renamed all three to GUI_TARGET — test contract is preserved end-to-end.
- pkgs/compiler/static/src/helpers/requireHanzoguiCore.ts: file was already
  renamed; internals already use HanzoguiPlatform / @hanzogui/core. No-op.
- plans/toast2.md: renamed to use hanzogui (no longer tracking upstream
  tamagui issues — this fork is independent).
- assets/banners.sketch: binary Sketch file (zip archive). Skipped — same
  treatment as svg/plist/pbxproj. Internal XML may still contain "tamagui"
  but it's only visible inside the design tool.
- bun.lock: 2 remaining @tamagui/constants references come from third-party
  transitive (@take-out/helpers depends on it). Cannot rewrite upstream
  package metadata.
- LICENSE files (root + per-pkg): preserved unchanged. MIT attribution to
  Tamagui Inc is a legal requirement.
- .git/config upstream remote: untouched (per task spec).
- pkgs/ui/switch/src/Switch.draggable-tmp: scratchpad, left alone.

Smoke tests:
- bun install: clean (lockfile regenerated, 1 package installed)
- @hanzogui/constants: builds in 302 ms
- @hanzogui/web (200+ source files): builds in 4187 ms
- @hanzogui/vite-plugin: builds in 997 ms
- @hanzogui/static: builds in 2547 ms

Residual count after sweep:
- git grep -ci tamagui (excluding LICENSE, lockfiles, binaries, draggable-tmp,
  rename script, intentional .gitignore safety entries): 0 source matches.

158 files changed.
2026-05-26 17:47:23 -07:00
hanzo-dev fb882d58b7 feat(@hanzogui/shell): peerDep @hanzo/iam ^0.11.0, use clean User/Organization names 2026-05-26 15:02:50 -07:00
hanzo-dev 794aec0797 feat(@hanzogui/shell): point at @hanzo/iam (canonical IAM client), bump 7.2.3 2026-05-26 15:00:17 -07:00
hanzo-dev 2668a67c8d feat: extract @hanzogui/shell — canonical multi-tenant navigation shell 2026-05-26 14:56:15 -07:00
hanzo-dev a92695f15f Merge sync-upstream-2.0.0 (tamagui 2.0.0 sync) into main (restructured pkgs/)
Two parallel streams of work landing together:

  • main: 74 commits — code/ → pkgs/+apps/+templates/ restructure, admin-base
    SPAs scaffolded, bento-get → gui-get rename, license/version 7.2.x bumps,
    @hanzogui/core type refactor (drop "Hanzogui" prefix), CI/build hardening,
    workspace:* resolves at pack time.

  • sync-upstream-2.0.0: 11 commits — wholesale upstream tamagui 2.0.0 sync
    over the (then-current) code/ tree, plus 10 fix-ups for types/, tsconfig,
    stale .d.ts artifacts, dep cleanup, hanzogui-build clean:build workaround,
    @tamagui/types → @hanzogui/types rename.

Conflict resolution doctrine: main is canonical for STRUCTURE (pkgs/ wins
over code/). Sync's fixups for types/tsconfig were largely superseded by
main's restructure work. Where both branches touched the same package.json
the published 7.2.3 from main wins (sync's 7.0.0 was already pushed to npm
and is now historical).

Resolved:
  • 1544 UD (sync deleted demos/sandbox/gui.hanzo.ai/starters; main kept
    those + restructured them) → kept main's restructured versions
  • 268 UA (both branches added the same paths with different content,
    typically lucide-icons backwards-compat shims) → kept main's
  • 175 UU (package.json version bump conflicts + 2 tsconfigs) →
    kept main's canonical 7.2.x + main's pkgs/ paths
  • 2 DU (main deleted files sync had modified) → accepted deletions

Net: the value Artem captured on sync-upstream-2.0.0 was the npm
publish of 7.0.0, which already shipped. Main's 7.2.3 supersedes it
and is the forward path. This merge closes the branch cleanly so the
history shows both streams converged rather than the sync branch being
abandoned.
2026-05-24 22:58:11 -07:00
Artem Ash 132b09a32d fix(types): bump @hanzogui/types to 7.0.0
when i overwrote this package.json earlier from upstream's tarball,
its version got reset to 2.0.0. sync-gui-versions.ts skipped it on
the first pass because its name was still @tamagui/types (chicken-
and-egg: filter requires the @hanzogui/ prefix). re-running after
the name rename catches it.
2026-05-24 16:14:00 -10:00
Artem Ash 23a6dad6a5 types: regenerate from current source as the new baseline
prior committed .d.ts files had drifted from current source over
multiple syncs. a fresh clean+force build emits 14 types differently
from what was committed — these are the accurate versions.

also reverts the floating --skip-types + custom clean:build workaround
from 98b82e613 / f4d6c480e. the original premise (hanzogui-build
drops '| null' from FloatingOverrideContext) only held when stale
types existed in types/ as the build was running. with a clean
types/ at build start, hanzogui-build emits the type correctly. no
workaround needed.
2026-05-24 15:55:05 -10:00
Artem Ash f4d6c480e7 fix(floating): clean:build preserves types/ (workaround for hanzogui-build bug)
hanzogui-build emits FloatingOverrideContext type as
React.Context<UseFloatingOverrideFn> instead of
React.Context<UseFloatingOverrideFn | null>, breaking every package
that imports it. workaround: build script uses --skip-types so the
committed (correct) types stay in place. but clean:build defaults
to wiping both dist/ AND types/ — override it here to wipe only
dist/ so the publish wave preserves our type fix.
2026-05-24 15:12:09 -10:00
Artem Ash bf5e392547 fix(types): rename @tamagui/types to @hanzogui/types in package.json
types-dir copy script earlier matched code/core/types as a directory
named 'types' and overwrote its package.json with upstream's
@tamagui/types name. subsequent rename pass only touched .ts/.d.ts,
not .json. bun install couldn't resolve @hanzogui/types@workspace:*
because nothing in the workspace exposed that name.

ran the rename rules across all package.json under code/ to belt-and-
suspenders catch any others.
2026-05-24 14:55:32 -10:00
Artem Ash 98b82e6139 fix(types): align types/ dirs with upstream + skip-types where hanzogui-build emits wrong
several packages had committed types/ files that drifted from source
over previous syncs. replaced our types/ contents with upstream v2.0.0's
(rename-translated) so they match current source.

@hanzogui/floating: hanzogui-build incorrectly drops '| null' from the
inferred type of FloatingOverrideContext on regeneration. set its
build script to --skip-types so the (now-correct) committed type is
preserved instead. real fix would be in hanzogui-build itself; this
unblocks the publish.

build status: 163/163 packages build successfully.

restored scripts/rename-from-tamagui.sh (was missing from earlier
commits).
2026-05-24 14:52:04 -10:00
Artem Ash 533a56de00 fix(react-native-web-lite): exclude from publish + remove stale .d.ts
ships 86 .d.ts files alongside .js source that don't exist upstream;
they confuse esbuild's loader inference. mark private until the
package's vendored react-native subtree builds cleanly with the
current hanzogui-build flow.
2026-05-24 14:06:09 -10:00
Artem Ash 128bcfb95d fix(tsconfig): restore full compilerOptions from upstream
earlier sed deletion of the @hanzogui/demos paths alias nuked the
bottom half of compilerOptions. restored noImplicitAny: false,
downlevelIteration: true, module: System, moduleResolution: node,
strict + strictNullChecks, target: es2020, etc. — verbatim from
upstream tamagui v2.0.0 root tsconfig.json (only paths differ to use
hanzogui-renamed aliases).
2026-05-24 14:00:25 -10:00
Artem Ash d40bed5868 fix: remove stale .js/.d.ts build artifacts from src/ dirs
upstream patches deposited compiled outputs into src/ alongside the
real .ts sources; esbuild treated both as inputs and hit output-path
collisions. removed every .js and .d.ts in src/ where a .ts or .tsx
sibling exists; kept 176 standalone .js/.d.ts files that look like
hand-written source.
2026-05-24 13:40:15 -10:00
Artem Ash 662bfb38f3 fix: drop workspace + dep refs to deleted demos/sandbox/gui.hanzo.ai/starters 2026-05-24 13:35:45 -10:00
Artem Ash 2e17b847f4 scripts: add upstream-sync + deprecate-pre-7 tooling 2026-05-24 12:46:01 -10:00
Artem Ash 01539b1b0e sync hanzogui tree to upstream tamagui 2.0.0
- merged upstream v2.0.0-rc.41 → v2.0.0 (~95 real commits + canary noise filtered)
- renamed via scripts/rename-from-tamagui.sh (committed alongside)
- bumped all @hanzogui/* + bare hanzogui to 7.0.0 (+5 convention, supersedes the 102.x RCs)
- removed code/gui.hanzo.ai/ (tamagui commercial marketing site — not needed for framework)
- removed code/sandbox/, code/demos/, code/starters/ (dev artifacts, not framework)
- tsconfig.json: added jsx: react-jsx + skipLibCheck: true for clean composition
- known issue: 3 kitchen-sink files broken (VariantsOrder.tsx, ZIndex.tsx, SheetAnimation.animated.test.tsx) — upstream stricter typing; framework substrate typechecks clean
2026-05-24 12:41:10 -10:00
hanzo-dev 4e810b071e admin SPAs: VITE_API_PREFIX, canonical block-H, BrandMark configurable
One mount-prefix knob per app, matches the server-side BASE_API_PREFIX.
Default per-app: /v1, /v1/tasks, /v1/agents, /v1/bot. Override at
deploy via VITE_API_PREFIX. IAM stays a fixed sibling at /v1/iam.

* admin-base: lib/api.ts gained API_PREFIX + apiPath(); every page +
  vite.config define block wired through. Logo wiring now respects
  VITE_BRAND_MARK_URL / VITE_BRAND_NAME / VITE_BRAND_SUBTITLE so
  white-label deployments override without code changes.
* admin-tasks / admin-agent / admin-bot: same pattern. Each lib/api.ts
  exports ROOT = '/' + (VITE_API_PREFIX ?? '/v1/<app>'). Pages now
  build URLs as `${ROOT}/...` instead of hardcoding `/v1/<app>/...`.
* BrandMark: HanzoMark now renders the CANONICAL block-H (five SVG
  paths, no font, no Geist text) on a BLACK chip — matches
  ~/work/hanzo/logo/dist/hanzo-favicon.svg exactly. Hanzo Red is for
  brand accents only, never the logo background.
* admin-base/public/favicon.svg fixed to the same canonical artwork.
2026-05-15 16:03:17 -07:00
hanzo-dev bca4a834bc admin-base: cut /api -> /v1, Bearer prefix, dedupe PKCE callback
End-to-end OIDC sign-in against the embedded /v1/iam now lands on the
collections page without leaking 401/403/PKCE-replay errors:

* lib/api.ts, src/pages/*: every fetch path moved from /api/* to /v1/*
  to match the Hanzo route convention. base no longer serves /api/.
* lib/api.ts: Authorization header is now standard OAuth2 `Bearer <jwt>`.
  The platform middleware accepts only Bearer; raw tokens 401'd.
* pages/Callback.tsx: gate handleCallback() on a module-scoped Set of
  consumed `code` params so React.StrictMode's intentional double-mount
  doesn't try to redeem the same single-use code twice.
* vite.config.ts: dev proxy now forwards /v1/* (was /api/) to
  VITE_BASE_URL or :8090. WebSocket survives the same path.
2026-05-15 15:04:08 -07:00
hanzo-dev 5800c91f32 chore(pkgs): scope gui-get under @hanzo/, tighten npm files for both 2026-05-15 14:46:04 -07:00
hanzo-dev 7a92232a6c feat(admin-base): vite-native env, OIDC redirect login (no /api/iam)
Decomplect: the env.ts cross-runtime shim was an "easy" bridge over
Vite + Metro that braided two unrelated platforms. Each platform now
reads env its native way — admin-base uses `import.meta.env.VITE_*`
directly; the Expo sibling (admin-base-go) owns its own
`process.env.EXPO_PUBLIC_*` strategy. One way per platform.

- src/env.ts                 : deleted (Function-shim was incidental
                               complexity over `import.meta.env`).
- src/App.tsx                : BRAND_*/APP_VERSION read directly from
                               `import.meta.env.VITE_*` (Vite inlines).
- src/pages/Login.tsx        : redirect-only PKCE. Click "Sign in" →
                               `iam.signinRedirect()` → IAM owns the
                               credential UI. No `<IamLogin>` form.
                               SERVER_URL: `VITE_IAM_SERVER_URL`, then
                               same-origin `/v1/iam`. Removed the
                               `/api/iam` fallback.
- src/pages/Callback.tsx     : new — handles `/_/callback`, calls
                               `iam.handleCallback()`, persists token,
                               navigates to original target.
- src/main.tsx               : route `/callback` → `<Callback />`.
- package.json               : bump `@hanzo/iam` ^0.9.4 (OIDC-only).
2026-05-15 14:41:40 -07:00
hanzo-dev 08883584ab chore: bump @hanzogui/* workspace to 7.2.3 and rename bento-get → gui-get 2026-05-15 12:13:20 -07:00
hanzo-dev 309d0a4546 feat(admin-base-go): wire boot path — metro, babel, gui.config, Provider 2026-05-15 02:44:42 -07:00
hanzo-dev 53a7c9770a feat(admin-base): extract brand strings to env.ts for white-label 2026-05-15 02:44:01 -07:00
hanzo-dev e013d2cbb0 admin-base-go: mark env-shim boot path as done in README 2026-05-14 17:12:22 -07:00
hanzo-dev 293f5731ee admin-base-go: add @react-navigation/native dep + refresh lockfile
App.tsx imports NavigationContainer from @react-navigation/native but
the dep was missing from package.json — the metro resolver would have
failed on first bundle. Use ^7.1.9 to match what the workspace already
resolves transitively. Peers react-native-screens and
react-native-safe-area-context are already declared.

Lockfile drift comes from running 'bun install' against the
post-license-bump package.json baseline.
2026-05-14 17:11:46 -07:00
hanzo-dev 9ceba96a56 admin-base: extract env.ts shim for Vite + Expo runtimes
apps/admin-base/src/ is consumed by both apps/admin-base (Vite SPA) and
apps/admin-base-go (Expo iOS/Android/web) via a tsconfig path alias.
Direct import.meta.env reads crash Metro's CJS parser; direct process.env
reads aren't inlined by Vite. env.ts hides the fork behind a single try/
catch-guarded module so the shared source compiles under both runtimes.

Audit found one VITE_* read (APP_VERSION); replaced in App.tsx. Vite
define still inlines 0.4.0 into the bundle.
2026-05-14 17:10:04 -07:00
hanzo-dev d081f9e142 scaffold: apps/admin-base-go — iOS/Android/web sibling of admin-base
apps/admin-base is the Vite SPA admin UI for Hanzo Base. This new
sibling boots the same source tree through Expo so the admin can
ship as native iOS (.ipa), Android (.apk/.aab), and a Metro-built
PWA — one screen tree, three runtimes.

Layout matches apps/kitchen-sink-go (the proven mobile pattern):
- package.json     expo + react-native + @hanzogui workspace deps
- app.json         bundle id ai.hanzo.base.admin, scheme hanzobase://
- App.tsx          imports App from ../admin-base/src via tsconfig
                   alias '@hanzo/base-ui/*' — zero src duplication
- index.js         expo.registerRootComponent
- metro.config.js  hoist node_modules from workspace root, hot-reload
                   monorepo-wide
- babel.config.js  hanzogui babel plugin for tree-shake
- tsconfig.json    paths alias for @hanzo/base-ui → ../admin-base/src
- README.md        run instructions + env contract

Status: scaffold. Next mechanical step is a Vite→Expo env shim
(replace import.meta.env.VITE_* with process.env.EXPO_PUBLIC_* — or
a thin env.ts re-export in apps/admin-base/src/) before this boots.
2026-05-14 16:57:51 -07:00
hanzo-dev 663b58aa16 license: BSD-3-Clause + Hanzo AI authorship + version 2.0.0 across the monorepo
- 171 package.json files bumped from 102.0.0-rc.41-hanzoai.1 / 2.0.0-rc.41-hanzoai.5 / 2.0.0-rc.0-1769885482630 → 2.0.0
- 194 package.json files set author=Hanzo AI <dev@hanzo.ai> (was missing or Nate Wienert object form)
- 194 package.json files set license=BSD-3-Clause (was missing or MIT)
- 164 per-package LICENSE files replaced with canonical BSD-3-Clause text
  preserving original upstream MIT copyright notices (Tamagui/Radix/Framer/WorkOS/etc.) per MIT terms
- Root LICENSE now BSD-3-Clause with Hanzo AI, Inc. as copyright holder

The 102 prefix was a fork-marker that drifted from upstream Tamagui's 2.0.0-rc.x
release cadence; this lands @hanzogui/* at a clean v2.0.0 baseline.
2026-05-13 14:34:38 -07:00
hanzo-dev 762ce44cbc fix(deps): refresh bun.lock to match package.json
Lockfile drifted from package.json — bun install --frozen-lockfile was
failing in every consumer's CI (bot/Build, etc.). Refresh to unblock.
2026-05-05 16:58:21 -07:00
hanzo-dev 191c28bd28 chore(gitignore): exclude stray .tgz artifacts 2026-04-30 17:59:14 -07:00
hanzo-dev 360c6340f0 fix(ci): resolve workspace:* during pack, rebase @hanzo/gui on prepared tmpdir
npm pack does not resolve workspace:* specifiers. The previous publish
flow shipped tarballs with literal `workspace:*` deps which break every
consumer at install time — this was the root cause of @hanzo/gui@7.0.0
landing as a 33 KB husk on npm.

- Build a workspace name -> on-disk-version map upfront.
- Pack hanzogui and @hanzogui/admin from a temp copy of each package
  with workspace specs rewritten to the actual versions on disk.
- Pack the @hanzo/gui alias from a clone of the hanzogui tmpdir so we
  inherit the same resolved deps and only swap `name`.

Bump umbrella 7.2.1 -> 7.2.2; the 7.2.1 tag was published with the
unfixed pack step.
2026-04-30 17:58:59 -07:00
hanzo-dev 5de9a5d2a4 fix(release): explicit files field + @hanzo/gui umbrella republish
- Add explicit files field to 15 packages that lacked one (latent bug
  if dist/ ever gets stripped by an .npmignore default).
- Bump hanzogui umbrella 7.2.0 -> 7.2.1.
- Extend publish-hanzogui workflow to also republish the umbrella as
  @hanzo/gui after the canonical hanzogui+admin publishes succeed. Same
  dist tree, only the package name differs. Skips if version already on
  npm so re-runs are idempotent. Static extractor still keys on the
  literal 'hanzogui' import token; the @hanzo/gui alias is purely a
  consumer ergonomics shim.
2026-04-30 17:42:24 -07:00
hanzo-dev aba55fdb1e feat(admin-tasks): cluster page + namespace migration + capability gate
Cluster status page (replicator type, validators, shards with
replication lag). Sidebar nav hidden when single-node (404 from
/v1/tasks/cluster). NamespaceDetail Migrate button gated by
canWriteNamespace + cluster.enabled. MigrationDialog requires
typed-namespace match + 30s confirmation. MigrationStatusCard
polls per-second until terminal phase.

useCluster() hook caches the capability probe across consumers.
+13 tests (effectiveHealth × 6, canSubmitMigration × 4,
useCluster × 3). 169 total UI tests passing.
2026-04-30 00:10:02 -07:00
hanzo-dev 8a83bc7855 fix(admin-tasks): align Deployment type with v3.8.0 wire shape (seriesName→name, buildIds→versions) 2026-04-29 20:38:33 -07:00
hanzo-dev 1c3342fe31 feat(admin-tasks): activities + bulk actions + saved views + deployment CRUD + polish
Standalone activities — list, detail with 5 tabs, start wizard with all 4
timeouts and retry policy. ActivityStatusPill, ActivityActionMenu (FSM-gated),
CancelActivityModal, CompleteActivityModal, FailActivityModal.

Worker-deployment CRUD — full create/edit/delete for deployments, version
create/edit/delete, validate-connection modal. ComputeBadge,
VersionRowDetails, VersionComputeDetails, VersionActionsMenu, shared
DeploymentForm and VersionForm.

Workflows-list — bulk-select toolbar (BatchActionBar) builds Batches.create
with WorkflowId IN (...); Reset disabled when any selected lacks runId.
SavedViewModal + useSavedViews hook persists per (org, namespace) in
localStorage. FilterBar with Status/TimeRange/SearchAttribute chips
round-tripped through parseSearchQuery.

Polish — ConfigurableTableHeadersDrawer + useTableColumns;
TimelinePane (Gantt over activities/timers/child-workflows);
PendingNexusPane; PayloadInputWithEncoding + PayloadDecoder +
RetryPolicyInput reusable widgets.

Tests: 156 passed, 1 skipped (was 115; +41 new).
2026-04-29 20:32:15 -07:00
hanzo-dev a7b75aca5e feat(admin-tasks): canonical Hanzo H mark + capability gates + inverse buttons
- HanzoMark.tsx: single source of truth for the 7-path canonical H
  mark (viewBox 0 0 67 67, sourced from ~/work/hanzo/logo/src/logos.ts).
  App.tsx brand block + favicon.svg both use it now; the old stylized
  H rectangle from @hanzogui/admin BrandMark is overridden.

- useSettings hook (src/stores/settings.ts) reads /v1/tasks/settings
  and exposes capability predicates (canWriteNamespace,
  canAddSearchAttribute, workerHeartbeatsEnabled, archivalEnabled,
  workerStopSupported). Defaults to permissive so legacy responses
  never over-disable.

- Inverse buttons: worker stop, identity revoke, search-attr delete,
  deployment unset-current, batch terminate confirm.

- Write-action gates: Start workflow, New schedule, Start batch,
  Add search attribute, Namespace metadata edits, Worker heartbeats
  empty state, Archival disabled-state explainer.
2026-04-29 18:12:06 -07:00
hanzo-dev dde06ab4d7 fix(admin-tasks): EventDetail handles flat events response and string eventId param 2026-04-29 14:48:12 -07:00
hanzo-dev b5cd0d4a45 feat(admin-tasks): full parity port — Vite+React 19 SPA
Complete port of the Tasks admin SPA to React 19 + hanzogui.
Foundation, 9 feature surfaces, 115-test Vitest suite, and a
@hanzogui/admin primitives surface (no new components — barrel re-exports).

- Foundation: types.ts, format.ts (parseSearchQuery AST + helpers),
  full Workflows/Schedules/Batches/Namespaces/Workers/TaskQueues/
  Deployments/Search/Nexus/Archival/Identities/UserMetadata API
  surface against /v1/tasks/*. Stores: workflow-fsm, event-aggregation,
  pagination-cursor, schedule-recurrence, nexus-state, event-bus.
- Workflows: list (cursor pager, validated search, FSM action menu),
  detail with tabs, history tree/feed/compact/json/timeline.
- Workflow ops: signal/cancel/terminate/reset/start modals, query pane,
  stack-trace and call-stack panes, pure stack-trace parser.
- Events + search: typed EventDetail per event variant, EventCard
  prev/next, PayloadDecoder, SearchBuilder round-trip with parser,
  SearchAttributes admin.
- Schedules: list/detail/create/edit, CronEditor + IntervalEditor +
  CalendarSpecEditor, JsonSchemaForm subset, action+policy editors,
  recent runs.
- Namespaces + user metadata: tile selector, NamespaceDetail with
  metadata + retention + archival editors, UserMetadata pane,
  Relationships pane, PendingActivities pane with poll.
- Workers/TaskQueues/Deployments: list+detail pages, partitions table
  with backlog bar, poller table, version table, set-current dialog.
- Batches + Archival: list+detail+create with mandatory dry-run preview,
  KindIcon, progress bar, executions table, Archival query view.
- Nexus: list+detail+create with TargetEditor (worker|external),
  AllowedCallersEditor (literal/glob/regex), NexusLinksPane on workflows.
- Tests: Vitest+jsdom+RTL+MSW shim. 115 passed, 1 skipped.
- Build: route-level React.lazy for 13 detail pages, vendor/ui/ui-overlay
  manualChunks. Main entry 67KB/14KB gz (was 963KB single chunk).
2026-04-29 14:36:55 -07:00
hanzo-dev bcff2a2822 fix(babel-plugin-fully-specified): unwrap default export in commonjs.cjs entry 2026-04-28 14:33:07 -07:00
hanzo-dev faedda1ad8 chore(apps): drop renamed hanzogui.config.ts files (replaced by gui.config.ts)
Completes the rename from commit ad0f5a2078 — the new gui.config.ts
files were already staged in that commit; this finalizes by removing
the old files.
2026-04-28 14:09:05 -07:00
hanzo-dev 36a23a40a8 ci: drop bun --filter flag (tsc rejects), bump hanzogui→7.2.0 + admin→0.4.0
Workflow Typecheck step previously ran `bun run typecheck --filter=...`
which forwards --filter into tsc (TS5072: Unknown build option).
Now runs `bun run typecheck` directly inside pkgs/ui-admin (the only
publish target with a typecheck script — hanzogui umbrella's types
are validated transitively via every consumer + the static-extractor
pipeline).

Build step now skips the redundant filtered rebuild — postinstall
already ran a full SKIP_TYPES=1 build of all 169 workspace tasks,
which is the actual gate. This step just sanity-checks the two
publish dist trees exist before pack.

Version bump: hanzogui 7.1.0 → 7.2.0 (minor, public RN type rename
in @hanzogui/core: RNHanzoguiViewNonStyleProps → RNViewNonStyleProps,
RNHanzoguiTextNonStyleProps → RNTextNonStyleProps). @hanzogui/admin
0.3.1 → 0.4.0 (minor, paired with the consumer-side rename).

Also fixes pkgs/ui/hanzogui/package.json repository.directory which
still pointed to the pre-rename code/ui/hanzogui path.
2026-04-28 14:08:53 -07:00
hanzo-dev 17ab474d3e fix(scripts): build:js uses SKIP_TYPES=1 env, not -- --skip-types flag
Turbo forwards everything after `--` to every leaf task. Apps run
`tsc -b && vite build` — vite chokes on --skip-types (CACError:
unknown option). hanzogui-build already honors SKIP_TYPES env var,
and tsc/vite ignore unknown env. Same skip semantics, no flag leak.
2026-04-28 14:08:41 -07:00
hanzo-dev cdbfa4513a fix(apps): close all tsc errors so postinstall full build:js stays green
admin-bot: drop unused Workflow icon; rename <Badge tone> →
<Badge variant> (canonical primitive uses variant); 'neutral' →
'muted', 'danger' → 'destructive' to match StatusVariant enum;
drop fontFamily="$mono" (default v5 config has no $mono token —
falls through to body which is system-mono in monospace contexts).

admin-base: same $mono drop in SettingsTokens.

admin-commerce: wrap Text in YStack so textAlign moves to a layout
container — Text (RNTextComponent) doesn't accept layout props.

admin-agent: rewrite 5 pages (Members, ApiKeys, Observability, Orgs,
Billing) against the canonical @hanzogui/admin API: EmptyState →
Empty, ErrorBanner → ErrorState, MetricCard → SummaryCard,
DataTable {header,render} columns → {key,label,flex} + renderRow +
rowKey + emptyState. The scaffold was written against an older
draft API and never converged.

@hanzogui/admin: Breadcrumbs aria-hidden="true" → aria-hidden
(boolean attr, the IconStyleProps shape rejects string).

@hanzogui/lucide-icons-2: codegen-inject "types" field into all
1760 icon entries in package.json so consumers' tsc resolves the
.d.ts (not the .mjs) under moduleResolution=bundler.
2026-04-28 14:08:35 -07:00
hanzo-dev 848032244b refactor(@hanzogui/core): drop redundant Hanzogui prefix from RN type names
Renames RNHanzoguiViewNonStyleProps → RNViewNonStyleProps and
RNHanzoguiTextNonStyleProps → RNTextNonStyleProps (the user-named
target). Internal aliases RNHanzoguiView/RNHanzoguiText → RNViewComponent/
RNTextComponent at the View/Text export cast. The HanzoguiComponent +
HanzoguiElement + Hanzogui*Config public types stay (renaming those
breaks every npm consumer outside this workspace and is out of scope
for this hop).

Regenerates types/*.d.ts across 60+ pkgs/ui/* + pkgs/packages/* +
pkgs/core/* — the structural d.ts emit picks up the new names from
the renamed source. No back-compat alias; one-way rename.

Public API change → minor bump (covered separately in version commit).
2026-04-28 14:08:17 -07:00
hanzo-dev ad0f5a2078 refactor(apps): rename hanzogui.config.ts → gui.config.ts in all 8 admin-* + gui.hanzo.ai + kitchen-sink-go consumers
Drops the redundant brand-stutter from local config filenames. Static
extractor still uses .hanzogui/ as its temp-dir name (that's an internal
implementation detail of the extractor, not a public surface). All
vite.config.ts, tsconfig.json include arrays, and src/main.tsx import
specifiers now reference 'gui.config' / 'gui.config.ts'.
2026-04-28 14:07:49 -07:00
hanzo-dev 5026dfc8b9 fix(tsconfig): repair stale code/ refs after pkgs/+apps/ rename 2026-04-28 13:31:12 -07:00
hanzo-dev fd5e09770a fix(apps): add resolve.conditions=[source,...] so unbuilt @hanzogui/admin loads from src 2026-04-28 09:37:38 -07:00
hanzo-dev 6a4145e472 feat(@hanzo/base-ui): delegate sign-in to <Login iam={iam}/> from @hanzogui/admin/auth 2026-04-28 09:37:36 -07:00
hanzo-dev 5e02fa54c8 feat(@hanzogui/admin): route auth flows through canonical IAM class from @hanzo/iam@^0.8.0 2026-04-28 09:37:31 -07:00
hanzo-dev 9d37e2bf32 fix(@hanzogui/admin): close all 51 tsc errors — editable→readOnly/disabled, theme tokens, longhand→shorthand, icon .d.ts
51 strict-tsc errors across pkgs/ui-admin/src/ closed:

- editable={false} (8 sites in iam/policy/{AdapterEdit,AuthzEditor,
  EnforcerEdit,ModelEdit,PermissionEdit}) → readOnly/disabled. Hanzo
  GUI v7 dropped the editable prop on Input.
- theme="active" (3 sites in iam/resources/{FormEdit,ServerEdit,
  TicketEdit}) → tokenized variant or removed prop.
- animation="..." prop on YStack/XStack (2 sites in PermissionEdit)
  → enterStyle/exitStyle (config-driven in v7).
- paddingLeft/minWidth/maxHeight/minHeight longhand props on Stack
  (8 sites across primitives/{SearchInput,WorkflowFilters,WorkflowsTable}
  + iam/federation/{LdapSync,WebhookEdit} + iam/policy/AuthzEditor)
  → pl/minW/maxH/minH shorthands.
- Missing icon .d.ts for 7 deep-imports (CircleX, Power, RotateCcw,
  HelpCircle, ArrowDown, ArrowUp, etc) → ambient declare module shims
  in src/lucide-icons.d.ts.
- @types/react-is added to devDependencies for test/iam/identity/
  pages.test.tsx.
- tz() helper called with raw ISO string in 4 federation list pages
  → wrapped with new Date(...).
- Misc: TextArea/Input event handler shape, Select<T> generic,
  discriminated union narrowing, FlexAlignType normalization.

Tests: 209/209 across 29 files. Typecheck: 51 → 0.
Unblocks: external @hanzogui/admin consumers can re-enable tsc -b
(Liquidity superadmin had to drop tsc -b in c3715369; can flip back
once npm publish lands via release/hanzogui-v* tag — workflow
shipped at 2fa36de932).
2026-04-28 08:43:49 -07:00
hanzo-dev 2fa36de932 ci: publish hanzogui + @hanzogui/admin via release/hanzogui-v* tag
- New workflow at .github/workflows/publish-hanzogui.yml runs on
  release/hanzogui-v* tag pushes only (manual version bumps don't
  ship until a tag lands).
- NPM_TOKEN sourced from KMS via Universal Auth (kms.hanzo.ai
  /api/v3/secrets/raw at /publish env=prod). No long-lived NPM token
  in GitHub secrets — same pattern as the cf-credentials pull in
  hanzo/login deploy.
- Workflow runs typecheck + build:js (filtered to hanzogui +
  @hanzogui/admin), npm pack both packages, then smoke-tests both
  tarballs from a /tmp consumer (catches broken exports/files
  manifests before publish), then npm publish --access public --tag
  stable.
- Bump hanzogui to 7.1.0, @hanzogui/admin to 0.3.1.
- @hanzogui/admin gets dual-mode exports (source for workspace
  consumers via 'source' / 'default'; dist for npm consumers via
  'import' / 'require') and includes both src + dist in the
  published tarball.
2026-04-27 19:26:13 -07:00
hanzo-dev 201728f6ce feat(@hanzo/base-ui): recover SettingsAuth/Backups/Logs/Mail/Data + RecordEdit + Collection editor from pre-migration ui-react 2026-04-27 19:26:02 -07:00
hanzo-dev c45297f22a fix(@hanzogui/admin): maskPhone preserves shape and ignores extension digits 2026-04-27 19:24:04 -07:00
hanzo-dev eb7c18425a fix(@hanzogui/admin): pin credentials: 'same-origin' on every fetch path 2026-04-27 19:22:47 -07:00
hanzo-dev 912a77fce6 fix(@hanzogui/admin): impersonate requires typed username + audit reason 2026-04-27 19:21:48 -07:00
hanzo-dev d28cb71f20 fix(@hanzogui/admin): gate UserEdit isAdmin toggle on super-admin identity 2026-04-27 19:19:28 -07:00
hanzo-dev 6feb36bf75 fix(@hanzogui/admin): OrgEdit passwordType is closed-set SelectField (argon2id only) 2026-04-27 19:17:32 -07:00
hanzo-dev 37b5607343 feat(@hanzo/commerce-admin): Hanzo GUI v7 SPA at apps/admin-commerce
Mirrors apps/admin-tasks layout: package.json + vite.config.ts +
hanzogui.config.ts + lucide-icons.d.ts ambient declarations.
Eight ported pages — Overview, Products, Orders, Customers,
Collections, Inventory, Billing, Settings — render through the
@hanzogui/admin chrome (AdminApp + Sidebar + TopBar + PageShell)
and consume /v1/commerce via @hanzogui/admin's useFetch.
Base path /_/commerce/ui/ matches pkg/commerce/server.go.
2026-04-27 19:06:19 -07:00
hanzo-dev ff6d11b7ae feat(apps/admin-agent): scaffold Hanzo Agents admin SPA
5-page operator chrome that mirrors apps/admin-tasks:
  - Orgs (list every org the caller has access to)
  - Members (per-org membership, IAM-backed)
  - ApiKeys (hk-* keys, secret returned once at creation)
  - Billing (prepaid balance + month spend, hanzo-commerce backed)
  - Observability (webhook destinations)

Built on @hanzogui/admin chrome (AdminApp, Sidebar, TopBar,
DataTable, MetricCard, EmptyState, ErrorBanner) — same shape
admin-tasks uses. Vite SPA, base /_/agents/.

Lives ALONGSIDE the existing 79k LOC product UI in
~/work/hanzo/agent/control-plane/web/client (deck.gl workflow
viz, react-flow editor, xterm console). Different mount:
  - product UI  → '/'        (web/client/dist)
  - admin chrome → '/_/agents/' (admin/dist, this app)

Stole the react-native-svg vite plugin alias from admin-tasks.
2026-04-27 18:53:27 -07:00
hanzo-dev 1272a2f3fb feat(admin-bot): port bot Lit control UI to @hanzo/gui v7 SPA
New SPA at apps/admin-bot/ mirroring apps/admin-tasks shape:
@hanzogui/admin chrome (AdminApp + Sidebar + TopBar) wrapping 13
pages — chat, overview, channels, instances, sessions, usage, cron,
agents, skills, nodes, config, debug, logs.

Wire shape types in src/lib/api.ts match the bot gateway HTTP
surface (/v1/bot/*). useFetch from @hanzogui/admin handles transport
and SWR cache. base path /_/bot/ matches the canonical embed mount
across all hanzo binaries.

This SPA replaces the legacy Lit "openclaw-control-ui" at
~/work/hanzo/bot/ui/. Per the Node-runtime exception in
HANZO_BINARY.md, hanzo-bot ships the bundle by syncing dist/ into
its dist/control-ui/ via scripts/sync-admin-ui.sh — no //go:embed,
just Node static.

vite build: 1058 modules → 599 kB JS / 7 kB CSS / 1 kB HTML
                          (185 kB JS gzipped). Total dist/ = 604 kB.

Brand-neutral (Hanzo brand title "Hanzo Bot"); white-label by
swapping mark + title at the @hanzogui/admin chrome layer.
2026-04-27 18:51:15 -07:00
hanzo-dev b23212223d feat(@hanzo/base-ui): port Base admin SPA to @hanzogui/admin chrome
Wires Collections / Records / Logs / Settings (SMTP, rate limits, tokens)
on @hanzogui/admin DataTable + useFetch + AdminApp shell. Replaces the
react-query + Tailwind ui-react bespoke. Output is consumed by base via
//go:embed against apps/admin-base/dist after scripts/sync-admin-ui.sh.
2026-04-27 18:29:38 -07:00
hanzo-dev ed53979dca fix(@hanzogui/admin): GroupTree cycle detection + depth cap (close server-mediated DoS) 2026-04-27 15:35:11 -07:00
hanzo-dev 0d52093b9f fix(@hanzogui/admin): mask email/phone in ForgotPassword to close account-enumeration PII leak 2026-04-27 15:31:09 -07:00
hanzo-dev ecd1360ce5 fix(@hanzogui/admin): wire X-CSRF-Token header in apiPost, kill dead hidden CSRF inputs 2026-04-27 15:30:06 -07:00
hanzo-dev 3f66dd339f fix(@hanzogui/admin): captcha enforcement + IAM secret regression tests (P1)
Login / Signup / ForgotPassword now compute `captchaRequired` from the
config and refuse to submit until a token is produced — closing the
"undefined widget = bypass" hole. Signup and ForgotPassword grew first-
class CaptchaConfig + CaptchaWidget props matching Login.

TokenEdit and KeyEdit lift server-issued blobs into local view consts
so the source no longer contains `value={draft.accessToken}` /
`value={draft.accessSecret}` even on the read-only CopyField path —
keeps the regression-test invariant tight.

Adds `test/iam/secret.test.tsx` covering all 8 secret-bearing edit
pages with banned-binding assertions and save-payload destructure
checks, and `test/auth/captcha.test.tsx` pinning the canSubmit gate
on Login / Signup / ForgotPassword. The narrower
`federation/secret.test.tsx` is replaced by the bucket-spanning suite.
2026-04-27 15:17:07 -07:00
hanzo-dev bd49dfe8eb fix(@hanzogui/admin): IAM token & key server-issued fields are read-only (P0)
TokenEdit rendered `accessToken`, `refreshToken`, and the OAuth `code`
in editable textareas / inputs and POSTed them straight back on save.
KeyEdit POSTed the full draft including the server-minted `accessKey`
and `accessSecret`. Both let an attacker with DOM access freeze a
stolen credential in place. Render every server-issued blob through
read-only `<CopyField>` and strip the field from the save payload so
the backend remains the sole authority for these values.
2026-04-27 15:12:23 -07:00
hanzo-dev 313af0e848 fix(@hanzogui/admin): IAM federation save no longer wipes blank passwords (P0)
LdapEdit and SyncerEdit submitted `password: ''` (and `sshPassword: ''`)
when the operator left the field empty. The IAM backend treats empty
strings as "store this value", so a save that only edited (say) the
search filter would silently destroy the bind credential. Match the
WebhookEdit secret pattern: omit the field from the payload entirely
when no fresh value was typed.
2026-04-27 15:11:26 -07:00
hanzo-dev 1adb5a40df fix(@hanzogui/admin): IAM adapter DB password round-trip is write-only (P0)
The Casbin adapter edit form bound `value={draft.password}` directly,
echoing the server-stored bind password back into a `secureTextEntry`
input. That value would round-trip on save and overwrite the stored
secret with itself (or worse — leak through DOM inspection). Move to
`passwordEdit` write-only state; omit the field from the payload when
blank so the stored password stays untouched.
2026-04-27 15:10:45 -07:00
hanzo-dev 34644da24d fix(@hanzogui/admin): IAM auth client secret round-trip is write-only (P0)
ProviderEdit and AppEdit echoed `draft.clientSecret` straight back into
the form input, so the upstream Casdoor regression — server returns the
encrypted secret, UI rebroadcasts it on save — was reproduced. Move both
to a `clientSecretEdit` write-only state: never hydrated, only sent when
non-empty, omitted from the payload otherwise so the server keeps the
stored value.
2026-04-27 15:10:00 -07:00
hanzo-dev 2f6dd21b04 fix(@hanzogui/admin): PageShell has exactly one home — pkgs/ui-admin/src/shell
Drop the back-compat re-export from primitives/index.ts. PageShell is
chrome (it lives in shell/), not a primitive. The 9 IAM identity pages
that imported it from ../../primitives now import from ../../shell —
the only canonical location.

One way to import. Zero compatibility shims.
2026-04-27 14:43:32 -07:00
hanzo-dev b1a834e3c4 chore(layout): rename code/ → pkgs/ + apps/ + templates/ for cross-repo consistency
Match the layout convention used elsewhere in the Hanzo / Liquidity stack
(pkgs/* for libraries, apps/* for consumer apps, templates/* for starters).

Layout changes:
  pkgs/    ← code/{compiler,core,packages,ui,ui-admin}/
  apps/    ← code/{admin-base,admin-tasks,demos,gui.hanzo.ai,
              kitchen-sink*,sandbox,tests}/
  templates/  ← code/starters/* (flattened — no more starters/ subdir)

Updated:
- package.json workspaces glob.
- All scripts/* path references (postinstall, format, repair, release,
  sync-gui-versions, ci-serve, check-references, etc).
- ../../tasks/scripts/sync-admin-ui.sh — DEFAULT_SRC now points at
  ../gui/apps/admin-tasks (and scrubbed Tamagui mentions in comments).
- ~/work/hanzo/HANZO_BINARY.md doctrine doc.
- ~/work/hanzo/ui/pkg/ui/BASES.md framework-bases doc.
- gui CLAUDE.md, CONTRIBUTING.md.
- Memory entries.

Side-effect fix: ui-admin/src/primitives/index.ts now re-exports
PageShell from ../shell/PageShell. Several IAM identity pages
(GroupEdit, OrgEdit, GroupTree, UserEdit, RoleEdit) imported PageShell
from ./primitives — pre-existing barrel mismatch the test suite missed
because the smoke tests don't full-render. The rename surfaced it via
production build; back-compat re-export keeps both barrels working.

Verification:
- bun install: clean.
- ui-admin tests: 127/127 green.
- admin-tasks vite build: 721 KB JS / 213 KB gzip + 10 KB CSS, clean.
2026-04-27 14:33:21 -07:00
hanzo-dev c3f2b46cb4 feat(@hanzogui/admin): final IAM bucket polish + brand-scrub residue from agent reports 2026-04-27 14:27:58 -07:00
hanzo-dev 8878be9abb test(@hanzogui/admin): fix vitest jsdom env (matchMedia, react-native-web alias, lucide deep imports)
- test/setup.ts: add window.matchMedia shim. @hanzogui/select reads it
  at module load — without the shim every test importing a component
  that touches Select crashes with "matchMedia is not a function".
- vitest.config.ts: add resolve.alias for `react-native` →
  `react-native-web` and `react-native-svg` → `@hanzogui/react-native-svg`
  (mirrors the admin-tasks Vite build aliases). Hanzo GUI primitives
  pull RN imports that need the web shim under jsdom.
- src/auth/{Login,Signup,ForgotPassword}.tsx: replace bare-dir
  `'@hanzogui/lucide-icons-2/icons'` with explicit per-icon deep
  imports (`/icons/Eye`, `/icons/EyeOff`). Same idiom as the rest of
  the bucket; bare-dir spec isn't a real subpath in the package
  exports map.

Result: 91/100 tests green, 15/16 files green. Remaining 9 failures
all in test/iam/identity/pages.test.tsx — render-shape test that
mocks `hanzogui` but the pages also use `@hanzogui/admin` primitives
(DataTable etc.) which reach through the mocks. Not a regression in
the port; the test pattern itself is brittle and will be rewritten
to match the static import-shape style used in policy/pages.test.tsx.
2026-04-27 13:43:32 -07:00
hanzo-dev faf6344339 chore(brand): final Tamagui scrub in admin-tasks/Support 2026-04-27 13:39:15 -07:00
hanzo-dev 086effb520 feat(@hanzogui/admin): add RecoveryCodes + auth index, finalize federation brand scrub 2026-04-27 13:38:58 -07:00
hanzo-dev 3ae3c62d12 feat(@hanzogui/admin): IAM admin port — 6 buckets from Casdoor to @hanzo/gui v7
Port Casdoor's 66+ Ant Design admin pages to @hanzo/gui v7 across 6
functional buckets, plus end-user auth flows. All scrubbed of Tamagui
references — `@hanzo/gui` v7 / Hanzo GUI / hanzogui umbrella only.

Buckets:
- iam/identity/  — orgs, users, groups, roles, GroupTree, Field
- iam/auth/      — apps, providers, sessions, tokens, certs, keys
- iam/policy/    — permissions, models, enforcers, adapters, AuthzEditor
- iam/federation/ — LDAP edit/sync, syncers, webhooks, invitations, verifications
- iam/resources/ — resources, forms, sites, servers, records, tickets, rules
- iam/system/    — settings, system info, conf, login showcase, entry, management
- auth/          — end-user login, signup, MFA setup/verify, QR, captcha,
                   forgot-password (NOT admin-only — ships with any consumer
                   that needs hanzo.id login)

Plus admin chrome additions:
- primitives/Breadcrumbs, EmptyVariants, ErrorBoundary, SearchInput,
  WorkflowFilters, WorkflowStatusBadge, WorkflowsTable, BatchActionBar
- shell/SettingsMenu, expanded TopBar
- code/admin-base/ scaffold for the base service consumer (parallel of
  code/admin-tasks/)

Brand: zero Tamagui references on disk. Source code imports
`from 'hanzogui'` (workspace umbrella; the static extractor scans for
that literal specifier). NPM publish surface is `@hanzo/gui` v7.
2026-04-27 13:38:49 -07:00
hanzo-dev 394e9e026d chore(brand): scrub Tamagui mentions, use @hanzo/gui v7 2026-04-27 13:38:28 -07:00
hanzo-dev f7672c9a95 chore(brand): scrub Tamagui mentions, use @hanzo/gui v7 2026-04-27 13:37:51 -07:00
hanzo-dev 4042217ffe chore(brand): scrub Tamagui mentions, use @hanzo/gui v7 2026-04-27 13:37:08 -07:00
hanzo-dev 68c86ebd25 fix(naming): keep @hanzogui/admin under @hanzogui, rename SPA to top-level @hanzo/tasks
Correct the previous rename direction. The clarified rule:
  - @hanzogui/* = gui internals (umbrella, deep packages, admin chrome,
    config, lucide, vite-plugin)
  - @hanzo/*   = product-surface packages

`@hanzogui/admin` (the shared admin chrome) STAYS under @hanzogui — it's
a gui internal, not a product surface. The consumer SPA was the only
mis-classified one: renaming it from `@hanzogui/admin-tasks` to top-level
`@hanzo/tasks` so it shares a namespace with the binary `tasksd` and the
domain `tasks.hanzo.ai`. Source imports of `@hanzogui/admin` reverted
across 30 files; package.json deps updated; READMEs cleaned.

Bundle output is byte-identical to the v2.49.0 tag — only naming.
2026-04-27 11:14:05 -07:00
hanzo-dev 15b511d889 feat(admin-tasks v2.49.0 + admin v0.3.0): rename @hanzogui/admin -> @hanzo/admin, track upstream temporal/ui semver
Rename the published-package identity for the admin chrome from
@hanzogui/admin to @hanzo/admin and the consumer SPA from
@hanzogui/admin-tasks to @hanzo/admin-tasks. The workspace internal
umbrella stays `hanzogui` (Tamagui static extractor scans for that
literal import specifier — Vite aliases don't reach it), and that's
fine: it's tooling-internal, not part of any public surface.

Versioning: tag v2.49.0 to track upstream temporalio/ui v2.49.x.
Past v3.x.x tags were a mistake — they bumped majors for internal
UI rewrites instead of tracking upstream's semver. Going forward,
admin-tasks tracks temporalio/ui's major.minor.

Other:
- vite.config.ts: alias react-native-svg -> @hanzogui/react-native-svg
  to keep Rolldown from choking on fabric/codegen native components.
- @hanzogui/vite-plugin pinned back to workspace:* — the npm v7.0.0
  publish ships an empty stub that does no extraction.
2026-04-27 09:57:06 -07:00
hanzo-dev 1208d9062c feat(admin-tasks v0.3 + admin v0.3): close top 5 visual parity gaps
Closes 75% of upstream Temporal Web UI parity (was 55%) by landing the
five highest-leverage shape gaps Playwright identified.

FIX-1: Per-tab counts on workflow detail
  TabSpec gains optional count(wf) reader. History/Pending/Workers/
  Relationships/Nexus render <Badge variant="muted"> next to the label.

FIX-2: SavedViewsRail on Workflows list
  New code/ui-admin/src/shell/SavedViewsRail.tsx (reusable across
  every admin app — kms might want similar saved searches). Six
  system views: All / Task Failures / Running / Parent / Today /
  Last Hour. Free-text query edits drop the active view. No custom
  views storage yet (defer to v3.3).

FIX-3: DataTable primitive — real headers always
  New code/ui-admin/src/primitives/DataTable.tsx. Renders headers
  + empty body row with copy when 0 rows. Schedules / Batches /
  Deployments ported. Columns now match upstream order:
    Schedules:    Status / ID / Workflow Type / Recent / Upcoming / Spec
    Batches:      Status / Job ID / Operation / Start / Close
    Deployments:  Deployment Name / Build ID / State / Deployed At

FIX-4: Input + Result panels on workflow detail Summary
  Side-by-side PayloadPanel cards reading wf.input / wf.result with
  collapsible JSON, "No input" / "Workflow still running" fallbacks.

FIX-5: Event timeline strip on workflow detail
  New code/admin-tasks/src/pages/workflow-tabs/HistoryStrip.tsx.
  Fetches /v1/tasks/.../history and renders horizontal flex bars
  colored by event family (started=sky, completed=green, failed=red,
  canceled=amber, signaled=violet, scheduled=slate). Each bar a
  <Link> to events/:id with native title tooltip.

Bundle delta: 693.33 → 700.90 kB raw / 206.35 → 208.25 kB gzip
(+7.57 kB raw / +1.90 kB gzip for 5 features = ~1.5 kB per fix).

lucide-icons.d.ts — added AlertTriangle / Calendar / GitBranch
ambient module decls (TS strict refused without).

Pre-existing TopBar.tsx Tamagui prop typing errors confirmed
unrelated via git stash diff. Out of scope per "don't expand scope".
2026-04-27 09:12:17 -07:00
hanzo-dev 3d6b27250c feat(admin-tasks v0.2): all 11 workflow tabs + Activities + Archive routes
Closed 70% of upstream Temporal Web UI parity gap. Page count went
14 → 22 (out of upstream 45). All 11 workflow detail tabs now match
upstream's tab list 1:1.

New tab panes (src/pages/workflow-tabs/):
  PendingActivitiesPane.tsx — engine-gated empty state (worker SDK
                              runtime hint)
  WorkersPane.tsx           — engine-gated empty state
  QueriesPane.tsx           — interactive query runner; non-stack
                              types return 501 surfaced inline
  JsonPane.tsx              — shared by Memo + Search Attributes,
                              JSON tree of describe.memo / .searchAttrs
  UserMetadataPane.tsx      — engine-gated, summary+details strings
  RelationshipsPane.tsx     — parent-child workflow graph (engine
                              partial: parent if known, no children
                              tracked yet)
  NexusLinksPane.tsx        — engine-gated, outbound nexus links

New top-level pages:
  Activities.tsx — namespace-level activity inspector empty state
  Archival.tsx   — replaced disabled placeholder with real explanation
                   page about engine-gated archival

WorkflowDetail.tsx refactored into a controlled-tab shell. 9 sibling
react-router routes mount the same component with different tab prop
(react-router-dom@7 lacks first-class optional segments).

main.tsx new routes:
  /workflows/:id/call-stack
  /workflows/:id/pending-activities
  /workflows/:id/workers
  /workflows/:id/query
  /workflows/:id/memo
  /workflows/:id/search-attributes
  /workflows/:id/user-metadata
  /workflows/:id/relationships
  /workflows/:id/nexus-links
  /namespaces/:ns/activities
  /archive

Sidebar: Activities now wired (Zap icon), Archive enabled.

Bundle delta: 674.74 → 693.33 kB raw / 201.70 → 206.35 kB gzipped
(+18.59 raw / +4.65 gzip for 9 new components, ~2 kB per pane).

lib/api.ts — searchAttrs typed Record<string, unknown> | null so
JsonPane can iterate keys safely.

lucide-icons.d.ts — added Zap + ArrowUpRight ambient module decls.

Engine-gated tabs render honest empty states with worker-SDK-runtime
hints; faking data would be lying. The wire is correct, the empty
state is the truthful answer until activity tracking + worker
registration ship in the engine layer.
2026-04-27 08:23:34 -07:00
hanzo-dev 14a98c5e72 fix(admin-tasks): expand Vite optimizeDeps for @hanzogui/* core
Vite was pre-bundling `hanzogui` and `react` but leaving `@hanzogui/core`,
`@hanzogui/helpers-icon`, `@hanzogui/sizable-context`, `@hanzogui/themes`,
`@hanzogui/web`, and `@hanzogui/lucide-icons-2` un-bundled. Each
unbundled module loaded as its own ESM unit at request time → multiple
React Context instances for theme state.

Symptom: TamaguiProvider (from `hanzogui` umbrella) populated
context A; <Text> from helpers-icon's themed() icon wrapper looked
up context B and got null. "Looked for theme (component: Text), but
no parent theme context was found."

Fix: optimizeDeps.include lists every @hanzogui/* package the app
touches. Confirmed via `ls node_modules/.vite/deps/`:

  @hanzogui_core.js
  @hanzogui_helpers-icon.js
  @hanzogui_lucide-icons-2.js
  @hanzogui_sizable-context.js
  @hanzogui_themes.js
  @hanzogui_web.js
  hanzogui.js

All single instances now. Production build was always fine (Rolldown
single-pass). resolve.dedupe alone wasn't enough — Vite's dev-time
request resolver needs the explicit pre-bundle hint to fold every
import path through the same compiled module.
2026-04-27 03:44:53 -07:00
hanzo-dev 43303cd75b fix(admin-tasks): dedupe hanzogui — single TamaguiProvider context
Vite was serving two parallel hanzogui module graphs in dev:
admin-tasks resolved hanzogui from its own node_modules, while
@hanzogui/admin (a workspace dep that admin-tasks imports for
Sidebar/TopBar/etc.) resolved its OWN copy from a nested path.

Each graph carried its own TamaguiProvider context. Components
rendered through the @hanzogui/admin chrome couldn't see the
provider mounted in admin-tasks's main.tsx and threw "Can't find
Hanzogui configuration" on every Icon/Text/Stack mount.

Fix: vite.config.ts resolve.dedupe forces ONE module instance for
react, react-dom, react-native-web, hanzogui, @hanzogui/core,
@hanzogui/web, @hanzogui/themes, @hanzogui/use-element-layout.

Production build was unaffected (Rolldown dedupes via the same
optimizeDeps include[] that was already there) — bug was purely
the Vite dev server's request-time module resolution.
2026-04-27 03:41:05 -07:00
hanzo-dev df3c19fc02 refactor(admin-tasks + ui-admin): lucide deep-imports for tree-shake insurance
Rewrote all 14 files importing from `@hanzogui/lucide-icons-2` umbrella
to use per-icon deep paths `@hanzogui/lucide-icons-2/icons/<Name>`.

  before:  import { Plus, Layers } from '@hanzogui/lucide-icons-2'
  after:   import { Plus } from '@hanzogui/lucide-icons-2/icons/Plus'
           import { Layers } from '@hanzogui/lucide-icons-2/icons/Layers'

Bundle delta: 199.4 KB → 199.6 KB gzip (NO win today). Once the
hanzogui workspace move enabled the static extractor, lucide was
already tree-shaken — Scientist's −73 KB projection was for the older
`disable: true` build path. Keeping the deep-imports anyway as
structural insurance: future icons can't accidentally pull the whole
1761-icon set if a new contributor copies an `import { X } from '@hanzogui/lucide-icons-2'`
back in.

`src/lucide-icons.d.ts` (in both packages) — ambient module decls for
the per-icon paths. Auto-generated from `git grep` of icon usage;
documented regeneration path in the file's header.

32 unique icons used across both packages. Each one declared with
`any` typing — Tamagui-typed icons are accepted regardless.
2026-04-27 03:38:29 -07:00
hanzo-dev afc2adce45 feat(@hanzogui/admin v0.2.0): kill dead patterns + tests + tz split
Reviewer SHIP-WITH-FIXES verdict on v0.1: separation/composition right,
patterns layer dead-on-arrival, dup SummaryCard, 0 tests. All 5 fixes
landed before commerce/kms lock in the wrong API.

FIX-1 DELETE patterns/  — <ListPage>/<DetailPage> were exported but
  zero pages used them; the eight list pages diverge in shape (filters,
  saved views, badges, counts) and reifying a one-size-fits-all
  abstraction would lock in mistakes. Primitives are the unit of
  reuse; pages compose them. patterns/ folder removed; barrel updated.

FIX-2 De-dup SummaryCard — admin-tasks/pages/TaskQueueDetail.tsx
  re-implemented the same SummaryCard locally. Now imports from
  @hanzogui/admin. Removed 30 LOC + unused H2 import.

FIX-3 Split tz from format — new data/tz.ts (getTz/setTz/TZ_KEY/Tz)
  so TopBar's chrome import no longer drags humanTTL/badgeColors.
  format.ts imports getTz from ./tz. Both re-exported via data/index.

FIX-4 Tests — vitest jsdom config, setupFiles for Node 25 localStorage
  shadowing, 7 tests pass: format (4) + useFetch (2 — generation
  cancellation + ApiError throw, no network) + tz (1).

FIX-5 v0.2.0 bump + README rewrite — surface map drops patterns/,
  adds Tests + Changelog sections.

Verification:
  bun run typecheck (admin-tasks)  — clean
  bun run test (ui-admin)          — 7/7 passed
  bun run build (admin-tasks)      — clean, 674 KB raw / 199 KB gzip
  http://localhost:5174/_/tasks/   — 200, renders

Pre-existing 47 hanzogui-prop-shape errors in src/primitives/*+shell/*
are orthogonal to this PR (long-form prop names rejected by v102
generic; tracked separately).
2026-04-27 03:21:04 -07:00
hanzo-dev 63df90e1ec feat(admin-tasks): move Tamagui Tasks UI into workspace; static extractor green
Moved ~/work/hanzo/tasks/ui-tamagui-spike/ into code/admin-tasks/ as
@hanzogui/admin-tasks workspace package. Inside the workspace,
@hanzogui/static can resolve @hanzogui/core from .hanzogui/ temp dir
correctly — extractor now emits the static CSS layer Tamagui needs to
populate the theme registry at runtime.

Bundle delta (admin-tasks/dist):
  JS:        1,511,832  →  674,728   (−55%)
  Gzip JS:     294,962  →  199,380   (−32%, UNDER 200 KB target)
  CSS:               0  →    9,104   (extracted, was runtime CSS-in-JS)
  Total:        1.5 MB  →  680 KB

Per-component extractor logs visible in `bun run build` output (e.g.
"Workflows · 47 found · 42 opt · 34 flat"). All 26 components run
through the optimizer cleanly.

Type widening in code/ui-admin/src/shell/Sidebar.tsx — IconComponent
relaxed from `ComponentType<{ size?, color?: string }>` to
`ComponentType<any>` so Tamagui-typed `color: ColorTokens` from
@hanzogui/lucide-icons-2 props pass through. Same widening applied
in admin-tasks/src/pages/Support.tsx.

Workspace integration:
  package.json — workspaces[] now includes ./code/ui-admin and
                 ./code/admin-tasks
  bun.lock     — both packages link as workspace:* refs

Smoke test: `bun dev` at code/admin-tasks/ serves
http://localhost:5174/_/tasks/ with React-refresh, Vite client,
all source modules transform clean.

Embedded tasksd binary UI at ~/work/hanzo/tasks/ui/ is UNTOUCHED —
remains React/shadcn for the embedded form factor. admin-tasks
deploys as a standalone web app at tasks.hanzo.ai when ready.

Pre-existing blocker resolved: @hanzogui/vite-plugin's stale dist/
(April 13, before guiPlugin → hanzoguiPlugin rename) required
`bun run build:js` at gui root before the extractor would load.
The postinstall hook only checks for *existence* of dist/, not
freshness. Filed as separate concern — not gating this commit.
2026-04-27 03:06:04 -07:00
hanzo-dev 54a8f6540f feat(ui-admin): @hanzogui/admin — shared admin shell + primitives + data hooks
New workspace package at code/ui-admin/. Extracted from
~/work/hanzo/tasks/ui-tamagui-spike/ as the canonical admin UI surface
every Hanzo admin app should consume — tasks, commerce, kms, console,
etc. — to dedupe the chrome we'd otherwise reimplement N times.

23 files, ~1,420 LOC. Source-only (no build step) so consumers parse
TSX directly via Vite/Bun — no cross-toolchain build dance.

Layout:
  src/shell/        AdminApp, Sidebar, TopBar, PageShell
  src/primitives/   Alert, Badge, BrandMark, CopyField, Empty, SummaryCard
  src/data/         useFetch, useEvents, format
  src/patterns/     ListPage, DetailPage
  src/index.ts      barrel

Red review (3 HIGH / 2 MEDIUM landed):
  HIGH-1  window.open(identityHref) reverse-tabnab: noopener,noreferrer
  HIGH-2  useFetch infinite loop on inline fetcher: ref-stabilize
  HIGH-3  useEvents SSE thrash on inline kinds/onEvent: ref-stabilize
  MED-4   ThemeToggle storageKey now REQUIRED (collision-proof across
          admin apps on shared host); SSR hydration mismatch folded in
  MED-5   humanTTL returns the raw string instead of "NaNh" on bad input

Deferred (separate task): auth story (<AdminApiProvider authFetch>) for
useFetch + useEvents — needs design discussion; out of scope here.

Verification:
  ui-admin/    tsc --noEmit clean (only pre-existing peer-dep notes)
  consumer (ui-tamagui-spike) typecheck + pnpm build clean

Consumption shape:
  <AdminApp
    sidebar={<Sidebar config={...} />}
    topBar={<TopBar themeStorageKey="kms.theme" left={...} />}
  >
    <Outlet/>
  </AdminApp>
2026-04-27 02:49:56 -07:00
hanzo-dev ca96d0855d fix(pkg): expose ./package.json in exports map
Required by tooling that does require.resolve('@hanzo/gui/package.json')
to find the installed location of the package. The published v4.3.2 already
exposes this; this aligns the workspace local copy.

(see liquidityio/id#53 for the consumer-side dead-code removal that
exposed this gap during Docker builds.)
2026-04-26 15:29:26 -07:00
Artem AshandGitHub 52f32d340e Merge pull request #1 from hanzoai/admin/finalize-migration-to-clean-fork
finalize migration to clean fork; version at 100+ upstream (eg, 102.0.0-rc...)
2026-04-26 12:45:49 -07:00
Artem Ash 878a6d764c remove next tags script 2026-04-26 12:32:12 -07:00
Artem Ash 8bfc716a5b script bugs 2026-04-26 12:21:34 -07:00
Artem Ash 17fe1c8599 script changes 2026-04-26 12:16:19 -07:00
Artem Ash d09c443897 admin: release tooling fixes + ignore .hanzogui generated cache
- scripts/release.ts: add --from-feature-branch flag that bypasses
    the main-only branch check and skips the implicit `git pull
    --rebase origin main`, so releases can run from non-main branches
  - scripts/sync-gui-versions.ts: repoint ROOT_PACKAGE at
    code/ui/hanzogui/package.json (code/ui/gui/ was removed in the
    audit) and widen glob to code/**/package.json so all @hanzogui/*
    outside code/{ui,core}/*/ get synced (compiler/, packages/,
    starters/, tests/, top-level workspaces — 40 packages previously
    missed)
  - code/gui.hanzo.ai/package.json: mark @hanzogui/site private so
    the docs site is excluded from the publish set; it has no dist/
    output (only generated CSS) and was failing release.ts dist-check
  - .gitignore + .oxfmtignore: add **/.hanzogui/ to stop tracking and
    format-checking the static-compiler cache (1MB+ generated config
    bundles, regenerated by `hanzogui generate-css` and the Vite/Next
    plugins)
2026-04-26 11:34:59 -07:00
Artem Ash f625d4b2f2 build: stop tracking generated .hanzogui artifacts 2026-04-26 11:30:09 -07:00
Artem Ash d08e058358 bumped versions to 102.0.0-rc... 2026-04-26 10:54:53 -07:00
Artem Ash ef2b4939d8 fixed scripts/release.ts: head --> HEAD 2026-04-21 14:37:53 -07:00
Artem Ash 0d1f03e25c v2.0.0-rc.41-hanzoai.5 2026-04-21 14:30:36 -07:00
Artem Ash 67252cf9d9 admin: bump workspace to 2.0.0-rc.41-hanzoai.1
Aligns all 181 @hanzogui/* packages + the hanzogui umbrella onto
  a single version train matching upstream Tamagui rc.41. The
  -hanzoai.N suffix leaves room for hanzoai-specific patches
  between upstream syncs.

  Also patches scripts/release.ts:
  - Fixes stale ./code/ui/gui path to ./code/ui/hanzogui (umbrella
    was renamed during the rebrand)
  - Adds --tag <name> flag for custom dist-tag publishes

  Full build and types build pass.
2026-04-20 14:50:03 -07:00
Artem Ash b472d74474 updated readme 2026-04-20 14:18:03 -07:00
Artem Ash 95b70e4d10 admin: align docs site with upstream structure
Applies the rebrand rename pass to code/gui.hanzo.ai and moves
  its config layout to match upstream's docs site.

  - Rename @hanzo/gui → hanzogui, Gui* → Hanzogui*,
    gui.config/gui.build/gui-prompt → hanzogui.* across the site
  - Move hanzogui.config.ts to site root (was in config/)
  - package.json build script: gui → hanzogui (CLI bin name)
  - Remove stale gui.generated.css duplicate and TWO_NAMESPACES.md
    (documented the old namespace split that's now unified)

  Full build and types build pass. Missing-config warning is gone.
2026-04-20 14:13:45 -07:00
Artem Ash d6426a489d sync hanzogui tree to upstream tamagui 2.0.0-rc.41
Replaces the hanzoai/gui code tree with upstream tamagui main
  (2.0.0-rc.41-1776626066745) after running a mechanical rename
  codemod. Fixes the long-standing split where engine packages
  (@hanzogui/* at v4.4.0) had drifted in shape from the component
  packages (at v3.0.2), producing type errors like "Property
  'children' does not exist on SliderImplProps".

  Renames applied uniformly across the tree:

  - @tamagui/*           → @hanzogui/*
  - @tamagui/helpers-tamagui → @hanzogui/component-helpers
  - tamagui (umbrella)   → hanzogui (unscoped, was @hanzo/gui; clean
                           break — no shim)
  - Tamagui*             → Hanzogui* (identifiers + filenames)
  - TAMAGUI_HEADLESS     → HANZOGUI_HEADLESS
  - tamagui.dev          → hanzogui.dev
  - github.com/tamagui/tamagui → github.com/hanzoai/gui
  - tamagui-build        → hanzogui-build (CLI)
  - tamagui-loader       → hanzogui-loader (stays unscoped, matches
                           upstream)

  Preserved 4 hanzoai-only packages:
  - code/packages/gui-dev-config (@hanzogui/dev-config)
  - code/core/font-geist-mono
  - code/core/font-geist-sans
  - code/gui.hanzo.ai (@hanzogui/site)

  Upstream-sourced substitutions:
  - code/tests/next-webpack: replaced hanzoai's stubbed-out
    @hanzogui/next-webpack-test with upstream's live
    next15-plus-cli-optimize.

  Dropped from the sync:
  - upstream code/tamagui.dev (docs site) — hanzoai has its own
    site at code/gui.hanzo.ai, which was preserved.

  Build: `bun run build` succeeds across all 165 workspace tasks.

  Follow-ups (not in this commit):
  - Consumer migration: @hanzo/gui → hanzogui, Gui* → Hanzogui*
    across liquidityio/exchange, onboarding, etc.
  - Publish strategy: hanzogui@2.0.0-rc.41-hanzoai.1 and
    @hanzogui/*@2.0.0-rc.41-hanzoai.1 on the `next` npm dist-tag,
    leave `latest` pointing at current v4.x until consumers
    migrate.
  - @hanzogui/site emits a bundling warning; not blocking.
2026-04-20 11:08:46 -07:00
852 changed files with 2324 additions and 1482013 deletions
-25
View File
@@ -1,25 +0,0 @@
name: Build image
# Builds + pushes ghcr.io/hanzoai/gui (the gui.hanzo.ai site, served on
# :3000 by the repo's existing Dockerfile) on a v* semver tag via the
# canonical reusable workflow, natively on the self-hosted arcd fleet
# (NO GitHub-hosted runners). Semver-only tags. Deployable on DOKS.
#
# This is the CONTAINER-image path. The repo's publish-gui*.yml workflows
# publish the npm library packages and are unaffected.
on:
push:
tags: ['v*']
workflow_dispatch:
permissions:
contents: read
packages: write
id-token: write
jobs:
docker:
uses: hanzoai/.github/.github/workflows/docker-build.yml@main
with:
image: ghcr.io/hanzoai/gui
secrets: inherit
+1 -1
View File
@@ -8,7 +8,7 @@ on:
jobs:
tagged-release:
name: Changelog
runs-on: [self-hosted, linux, amd64]
runs-on: hanzo-build-linux-amd64
# needs: release
steps:
+4 -4
View File
@@ -19,7 +19,7 @@ concurrency:
jobs:
checks:
runs-on: [self-hosted, linux, amd64]
runs-on: hanzo-build-linux-amd64
steps:
- name: Checkout
uses: actions/checkout@v5
@@ -37,7 +37,7 @@ jobs:
run: bun run lint
unit-tests:
runs-on: [self-hosted, linux, amd64]
runs-on: hanzo-build-linux-amd64
env:
NODE_OPTIONS: '--max-old-space-size=6144'
steps:
@@ -66,7 +66,7 @@ jobs:
run: bun turbo run test:web --filter='!@hanzogui/kitchen-sink' --concurrency=1
changes:
runs-on: [self-hosted, linux, amd64]
runs-on: hanzo-build-linux-amd64
outputs:
integration-relevant: ${{ steps.filter.outputs.integration-relevant }}
steps:
@@ -90,7 +90,7 @@ jobs:
integration-tests:
needs: changes
if: needs.changes.outputs.integration-relevant == 'true'
runs-on: [self-hosted, linux, amd64]
runs-on: hanzo-build-linux-amd64
strategy:
fail-fast: false
matrix:
-108
View File
@@ -1,108 +0,0 @@
name: Publish gui (all packages)
# Publishes the FULL gui surface — every @hanzogui/* primitive AND the
# `hanzogui` + `@hanzo/gui` umbrellas — at the current on-disk version
# (7.x), with freshly built `dist/`. This is the fix for the broken
# 7.0.0 publish, where the primitives shipped without `dist/` and
# `@hanzo/gui` therefore failed to resolve for standalone consumers.
#
# `publish-gui.yml` only ships the umbrella; this ships the primitives it
# depends on so a clean `npm i @hanzo/gui` works end-to-end.
#
# Trigger: manual (workflow_dispatch, type "publish" to confirm) or by
# pushing a `release/gui-all-v*` tag.
#
# NPM_TOKEN resolution mirrors publish-gui.yml:
# 1. KMS via Universal Auth (KMS_CLIENT_ID/SECRET → short-lived token)
# 2. KMS via long-lived HANZO_API_KEY (legacy bootstrap)
# 3. Direct repo secret NPM_TOKEN (fallback)
on:
workflow_dispatch:
inputs:
confirm:
description: 'Type "publish" to publish ALL gui packages at the current version'
required: true
default: ''
push:
tags:
- 'release/gui-all-v*'
permissions:
contents: read
id-token: write
jobs:
publish-all:
name: Build + publish all gui packages
runs-on: [self-hosted, linux, arm64]
if: github.event_name == 'push' || github.event.inputs.confirm == 'publish'
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Install
uses: ./.github/actions/install
- name: Build all packages
# Fresh checkout has no dist; --republish skips release.ts's own
# build, so build here explicitly. `npm pack` (inside release.ts)
# will fail loudly if any dist tree is missing.
run: bun run build
- name: Resolve NPM_TOKEN (KMS → fallback to repo secret)
id: token
env:
DIRECT_NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
KMS_CLIENT_ID: ${{ secrets.KMS_CLIENT_ID }}
KMS_CLIENT_SECRET: ${{ secrets.KMS_CLIENT_SECRET }}
HANZO_API_KEY: ${{ secrets.HANZO_API_KEY }}
KMS_ENDPOINT: ${{ vars.KMS_ENDPOINT || 'https://kms.hanzo.ai' }}
KMS_WORKSPACE_ID: ${{ vars.KMS_WORKSPACE_ID_GUI || 'e1359bf4-31b4-4dfa-bb90-323e2c298ad8' }}
run: |
set -eu
npm_token=""
if [ -n "${KMS_CLIENT_ID:-}" ] && [ -n "${KMS_CLIENT_SECRET:-}" ]; then
HANZO_API_KEY=$(curl -sf "${KMS_ENDPOINT}/api/v1/auth/universal-auth/login" \
-H "Content-Type: application/json" \
-d "{\"clientId\":\"${KMS_CLIENT_ID}\",\"clientSecret\":\"${KMS_CLIENT_SECRET}\"}" \
| jq -r '.accessToken') || true
fi
if [ -n "${HANZO_API_KEY:-}" ]; then
response=$(curl -sf \
"${KMS_ENDPOINT}/api/v3/secrets/raw?workspaceId=${KMS_WORKSPACE_ID}&secretPath=/publish&environment=prod" \
-H "Authorization: Bearer ${HANZO_API_KEY}" 2>/dev/null) || true
if [ -n "${response:-}" ]; then
npm_token=$(echo "$response" | jq -r '.secrets[] | select(.secretKey=="NPM_TOKEN") | .secretValue // empty')
fi
fi
if [ -z "$npm_token" ]; then
npm_token="${DIRECT_NPM_TOKEN:-}"
if [ -n "$npm_token" ]; then
echo "Using NPM_TOKEN from repo secret (KMS path unavailable)."
fi
fi
if [ -z "$npm_token" ]; then
echo "::error::No NPM_TOKEN available — need KMS_CLIENT_ID/SECRET, HANZO_API_KEY, or NPM_TOKEN repo secret."
exit 1
fi
echo "::add-mask::${npm_token}"
echo "npm_token=${npm_token}" >> "$GITHUB_OUTPUT"
- name: Configure npm registry
env:
NPM_TOKEN: ${{ steps.token.outputs.npm_token }}
run: |
echo 'registry=https://registry.npmjs.org/' > ~/.npmrc
echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" >> ~/.npmrc
- name: Publish gui surface (primitives + umbrella + @hanzo/gui alias)
# Targeted publish of just the @hanzogui/* closure + hanzogui +
# @hanzo/gui, at the current on-disk version. Avoids release.ts's
# whole-workspace fan-out (which fails packing unrelated
# @hanzo_network/* packages) and its fragile tarball-rename step.
# Idempotent — skips any name@version already on npm.
env:
NPM_TOKEN: ${{ steps.token.outputs.npm_token }}
NODE_AUTH_TOKEN: ${{ steps.token.outputs.npm_token }}
run: node ./scripts/publish-gui-surface.mjs
+1 -1
View File
@@ -28,7 +28,7 @@ permissions:
jobs:
publish:
name: Build, smoke-test, publish
runs-on: [self-hosted, linux, arm64]
runs-on: hanzo-build-linux-amd64
steps:
- uses: actions/checkout@v5
with:
+2 -2
View File
@@ -10,7 +10,7 @@ on:
jobs:
release:
name: Release
runs-on: [self-hosted, linux, amd64]
runs-on: hanzo-build-linux-amd64
steps:
- name: Checkout Repo
uses: actions/checkout@v5
@@ -36,7 +36,7 @@ jobs:
tagged-release:
name: Tagged Release
runs-on: [self-hosted, linux, amd64]
runs-on: hanzo-build-linux-amd64
# needs: release
steps:
+2 -2
View File
@@ -179,7 +179,7 @@ jobs:
name: Build Android App
# Only run on main/v* branches (not PRs)
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/v') || github.ref == 'refs/heads/rn82'
runs-on: [self-hosted, linux, amd64]
runs-on: hanzo-build-linux-amd64
timeout-minutes: 45
outputs:
android-cache-key: ${{ steps.final-cache-key.outputs.cache_key }}
@@ -446,7 +446,7 @@ jobs:
needs: build-android
# Only run on main/v* branches (not PRs)
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/v') || github.ref == 'refs/heads/rn82'
runs-on: [self-hosted, linux, amd64]
runs-on: hanzo-build-linux-amd64
timeout-minutes: 45
# Android emulator in CI is flaky with window focus issues - don't block on failures
continue-on-error: true
-1
View File
@@ -1 +0,0 @@
LLM.md
+136
View File
@@ -0,0 +1,136 @@
Please read ./CONTRIBUTING.md as well
Note you need to re-build packages (`bun run build` in the package directory) as you change them, unless you or someone is running a `bun run watch` at root.
FOR LONG RUNNNING DEBUGGING run `bun run watch` in the background its faster and rebuilds all packages.
keep commits to one line, add a trailing "Fixes #" if associated with a GH issue, and start with a convential commit style - UNLESS its a change that shouldn't go into the changelog, in those cases you can do things like `docs: ` or `site: `.
# Hanzo GUI Testing Guide
## Running Tests
### Kitchen Sink Tests
The kitchen-sink package contains the main integration tests for Hanzo GUI components. To run these tests:
1. **Start the web server** (in the background):
```bash
cd apps/kitchen-sink
bun run start:web
```
To open a specific test case in the browser:
```bash
open "http://localhost:9000/?test=YourTestCaseName"
```
Test case names match the file names in `apps/kitchen-sink/src/usecases/` (e.g., `SelectFocusScopeCase`).
To open a component demo:
```bash
open "http://localhost:9000/?demo=Select"
```
Demo names match files in `apps/demos/src/` without the `Demo` suffix (e.g., `Select` for `SelectDemo.tsx`).
2. **Run all web tests** with different animation drivers:
```bash
bun run test:web
```
This uses `run-tests-parallel.ts` which first runs `default` + `webkit` projects sequentially, then runs all four animated driver projects (`css`, `native`, `reanimated`, `motion`) in parallel against a single shared dev server.
3. **Run tests with a specific animation driver**:
```bash
# Using env var + playwright --project flag
cd apps/kitchen-sink
NODE_ENV=test HANZO_GUI_TEST_ANIMATION_DRIVER=css npx playwright test --project=animated-css
# Available projects: animated-css, animated-native, animated-reanimated, animated-motion
```
4. **Run a specific test file**:
```bash
# Using playwright directly
cd apps/kitchen-sink
npx playwright test tests/PopoverFocusScope.test.tsx
# Or with a specific driver
NODE_ENV=test HANZO_GUI_TEST_ANIMATION_DRIVER=css npx playwright test tests/YourTest.animated.test.tsx --project=animated-css
```
5. **Debug tests**:
```bash
bun run test:web:debug
# or
npx playwright test --debug
```
### Test Structure
Tests are located in `apps/kitchen-sink/tests/` and follow these naming conventions:
- `ComponentName.test.tsx` - Standard tests that run ONCE with the default animation driver
- `ComponentName.animated.test.tsx` - Animation-dependent tests that run with ALL animation drivers (css, native, reanimated, motion)
This separation significantly speeds up the test suite since most tests don't need to run 4x across all animation drivers. Only use `.animated.test.tsx` for tests that specifically verify animation behavior across different drivers.
### Writing Tests
When writing tests for focus behavior or component interactions:
1. Use appropriate wait times for animations and focus changes
2. Be aware that `trapFocus` behavior depends on the component's open state
3. Test both trapped and non-trapped focus scenarios
4. Consider browser focus behavior when `trapFocus` is false
### Common Issues
- If tests fail due to timing, add appropriate `waitForTimeout` calls
- For focus tests, ensure elements are visible before testing focus state
- When testing popover/dialog components, wait for animations to complete
## Commit Message Conventions
- Use `site:` prefix (not `fix(site):`) for gui.hanzo.ai changes since they don't go in the changelog
- Use `ci:` prefix (not `fix(ci):`) for CI/workflow changes since they don't go in the changelog
- Keep commit messages to a single line
## iOS Development
See [docs/using-ios.md](./docs/using-ios.md) for iOS native development and Detox testing tips.
## gui.hanzo.ai API Authentication
When making authenticated API calls from the client side in gui.hanzo.ai, always use the `authFetch` helper:
```ts
import { authFetch } from '~/features/api/authFetch'
const response = await authFetch('/api/some-endpoint', {
method: 'POST',
body: JSON.stringify({ ... }),
})
```
**Why this matters:** Cookies alone are not reliable for auth in production due to cross-origin/SameSite issues. The `authFetch` helper automatically includes the Authorization header with the user's access token. All payment/subscription endpoints require this.
---
## Additional notes (merged from LLM.md)
# gui — AI Assistant Context
# Hanzo GUI
<h3 align="center">
Style library, design system, composable components, and more.
</h3>
-136
View File
@@ -1,136 +0,0 @@
Please read ./CONTRIBUTING.md as well
Note you need to re-build packages (`bun run build` in the package directory) as you change them, unless you or someone is running a `bun run watch` at root.
FOR LONG RUNNNING DEBUGGING run `bun run watch` in the background its faster and rebuilds all packages.
keep commits to one line, add a trailing "Fixes #" if associated with a GH issue, and start with a convential commit style - UNLESS its a change that shouldn't go into the changelog, in those cases you can do things like `docs: ` or `site: `.
# Hanzo GUI Testing Guide
## Running Tests
### Kitchen Sink Tests
The kitchen-sink package contains the main integration tests for Hanzo GUI components. To run these tests:
1. **Start the web server** (in the background):
```bash
cd apps/kitchen-sink
bun run start:web
```
To open a specific test case in the browser:
```bash
open "http://localhost:9000/?test=YourTestCaseName"
```
Test case names match the file names in `apps/kitchen-sink/src/usecases/` (e.g., `SelectFocusScopeCase`).
To open a component demo:
```bash
open "http://localhost:9000/?demo=Select"
```
Demo names match files in `apps/demos/src/` without the `Demo` suffix (e.g., `Select` for `SelectDemo.tsx`).
2. **Run all web tests** with different animation drivers:
```bash
bun run test:web
```
This uses `run-tests-parallel.ts` which first runs `default` + `webkit` projects sequentially, then runs all four animated driver projects (`css`, `native`, `reanimated`, `motion`) in parallel against a single shared dev server.
3. **Run tests with a specific animation driver**:
```bash
# Using env var + playwright --project flag
cd apps/kitchen-sink
NODE_ENV=test HANZO_GUI_TEST_ANIMATION_DRIVER=css npx playwright test --project=animated-css
# Available projects: animated-css, animated-native, animated-reanimated, animated-motion
```
4. **Run a specific test file**:
```bash
# Using playwright directly
cd apps/kitchen-sink
npx playwright test tests/PopoverFocusScope.test.tsx
# Or with a specific driver
NODE_ENV=test HANZO_GUI_TEST_ANIMATION_DRIVER=css npx playwright test tests/YourTest.animated.test.tsx --project=animated-css
```
5. **Debug tests**:
```bash
bun run test:web:debug
# or
npx playwright test --debug
```
### Test Structure
Tests are located in `apps/kitchen-sink/tests/` and follow these naming conventions:
- `ComponentName.test.tsx` - Standard tests that run ONCE with the default animation driver
- `ComponentName.animated.test.tsx` - Animation-dependent tests that run with ALL animation drivers (css, native, reanimated, motion)
This separation significantly speeds up the test suite since most tests don't need to run 4x across all animation drivers. Only use `.animated.test.tsx` for tests that specifically verify animation behavior across different drivers.
### Writing Tests
When writing tests for focus behavior or component interactions:
1. Use appropriate wait times for animations and focus changes
2. Be aware that `trapFocus` behavior depends on the component's open state
3. Test both trapped and non-trapped focus scenarios
4. Consider browser focus behavior when `trapFocus` is false
### Common Issues
- If tests fail due to timing, add appropriate `waitForTimeout` calls
- For focus tests, ensure elements are visible before testing focus state
- When testing popover/dialog components, wait for animations to complete
## Commit Message Conventions
- Use `site:` prefix (not `fix(site):`) for gui.hanzo.ai changes since they don't go in the changelog
- Use `ci:` prefix (not `fix(ci):`) for CI/workflow changes since they don't go in the changelog
- Keep commit messages to a single line
## iOS Development
See [docs/using-ios.md](./docs/using-ios.md) for iOS native development and Detox testing tips.
## gui.hanzo.ai API Authentication
When making authenticated API calls from the client side in gui.hanzo.ai, always use the `authFetch` helper:
```ts
import { authFetch } from '~/features/api/authFetch'
const response = await authFetch('/api/some-endpoint', {
method: 'POST',
body: JSON.stringify({ ... }),
})
```
**Why this matters:** Cookies alone are not reliable for auth in production due to cross-origin/SameSite issues. The `authFetch` helper automatically includes the Authorization header with the user's access token. All payment/subscription endpoints require this.
---
## Additional notes (merged from LLM.md)
# gui — AI Assistant Context
# Hanzo GUI
<h3 align="center">
Style library, design system, composable components, and more.
</h3>
Symlink
+1
View File
@@ -0,0 +1 @@
CLAUDE.md
+1 -1
View File
@@ -3,7 +3,7 @@ import React from 'react'
import type { FontSizeTokens, SelectProps } from 'hanzogui'
import { Adapt, Label, Select, Sheet, Theme, XStack, YStack, getFontSize } from 'hanzogui'
import { LinearGradient } from 'hanzogui/linear-gradient'
import { LinearGradient } from 'gui/linear-gradient'
export function SelectDemo() {
return (
+1 -1
View File
@@ -1,7 +1,7 @@
import type { GuiBuildOptions } from 'hanzogui'
export default {
components: ['hanzogui'],
components: ['gui'],
logTimings: true,
config: '@hanzogui/dev-config',
outputCSS: './gui.generated.css',
@@ -1,149 +1,10 @@
import { mkdirSync, readdirSync, statSync } from 'node:fs'
import { mkdirSync } from 'node:fs'
import { existsSync, writeFileSync, readFileSync } from 'node:fs'
import { resolve, dirname, join } from 'node:path'
import { resolve, dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
const __dirname = dirname(fileURLToPath(import.meta.url))
const RECIPES_COMPONENT_PREFIX = '@hanzogui/recipes/component/'
/**
* Recursively collect .ts/.tsx source files under a directory, skipping
* node_modules and build output.
* @param {string} dir
* @param {string[]} acc
* @returns {string[]}
*/
function collectSourceFiles(dir, acc = []) {
let entries
try {
entries = readdirSync(dir)
} catch {
return acc
}
for (const name of entries) {
if (name === 'node_modules' || name === 'dist' || name === 'recipes-output') continue
const full = join(dir, name)
let s
try {
s = statSync(full)
} catch {
continue
}
if (s.isDirectory()) {
collectSourceFiles(full, acc)
} else if (name.endsWith('.ts') || name.endsWith('.tsx')) {
acc.push(full)
}
}
return acc
}
/**
* Scan the app for deep `@hanzogui/recipes/component/*` imports and the named
* bindings each subpath must provide, so concrete stub modules can be generated
* when the (optional, pro-only) recipes repo is absent.
*
* Three import shapes are detected:
* 1. namespace -> import * as NS from '<subpath>' (then NS.Member usages)
* 2. named -> import { A, B } from '<subpath>'
* 3. re-export -> export { A } from '<subpath>'
*
* @param {string} appDir
* @returns {Record<string, string[]>} subpath -> sorted unique export names
*/
function scanRecipesSubpaths(appDir) {
const subpaths = {}
for (const file of collectSourceFiles(appDir)) {
let src
try {
src = readFileSync(file, 'utf-8')
} catch {
continue
}
if (!src.includes(RECIPES_COMPONENT_PREFIX)) continue
// namespace imports + member accesses
for (const m of src.matchAll(/import\s+\*\s+as\s+(\w+)\s+from\s+['"]([^'"]+)['"]/g)) {
const [, ns, sp] = m
if (!sp.startsWith(RECIPES_COMPONENT_PREFIX)) continue
subpaths[sp] ??= new Set()
const memberRe = new RegExp('\\b' + ns + '\\.([A-Za-z_][A-Za-z0-9_]*)', 'g')
for (const u of src.matchAll(memberRe)) subpaths[sp].add(u[1])
}
// named imports and re-exports
for (const m of src.matchAll(/(?:import|export)\s+\{([^}]+)\}\s+from\s+['"]([^'"]+)['"]/g)) {
const [, names, sp] = m
if (!sp.startsWith(RECIPES_COMPONENT_PREFIX)) continue
subpaths[sp] ??= new Set()
for (const raw of names.split(',')) {
const name = raw.trim().split(/\s+as\s+/)[0].trim()
if (name) subpaths[sp].add(name)
}
}
}
return Object.fromEntries(
Object.entries(subpaths).map(([k, v]) => [k, [...v].sort()])
)
}
/**
* Generate concrete stub modules for deep `@hanzogui/recipes/component/*`
* subpaths used by the showcase tree, returning a map from subpath -> absolute
* stub file path. Each stub exports a no-op component (carrying a `.fileName`
* field so `Member.fileName` reads don't throw) as the default and as every
* named binding the app imports — concrete on-disk named exports are required
* because rolldown statically validates `export { X } from` / `import { X }`
* and does not transform virtual `\0`-modules through commonjs interop.
*
* @param {Object} options
* @param {string} options.appDir - app root (dir containing components/, vite.config.ts)
* @param {string} options.outDir - directory to write stub modules into
* @returns {Record<string, string>} subpath -> absolute stub path
*/
export function generateSubpathStubs({ appDir, outDir }) {
const map = scanRecipesSubpaths(appDir)
mkdirSync(outDir, { recursive: true })
const result = {}
for (const [subpath, names] of Object.entries(map)) {
const flat = subpath.slice(RECIPES_COMPONENT_PREFIX.length).replace(/[^A-Za-z0-9]+/g, '_')
const stubPath = resolve(outDir, `${flat}.tsx`)
// Hook-shaped exports (useFoo) are called, not rendered, and their result is
// often destructured (e.g. `const { sm } = useGroupMedia(...)`), so they must
// return a (proxy) object rather than the null-rendering component stub.
const namedExports = names
.filter((n) => n !== 'default')
.map((n) =>
/^use[A-Z0-9]/.test(n)
? `export const ${n} = recipesSubpathHook`
: `export const ${n} = RecipesSubpathStub`
)
.join('\n')
writeFileSync(
stubPath,
`// AUTO-GENERATED stub for ${subpath}
// Recipes is optional (pro users only); the real components live in the
// separate recipes repo. Regenerate via scripts/generate-recipes-proxy.mjs.
function RecipesSubpathStub() {
return null
}
RecipesSubpathStub.fileName = ''
// Hook stub: returns an object that yields undefined for any destructured key,
// so callers like \`const { sm } = useGroupMedia(...)\` never throw.
const recipesSubpathHook = () =>
new Proxy({}, { get: () => undefined }) as any
export default RecipesSubpathStub
${namedExports}
`
)
result[subpath] = stubPath
}
return result
}
/**
* Generate recipes proxy files based on whether the recipes repo is available.
* Can be called from vite config or run directly as a script.
@@ -158,23 +19,11 @@ export function generateRecipesProxy(options = {}) {
const RECIPES_PATH = resolve(basePath, '../../../../recipes')
const HELPERS_DIST_PATH = resolve(basePath, '../helpers/dist')
const APP_DIR = resolve(basePath, '..')
const hasRecipes = existsSync(RECIPES_PATH)
// Ensure dist exists
mkdirSync(HELPERS_DIST_PATH, { recursive: true })
// When recipes is absent, generate concrete stub modules for every deep
// `@hanzogui/recipes/component/*` subpath the app imports, so the showcase
// tree (which is always in the build graph via RecipesComponentSection) can
// resolve its named imports/re-exports.
const subpathStubs = hasRecipes
? {}
: generateSubpathStubs({
appDir: APP_DIR,
outDir: resolve(HELPERS_DIST_PATH, 'recipes-subpath-stubs'),
})
const proxyPath = resolve(HELPERS_DIST_PATH, 'recipes-proxy.ts')
const existingContent = existsSync(proxyPath) ? readFileSync(proxyPath, 'utf-8') : ''
const isStub = existingContent.includes('Stub file for when recipes is not available')
@@ -182,7 +31,7 @@ export function generateRecipesProxy(options = {}) {
// Skip if already generated with correct state and has all exports
if (existingContent && isStub === !hasRecipes && hasCurrentRouteProvider) {
return { hasRecipes, subpathStubs }
return { hasRecipes }
}
if (!hasRecipes) {
@@ -238,7 +87,7 @@ export * as Sections from '../../components/recipes-showcase/sections'
}
}
return { hasRecipes, subpathStubs }
return { hasRecipes }
}
// Run if called directly (postinstall script)
+50 -17
View File
@@ -37,10 +37,8 @@ if (!existsSync(vitePluginDist) || !existsSync(staticDist)) {
}
}
// Generate recipes proxy files (creates stubs if recipes repo not found).
// When recipes is absent, subpathStubs maps each deep
// `@hanzogui/recipes/component/*` import to a concrete generated stub module.
const { hasRecipes, subpathStubs } = generateRecipesProxy({
// Generate recipes proxy files (creates stubs if recipes repo not found)
const { hasRecipes } = generateRecipesProxy({
basePath: pathResolve(import.meta.dirname, 'scripts'),
silent: false,
})
@@ -63,7 +61,7 @@ const include = [
'swr/mutation',
'mdx-bundler/client',
// core hanzo-gui packages must be pre-bundled together to avoid duplicate instances
'hanzogui',
'gui',
'@hanzogui/core',
'@hanzogui/web',
// existing
@@ -121,19 +119,17 @@ export default {
resolve: {
preserveSymlinks: false,
alias: [
// When recipes is absent, map each deep @hanzogui/recipes/component/*
// import to its concrete generated stub. These MUST precede the catch-all
// '@hanzogui/recipes' alias below, otherwise that alias swallows the
// subpath (resolving to recipes-proxy/component/...) and the build fails
// with UNLOADABLE_DEPENDENCY. Stubs carry the exact named exports the
// showcase tree imports/re-exports, which rolldown validates statically.
// Regex-based alias for recipes components when not available
...(!hasRecipes
? Object.entries(subpathStubs)
// longest subpath first: vite matches `id === find || id.startsWith(find + '/')`,
// so a parent like `.../user/preferences` must not shadow its child
// `.../user/preferences/LocationNotification`.
.sort(([a], [b]) => b.length - a.length)
.map(([find, replacement]) => ({ find, replacement }))
? [
{
find: /^@gui\/recipes\/component\/.+$/,
replacement: pathResolve(
import.meta.dirname,
'./helpers/dist/recipes-component-stub.tsx'
),
},
]
: []),
// Standard string-based aliases
{
@@ -208,6 +204,43 @@ export default {
},
plugins: [
// Plugin to stub recipes component imports when recipes repo is not available
!hasRecipes && {
name: 'stub-recipes-components',
enforce: 'pre', // Run before other plugins including alias resolution
resolveId(id: string) {
// Intercept imports from @hanzogui/recipes/component/*
if (id.startsWith('@hanzogui/recipes/component/')) {
// Return a virtual module ID
return '\0recipes-component-stub:' + id
}
},
load(id: string) {
// Handle the virtual module
if (id.startsWith('\0recipes-component-stub:')) {
// Return stub component code
return `
import { YStack, Paragraph } from 'hanzogui'
export default function RecipesComponentStub() {
if (process.env.NODE_ENV === 'production') {
return null
}
return (
<YStack p="$4" bc="$borderColor" br="$4">
<Paragraph size="$2" color="$color10">
Recipes component not available
</Paragraph>
</YStack>
)
}
// Export as default and named for compatibility
export const LocationNotification = RecipesComponentStub
`
}
},
},
guiPlugin({
// see gui.build.ts
disable: process.env.NODE_ENV !== 'production',
+1 -1
View File
@@ -3,7 +3,7 @@ import React from 'react'
import type { FontSizeTokens, SelectProps } from 'hanzogui'
import { Adapt, Label, Select, Sheet, XStack, YStack, getFontSize } from 'hanzogui'
import { LinearGradient } from 'hanzogui/linear-gradient'
import { LinearGradient } from 'gui/linear-gradient'
export function SelectDemo() {
return (
+356 -205
View File
File diff suppressed because it is too large Load Diff
+3 -23
View File
@@ -120,8 +120,6 @@
"devDependencies": {
"@manypkg/cli": "^0.23.0",
"@playwright/test": "^1.49.1",
"@tailwindcss/typography": "^0.5.20",
"@tailwindcss/vite": "^4",
"@testing-library/dom": "^10.4.0",
"dotenv-cli": "^7.4.2",
"esbuild": "^0.27.2",
@@ -136,7 +134,6 @@
"p-map": "^7.0.3",
"prompts": "2.1.0",
"react-native-screens": "~4.23.0",
"tailwindcss": "^4",
"turbo": "^2.1.3",
"typescript": "~5.9.2",
"ultra-runner": "^3.10.5"
@@ -144,7 +141,7 @@
"overrides": {
"@react-navigation/core": "7.9.2",
"@react-navigation/elements": "2.8.1",
"@react-navigation/native": "7.1.34",
"@react-navigation/native": "7.1.9",
"@react-navigation/native-stack": "7.6.2",
"@react-navigation/routers": "7.4.0",
"@swc/core": "1.14.0",
@@ -153,24 +150,7 @@
"react-native": "0.83.2",
"whatwg-url": "14.1.1",
"shiki": "^3.19.0",
"react-resizable-panels": "^3.0.2",
"one": "1.12.5",
"vxrn": "1.12.5",
"@vxrn/compiler": "1.12.5",
"@vxrn/resolve": "1.12.5",
"@vxrn/color-scheme": "1.12.5",
"@vxrn/mdx": "1.12.5",
"@vxrn/safe-area": "1.12.5",
"@vxrn/utils": "1.12.5",
"@vxrn/debug": "1.12.5",
"@vxrn/vendor": "1.12.5",
"@vxrn/query-string": "1.12.5",
"@vxrn/url-parse": "1.12.5",
"@vxrn/vite-flow": "1.12.5",
"@vxrn/vite-plugin-metro": "1.12.5",
"@vxrn/tslib-lite": "1.12.5",
"create-vxrn": "1.12.5",
"@react-navigation/bottom-tabs": "7.10.1"
"react-resizable-panels": "^3.0.2"
},
"packageManager": "bun@1.3.9",
"manypkg": {
@@ -207,4 +187,4 @@
"exports": {
"./package.json": "./package.json"
}
}
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-270
View File
@@ -1,270 +0,0 @@
'use strict';
const index = require('./index-BSSKeTjn.cjs');
function arcInnerRadius(d) {
return d.innerRadius;
}
function arcOuterRadius(d) {
return d.outerRadius;
}
function arcStartAngle(d) {
return d.startAngle;
}
function arcEndAngle(d) {
return d.endAngle;
}
function arcPadAngle(d) {
return d && d.padAngle; // Note: optional!
}
function intersect(x0, y0, x1, y1, x2, y2, x3, y3) {
var x10 = x1 - x0, y10 = y1 - y0,
x32 = x3 - x2, y32 = y3 - y2,
t = y32 * x10 - x32 * y10;
if (t * t < index.epsilon) return;
t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / t;
return [x0 + t * x10, y0 + t * y10];
}
// Compute perpendicular offset line of length rc.
// http://mathworld.wolfram.com/Circle-LineIntersection.html
function cornerTangents(x0, y0, x1, y1, r1, rc, cw) {
var x01 = x0 - x1,
y01 = y0 - y1,
lo = (cw ? rc : -rc) / index.sqrt(x01 * x01 + y01 * y01),
ox = lo * y01,
oy = -lo * x01,
x11 = x0 + ox,
y11 = y0 + oy,
x10 = x1 + ox,
y10 = y1 + oy,
x00 = (x11 + x10) / 2,
y00 = (y11 + y10) / 2,
dx = x10 - x11,
dy = y10 - y11,
d2 = dx * dx + dy * dy,
r = r1 - rc,
D = x11 * y10 - x10 * y11,
d = (dy < 0 ? -1 : 1) * index.sqrt(index.max(0, r * r * d2 - D * D)),
cx0 = (D * dy - dx * d) / d2,
cy0 = (-D * dx - dy * d) / d2,
cx1 = (D * dy + dx * d) / d2,
cy1 = (-D * dx + dy * d) / d2,
dx0 = cx0 - x00,
dy0 = cy0 - y00,
dx1 = cx1 - x00,
dy1 = cy1 - y00;
// Pick the closer of the two intersection points.
// TODO Is there a faster way to determine which intersection to use?
if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1;
return {
cx: cx0,
cy: cy0,
x01: -ox,
y01: -oy,
x11: cx0 * (r1 / r - 1),
y11: cy0 * (r1 / r - 1)
};
}
function d3arc() {
var innerRadius = arcInnerRadius,
outerRadius = arcOuterRadius,
cornerRadius = index.constant(0),
padRadius = null,
startAngle = arcStartAngle,
endAngle = arcEndAngle,
padAngle = arcPadAngle,
context = null,
path = index.withPath(arc);
function arc() {
var buffer,
r,
r0 = +innerRadius.apply(this, arguments),
r1 = +outerRadius.apply(this, arguments),
a0 = startAngle.apply(this, arguments) - index.halfPi,
a1 = endAngle.apply(this, arguments) - index.halfPi,
da = index.abs(a1 - a0),
cw = a1 > a0;
if (!context) context = buffer = path();
// Ensure that the outer radius is always larger than the inner radius.
if (r1 < r0) r = r1, r1 = r0, r0 = r;
// Is it a point?
if (!(r1 > index.epsilon)) context.moveTo(0, 0);
// Or is it a circle or annulus?
else if (da > index.tau - index.epsilon) {
context.moveTo(r1 * index.cos(a0), r1 * index.sin(a0));
context.arc(0, 0, r1, a0, a1, !cw);
if (r0 > index.epsilon) {
context.moveTo(r0 * index.cos(a1), r0 * index.sin(a1));
context.arc(0, 0, r0, a1, a0, cw);
}
}
// Or is it a circular or annular sector?
else {
var a01 = a0,
a11 = a1,
a00 = a0,
a10 = a1,
da0 = da,
da1 = da,
ap = padAngle.apply(this, arguments) / 2,
rp = (ap > index.epsilon) && (padRadius ? +padRadius.apply(this, arguments) : index.sqrt(r0 * r0 + r1 * r1)),
rc = index.min(index.abs(r1 - r0) / 2, +cornerRadius.apply(this, arguments)),
rc0 = rc,
rc1 = rc,
t0,
t1;
// Apply padding? Note that since r1 ≥ r0, da1 ≥ da0.
if (rp > index.epsilon) {
var p0 = index.asin(rp / r0 * index.sin(ap)),
p1 = index.asin(rp / r1 * index.sin(ap));
if ((da0 -= p0 * 2) > index.epsilon) p0 *= (cw ? 1 : -1), a00 += p0, a10 -= p0;
else da0 = 0, a00 = a10 = (a0 + a1) / 2;
if ((da1 -= p1 * 2) > index.epsilon) p1 *= (cw ? 1 : -1), a01 += p1, a11 -= p1;
else da1 = 0, a01 = a11 = (a0 + a1) / 2;
}
var x01 = r1 * index.cos(a01),
y01 = r1 * index.sin(a01),
x10 = r0 * index.cos(a10),
y10 = r0 * index.sin(a10);
// Apply rounded corners?
if (rc > index.epsilon) {
var x11 = r1 * index.cos(a11),
y11 = r1 * index.sin(a11),
x00 = r0 * index.cos(a00),
y00 = r0 * index.sin(a00),
oc;
// Restrict the corner radius according to the sector angle. If this
// intersection fails, its probably because the arc is too small, so
// disable the corner radius entirely.
if (da < index.pi) {
if (oc = intersect(x01, y01, x00, y00, x11, y11, x10, y10)) {
var ax = x01 - oc[0],
ay = y01 - oc[1],
bx = x11 - oc[0],
by = y11 - oc[1],
kc = 1 / index.sin(index.acos((ax * bx + ay * by) / (index.sqrt(ax * ax + ay * ay) * index.sqrt(bx * bx + by * by))) / 2),
lc = index.sqrt(oc[0] * oc[0] + oc[1] * oc[1]);
rc0 = index.min(rc, (r0 - lc) / (kc - 1));
rc1 = index.min(rc, (r1 - lc) / (kc + 1));
} else {
rc0 = rc1 = 0;
}
}
}
// Is the sector collapsed to a line?
if (!(da1 > index.epsilon)) context.moveTo(x01, y01);
// Does the sectors outer ring have rounded corners?
else if (rc1 > index.epsilon) {
t0 = cornerTangents(x00, y00, x01, y01, r1, rc1, cw);
t1 = cornerTangents(x11, y11, x10, y10, r1, rc1, cw);
context.moveTo(t0.cx + t0.x01, t0.cy + t0.y01);
// Have the corners merged?
if (rc1 < rc) context.arc(t0.cx, t0.cy, rc1, index.atan2(t0.y01, t0.x01), index.atan2(t1.y01, t1.x01), !cw);
// Otherwise, draw the two corners and the ring.
else {
context.arc(t0.cx, t0.cy, rc1, index.atan2(t0.y01, t0.x01), index.atan2(t0.y11, t0.x11), !cw);
context.arc(0, 0, r1, index.atan2(t0.cy + t0.y11, t0.cx + t0.x11), index.atan2(t1.cy + t1.y11, t1.cx + t1.x11), !cw);
context.arc(t1.cx, t1.cy, rc1, index.atan2(t1.y11, t1.x11), index.atan2(t1.y01, t1.x01), !cw);
}
}
// Or is the outer ring just a circular arc?
else context.moveTo(x01, y01), context.arc(0, 0, r1, a01, a11, !cw);
// Is there no inner ring, and its a circular sector?
// Or perhaps its an annular sector collapsed due to padding?
if (!(r0 > index.epsilon) || !(da0 > index.epsilon)) context.lineTo(x10, y10);
// Does the sectors inner ring (or point) have rounded corners?
else if (rc0 > index.epsilon) {
t0 = cornerTangents(x10, y10, x11, y11, r0, -rc0, cw);
t1 = cornerTangents(x01, y01, x00, y00, r0, -rc0, cw);
context.lineTo(t0.cx + t0.x01, t0.cy + t0.y01);
// Have the corners merged?
if (rc0 < rc) context.arc(t0.cx, t0.cy, rc0, index.atan2(t0.y01, t0.x01), index.atan2(t1.y01, t1.x01), !cw);
// Otherwise, draw the two corners and the ring.
else {
context.arc(t0.cx, t0.cy, rc0, index.atan2(t0.y01, t0.x01), index.atan2(t0.y11, t0.x11), !cw);
context.arc(0, 0, r0, index.atan2(t0.cy + t0.y11, t0.cx + t0.x11), index.atan2(t1.cy + t1.y11, t1.cx + t1.x11), cw);
context.arc(t1.cx, t1.cy, rc0, index.atan2(t1.y11, t1.x11), index.atan2(t1.y01, t1.x01), !cw);
}
}
// Or is the inner ring just a circular arc?
else context.arc(0, 0, r0, a10, a00, cw);
}
context.closePath();
if (buffer) return context = null, buffer + "" || null;
}
arc.centroid = function() {
var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2,
a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - index.pi / 2;
return [index.cos(a) * r, index.sin(a) * r];
};
arc.innerRadius = function(_) {
return arguments.length ? (innerRadius = typeof _ === "function" ? _ : index.constant(+_), arc) : innerRadius;
};
arc.outerRadius = function(_) {
return arguments.length ? (outerRadius = typeof _ === "function" ? _ : index.constant(+_), arc) : outerRadius;
};
arc.cornerRadius = function(_) {
return arguments.length ? (cornerRadius = typeof _ === "function" ? _ : index.constant(+_), arc) : cornerRadius;
};
arc.padRadius = function(_) {
return arguments.length ? (padRadius = _ == null ? null : typeof _ === "function" ? _ : index.constant(+_), arc) : padRadius;
};
arc.startAngle = function(_) {
return arguments.length ? (startAngle = typeof _ === "function" ? _ : index.constant(+_), arc) : startAngle;
};
arc.endAngle = function(_) {
return arguments.length ? (endAngle = typeof _ === "function" ? _ : index.constant(+_), arc) : endAngle;
};
arc.padAngle = function(_) {
return arguments.length ? (padAngle = typeof _ === "function" ? _ : index.constant(+_), arc) : padAngle;
};
arc.context = function(_) {
return arguments.length ? ((context = _ == null ? null : _), arc) : context;
};
return arc;
}
exports.d3arc = d3arc;
-268
View File
@@ -1,268 +0,0 @@
import { P as withPath, Q as pi, S as cos, T as sin, V as constant, W as halfPi, X as epsilon, Y as tau, Z as sqrt, $ as min, a0 as abs, a1 as atan2, a2 as max, a3 as asin, a4 as acos } from './index-BnaE_tRw.js';
function arcInnerRadius(d) {
return d.innerRadius;
}
function arcOuterRadius(d) {
return d.outerRadius;
}
function arcStartAngle(d) {
return d.startAngle;
}
function arcEndAngle(d) {
return d.endAngle;
}
function arcPadAngle(d) {
return d && d.padAngle; // Note: optional!
}
function intersect(x0, y0, x1, y1, x2, y2, x3, y3) {
var x10 = x1 - x0, y10 = y1 - y0,
x32 = x3 - x2, y32 = y3 - y2,
t = y32 * x10 - x32 * y10;
if (t * t < epsilon) return;
t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / t;
return [x0 + t * x10, y0 + t * y10];
}
// Compute perpendicular offset line of length rc.
// http://mathworld.wolfram.com/Circle-LineIntersection.html
function cornerTangents(x0, y0, x1, y1, r1, rc, cw) {
var x01 = x0 - x1,
y01 = y0 - y1,
lo = (cw ? rc : -rc) / sqrt(x01 * x01 + y01 * y01),
ox = lo * y01,
oy = -lo * x01,
x11 = x0 + ox,
y11 = y0 + oy,
x10 = x1 + ox,
y10 = y1 + oy,
x00 = (x11 + x10) / 2,
y00 = (y11 + y10) / 2,
dx = x10 - x11,
dy = y10 - y11,
d2 = dx * dx + dy * dy,
r = r1 - rc,
D = x11 * y10 - x10 * y11,
d = (dy < 0 ? -1 : 1) * sqrt(max(0, r * r * d2 - D * D)),
cx0 = (D * dy - dx * d) / d2,
cy0 = (-D * dx - dy * d) / d2,
cx1 = (D * dy + dx * d) / d2,
cy1 = (-D * dx + dy * d) / d2,
dx0 = cx0 - x00,
dy0 = cy0 - y00,
dx1 = cx1 - x00,
dy1 = cy1 - y00;
// Pick the closer of the two intersection points.
// TODO Is there a faster way to determine which intersection to use?
if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1;
return {
cx: cx0,
cy: cy0,
x01: -ox,
y01: -oy,
x11: cx0 * (r1 / r - 1),
y11: cy0 * (r1 / r - 1)
};
}
function d3arc() {
var innerRadius = arcInnerRadius,
outerRadius = arcOuterRadius,
cornerRadius = constant(0),
padRadius = null,
startAngle = arcStartAngle,
endAngle = arcEndAngle,
padAngle = arcPadAngle,
context = null,
path = withPath(arc);
function arc() {
var buffer,
r,
r0 = +innerRadius.apply(this, arguments),
r1 = +outerRadius.apply(this, arguments),
a0 = startAngle.apply(this, arguments) - halfPi,
a1 = endAngle.apply(this, arguments) - halfPi,
da = abs(a1 - a0),
cw = a1 > a0;
if (!context) context = buffer = path();
// Ensure that the outer radius is always larger than the inner radius.
if (r1 < r0) r = r1, r1 = r0, r0 = r;
// Is it a point?
if (!(r1 > epsilon)) context.moveTo(0, 0);
// Or is it a circle or annulus?
else if (da > tau - epsilon) {
context.moveTo(r1 * cos(a0), r1 * sin(a0));
context.arc(0, 0, r1, a0, a1, !cw);
if (r0 > epsilon) {
context.moveTo(r0 * cos(a1), r0 * sin(a1));
context.arc(0, 0, r0, a1, a0, cw);
}
}
// Or is it a circular or annular sector?
else {
var a01 = a0,
a11 = a1,
a00 = a0,
a10 = a1,
da0 = da,
da1 = da,
ap = padAngle.apply(this, arguments) / 2,
rp = (ap > epsilon) && (padRadius ? +padRadius.apply(this, arguments) : sqrt(r0 * r0 + r1 * r1)),
rc = min(abs(r1 - r0) / 2, +cornerRadius.apply(this, arguments)),
rc0 = rc,
rc1 = rc,
t0,
t1;
// Apply padding? Note that since r1 ≥ r0, da1 ≥ da0.
if (rp > epsilon) {
var p0 = asin(rp / r0 * sin(ap)),
p1 = asin(rp / r1 * sin(ap));
if ((da0 -= p0 * 2) > epsilon) p0 *= (cw ? 1 : -1), a00 += p0, a10 -= p0;
else da0 = 0, a00 = a10 = (a0 + a1) / 2;
if ((da1 -= p1 * 2) > epsilon) p1 *= (cw ? 1 : -1), a01 += p1, a11 -= p1;
else da1 = 0, a01 = a11 = (a0 + a1) / 2;
}
var x01 = r1 * cos(a01),
y01 = r1 * sin(a01),
x10 = r0 * cos(a10),
y10 = r0 * sin(a10);
// Apply rounded corners?
if (rc > epsilon) {
var x11 = r1 * cos(a11),
y11 = r1 * sin(a11),
x00 = r0 * cos(a00),
y00 = r0 * sin(a00),
oc;
// Restrict the corner radius according to the sector angle. If this
// intersection fails, its probably because the arc is too small, so
// disable the corner radius entirely.
if (da < pi) {
if (oc = intersect(x01, y01, x00, y00, x11, y11, x10, y10)) {
var ax = x01 - oc[0],
ay = y01 - oc[1],
bx = x11 - oc[0],
by = y11 - oc[1],
kc = 1 / sin(acos((ax * bx + ay * by) / (sqrt(ax * ax + ay * ay) * sqrt(bx * bx + by * by))) / 2),
lc = sqrt(oc[0] * oc[0] + oc[1] * oc[1]);
rc0 = min(rc, (r0 - lc) / (kc - 1));
rc1 = min(rc, (r1 - lc) / (kc + 1));
} else {
rc0 = rc1 = 0;
}
}
}
// Is the sector collapsed to a line?
if (!(da1 > epsilon)) context.moveTo(x01, y01);
// Does the sectors outer ring have rounded corners?
else if (rc1 > epsilon) {
t0 = cornerTangents(x00, y00, x01, y01, r1, rc1, cw);
t1 = cornerTangents(x11, y11, x10, y10, r1, rc1, cw);
context.moveTo(t0.cx + t0.x01, t0.cy + t0.y01);
// Have the corners merged?
if (rc1 < rc) context.arc(t0.cx, t0.cy, rc1, atan2(t0.y01, t0.x01), atan2(t1.y01, t1.x01), !cw);
// Otherwise, draw the two corners and the ring.
else {
context.arc(t0.cx, t0.cy, rc1, atan2(t0.y01, t0.x01), atan2(t0.y11, t0.x11), !cw);
context.arc(0, 0, r1, atan2(t0.cy + t0.y11, t0.cx + t0.x11), atan2(t1.cy + t1.y11, t1.cx + t1.x11), !cw);
context.arc(t1.cx, t1.cy, rc1, atan2(t1.y11, t1.x11), atan2(t1.y01, t1.x01), !cw);
}
}
// Or is the outer ring just a circular arc?
else context.moveTo(x01, y01), context.arc(0, 0, r1, a01, a11, !cw);
// Is there no inner ring, and its a circular sector?
// Or perhaps its an annular sector collapsed due to padding?
if (!(r0 > epsilon) || !(da0 > epsilon)) context.lineTo(x10, y10);
// Does the sectors inner ring (or point) have rounded corners?
else if (rc0 > epsilon) {
t0 = cornerTangents(x10, y10, x11, y11, r0, -rc0, cw);
t1 = cornerTangents(x01, y01, x00, y00, r0, -rc0, cw);
context.lineTo(t0.cx + t0.x01, t0.cy + t0.y01);
// Have the corners merged?
if (rc0 < rc) context.arc(t0.cx, t0.cy, rc0, atan2(t0.y01, t0.x01), atan2(t1.y01, t1.x01), !cw);
// Otherwise, draw the two corners and the ring.
else {
context.arc(t0.cx, t0.cy, rc0, atan2(t0.y01, t0.x01), atan2(t0.y11, t0.x11), !cw);
context.arc(0, 0, r0, atan2(t0.cy + t0.y11, t0.cx + t0.x11), atan2(t1.cy + t1.y11, t1.cx + t1.x11), cw);
context.arc(t1.cx, t1.cy, rc0, atan2(t1.y11, t1.x11), atan2(t1.y01, t1.x01), !cw);
}
}
// Or is the inner ring just a circular arc?
else context.arc(0, 0, r0, a10, a00, cw);
}
context.closePath();
if (buffer) return context = null, buffer + "" || null;
}
arc.centroid = function() {
var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2,
a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - pi / 2;
return [cos(a) * r, sin(a) * r];
};
arc.innerRadius = function(_) {
return arguments.length ? (innerRadius = typeof _ === "function" ? _ : constant(+_), arc) : innerRadius;
};
arc.outerRadius = function(_) {
return arguments.length ? (outerRadius = typeof _ === "function" ? _ : constant(+_), arc) : outerRadius;
};
arc.cornerRadius = function(_) {
return arguments.length ? (cornerRadius = typeof _ === "function" ? _ : constant(+_), arc) : cornerRadius;
};
arc.padRadius = function(_) {
return arguments.length ? (padRadius = _ == null ? null : typeof _ === "function" ? _ : constant(+_), arc) : padRadius;
};
arc.startAngle = function(_) {
return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant(+_), arc) : startAngle;
};
arc.endAngle = function(_) {
return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant(+_), arc) : endAngle;
};
arc.padAngle = function(_) {
return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant(+_), arc) : padAngle;
};
arc.context = function(_) {
return arguments.length ? ((context = _ == null ? null : _), arc) : context;
};
return arc;
}
export { d3arc as d };
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,3 +0,0 @@
var __viteBrowserExternal = {};
export { __viteBrowserExternal as default };
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-7
View File
@@ -1,7 +0,0 @@
const lang = Object.freeze(JSON.parse("{\"displayName\":\"Berry\",\"name\":\"berry\",\"patterns\":[{\"include\":\"#controls\"},{\"include\":\"#strings\"},{\"include\":\"#comment-block\"},{\"include\":\"#comments\"},{\"include\":\"#keywords\"},{\"include\":\"#function\"},{\"include\":\"#member\"},{\"include\":\"#identifier\"},{\"include\":\"#number\"},{\"include\":\"#operator\"}],\"repository\":{\"comment-block\":{\"begin\":\"#-\",\"end\":\"-#\",\"name\":\"comment.berry\",\"patterns\":[{}]},\"comments\":{\"begin\":\"#\",\"end\":\"\\\\n\",\"name\":\"comment.line.berry\",\"patterns\":[{}]},\"controls\":{\"patterns\":[{\"match\":\"\\\\b(if|elif|else|for|while|do|end|break|continue|return|try|except|raise)\\\\b\",\"name\":\"keyword.control.berry\"}]},\"function\":{\"patterns\":[{\"match\":\"\\\\b([A-Z_a-z][0-9A-Z_a-z]*(?=\\\\s*\\\\())\",\"name\":\"entity.name.function.berry\"}]},\"identifier\":{\"patterns\":[{\"match\":\"\\\\b[A-Z_a-z]\\\\w+\\\\b\",\"name\":\"identifier.berry\"}]},\"keywords\":{\"patterns\":[{\"match\":\"\\\\b(var|static|def|class|true|false|nil|self|super|import|as|_class)\\\\b\",\"name\":\"keyword.berry\"}]},\"member\":{\"patterns\":[{\"captures\":{\"0\":{\"name\":\"entity.other.attribute-name.berry\"}},\"match\":\"\\\\.([A-Z_a-z][0-9A-Z_a-z]*)\"}]},\"number\":{\"patterns\":[{\"match\":\"0x\\\\h+|\\\\d+|(\\\\d+\\\\.?|\\\\.\\\\d)\\\\d*([Ee][-+]?\\\\d+)?\",\"name\":\"constant.numeric.berry\"}]},\"operator\":{\"patterns\":[{\"match\":\"[-\\\\]!%\\\\&(-+./:<=>\\\\[^|~]\",\"name\":\"keyword.operator.berry\"}]},\"strings\":{\"patterns\":[{\"begin\":\"f(?=[\\\"'])\",\"patterns\":[{\"begin\":\"\\\"\",\"end\":\"\\\"\",\"name\":\"string.quoted.other.berry\",\"patterns\":[{\"match\":\"(\\\\\\\\x\\\\h{2})|(\\\\\\\\[0-7]{3})|(\\\\\\\\\\\\\\\\)|(\\\\\\\\\\\")|(\\\\\\\\')|(\\\\\\\\a)|(\\\\\\\\b)|(\\\\\\\\f)|(\\\\\\\\n)|(\\\\\\\\r)|(\\\\\\\\t)|(\\\\\\\\v)\",\"name\":\"constant.character.escape.berry\"},{\"match\":\"\\\\{\\\\{[^}]*}}\",\"name\":\"string.quoted.other.berry\"},{\"begin\":\"\\\\{\",\"end\":\"}\",\"name\":\"keyword.other.unit.berry\",\"patterns\":[{\"include\":\"#keywords\"},{\"include\":\"#numbers\"},{\"include\":\"#identifier\"},{\"include\":\"#operator\"},{\"include\":\"#member\"},{\"include\":\"#function\"}]}]},{\"begin\":\"'\",\"end\":\"'\",\"name\":\"string.quoted.other.berry\",\"patterns\":[{\"match\":\"(\\\\\\\\x\\\\h{2})|(\\\\\\\\[0-7]{3})|(\\\\\\\\\\\\\\\\)|(\\\\\\\\\\\")|(\\\\\\\\')|(\\\\\\\\a)|(\\\\\\\\b)|(\\\\\\\\f)|(\\\\\\\\n)|(\\\\\\\\r)|(\\\\\\\\t)|(\\\\\\\\v)\",\"name\":\"constant.character.escape.berry\"},{\"match\":\"\\\\{\\\\{[^}]*}}\",\"name\":\"string.quoted.other.berry\"},{\"begin\":\"\\\\{\",\"end\":\"}\",\"name\":\"keyword.other.unit.berry\",\"patterns\":[{\"include\":\"#keywords\"},{\"include\":\"#numbers\"},{\"include\":\"#identifier\"},{\"include\":\"#operator\"},{\"include\":\"#member\"},{\"include\":\"#function\"}]}]}],\"while\":\"\\\\G|^[\\\\t ]*(?=[\\\"'])\"},{\"begin\":\"([\\\"'])\",\"end\":\"\\\\1\",\"name\":\"string.quoted.double.berry\",\"patterns\":[{\"match\":\"(\\\\\\\\x\\\\h{2})|(\\\\\\\\[0-7]{3})|(\\\\\\\\\\\\\\\\)|(\\\\\\\\\\\")|(\\\\\\\\')|(\\\\\\\\a)|(\\\\\\\\b)|(\\\\\\\\f)|(\\\\\\\\n)|(\\\\\\\\r)|(\\\\\\\\t)|(\\\\\\\\v)\",\"name\":\"constant.character.escape.berry\"}]}]}},\"scopeName\":\"source.berry\",\"aliases\":[\"be\"]}"));
const berry = [
lang
];
export { berry as default };
-11
View File
@@ -1,11 +0,0 @@
'use strict';
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const lang = Object.freeze(JSON.parse("{\"displayName\":\"Berry\",\"name\":\"berry\",\"patterns\":[{\"include\":\"#controls\"},{\"include\":\"#strings\"},{\"include\":\"#comment-block\"},{\"include\":\"#comments\"},{\"include\":\"#keywords\"},{\"include\":\"#function\"},{\"include\":\"#member\"},{\"include\":\"#identifier\"},{\"include\":\"#number\"},{\"include\":\"#operator\"}],\"repository\":{\"comment-block\":{\"begin\":\"#-\",\"end\":\"-#\",\"name\":\"comment.berry\",\"patterns\":[{}]},\"comments\":{\"begin\":\"#\",\"end\":\"\\\\n\",\"name\":\"comment.line.berry\",\"patterns\":[{}]},\"controls\":{\"patterns\":[{\"match\":\"\\\\b(if|elif|else|for|while|do|end|break|continue|return|try|except|raise)\\\\b\",\"name\":\"keyword.control.berry\"}]},\"function\":{\"patterns\":[{\"match\":\"\\\\b([A-Z_a-z][0-9A-Z_a-z]*(?=\\\\s*\\\\())\",\"name\":\"entity.name.function.berry\"}]},\"identifier\":{\"patterns\":[{\"match\":\"\\\\b[A-Z_a-z]\\\\w+\\\\b\",\"name\":\"identifier.berry\"}]},\"keywords\":{\"patterns\":[{\"match\":\"\\\\b(var|static|def|class|true|false|nil|self|super|import|as|_class)\\\\b\",\"name\":\"keyword.berry\"}]},\"member\":{\"patterns\":[{\"captures\":{\"0\":{\"name\":\"entity.other.attribute-name.berry\"}},\"match\":\"\\\\.([A-Z_a-z][0-9A-Z_a-z]*)\"}]},\"number\":{\"patterns\":[{\"match\":\"0x\\\\h+|\\\\d+|(\\\\d+\\\\.?|\\\\.\\\\d)\\\\d*([Ee][-+]?\\\\d+)?\",\"name\":\"constant.numeric.berry\"}]},\"operator\":{\"patterns\":[{\"match\":\"[-\\\\]!%\\\\&(-+./:<=>\\\\[^|~]\",\"name\":\"keyword.operator.berry\"}]},\"strings\":{\"patterns\":[{\"begin\":\"f(?=[\\\"'])\",\"patterns\":[{\"begin\":\"\\\"\",\"end\":\"\\\"\",\"name\":\"string.quoted.other.berry\",\"patterns\":[{\"match\":\"(\\\\\\\\x\\\\h{2})|(\\\\\\\\[0-7]{3})|(\\\\\\\\\\\\\\\\)|(\\\\\\\\\\\")|(\\\\\\\\')|(\\\\\\\\a)|(\\\\\\\\b)|(\\\\\\\\f)|(\\\\\\\\n)|(\\\\\\\\r)|(\\\\\\\\t)|(\\\\\\\\v)\",\"name\":\"constant.character.escape.berry\"},{\"match\":\"\\\\{\\\\{[^}]*}}\",\"name\":\"string.quoted.other.berry\"},{\"begin\":\"\\\\{\",\"end\":\"}\",\"name\":\"keyword.other.unit.berry\",\"patterns\":[{\"include\":\"#keywords\"},{\"include\":\"#numbers\"},{\"include\":\"#identifier\"},{\"include\":\"#operator\"},{\"include\":\"#member\"},{\"include\":\"#function\"}]}]},{\"begin\":\"'\",\"end\":\"'\",\"name\":\"string.quoted.other.berry\",\"patterns\":[{\"match\":\"(\\\\\\\\x\\\\h{2})|(\\\\\\\\[0-7]{3})|(\\\\\\\\\\\\\\\\)|(\\\\\\\\\\\")|(\\\\\\\\')|(\\\\\\\\a)|(\\\\\\\\b)|(\\\\\\\\f)|(\\\\\\\\n)|(\\\\\\\\r)|(\\\\\\\\t)|(\\\\\\\\v)\",\"name\":\"constant.character.escape.berry\"},{\"match\":\"\\\\{\\\\{[^}]*}}\",\"name\":\"string.quoted.other.berry\"},{\"begin\":\"\\\\{\",\"end\":\"}\",\"name\":\"keyword.other.unit.berry\",\"patterns\":[{\"include\":\"#keywords\"},{\"include\":\"#numbers\"},{\"include\":\"#identifier\"},{\"include\":\"#operator\"},{\"include\":\"#member\"},{\"include\":\"#function\"}]}]}],\"while\":\"\\\\G|^[\\\\t ]*(?=[\\\"'])\"},{\"begin\":\"([\\\"'])\",\"end\":\"\\\\1\",\"name\":\"string.quoted.double.berry\",\"patterns\":[{\"match\":\"(\\\\\\\\x\\\\h{2})|(\\\\\\\\[0-7]{3})|(\\\\\\\\\\\\\\\\)|(\\\\\\\\\\\")|(\\\\\\\\')|(\\\\\\\\a)|(\\\\\\\\b)|(\\\\\\\\f)|(\\\\\\\\n)|(\\\\\\\\r)|(\\\\\\\\t)|(\\\\\\\\v)\",\"name\":\"constant.character.escape.berry\"}]}]}},\"scopeName\":\"source.berry\",\"aliases\":[\"be\"]}"));
const berry = [
lang
];
exports.default = berry;
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-14
View File
@@ -1,14 +0,0 @@
'use strict';
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const python = require('./python-R5Doq6Ap.cjs');
const lang = Object.freeze(JSON.parse("{\"displayName\":\"Cairo\",\"name\":\"cairo\",\"patterns\":[{\"begin\":\"\\\\b(if).*\\\\(\",\"beginCaptures\":{\"1\":{\"name\":\"keyword.control.if\"},\"2\":{\"name\":\"entity.name.condition\"}},\"contentName\":\"source.cairo0\",\"end\":\"}\",\"endCaptures\":{\"0\":{\"name\":\"keyword.control.end\"}},\"name\":\"meta.control.if\",\"patterns\":[{\"include\":\"source.cairo0\"}]},{\"begin\":\"\\\\b(with)\\\\s+(.+)\\\\s*\\\\{\",\"beginCaptures\":{\"1\":{\"name\":\"keyword.control.with\"},\"2\":{\"name\":\"entity.name.identifiers\"}},\"contentName\":\"source.cairo0\",\"end\":\"}\",\"endCaptures\":{\"0\":{\"name\":\"keyword.control.end\"}},\"name\":\"meta.control.with\",\"patterns\":[{\"include\":\"source.cairo0\"}]},{\"begin\":\"\\\\b(with_attr)\\\\s+([A-Z_a-z][0-9A-Z_a-z]*)\\\\s*[({]\",\"beginCaptures\":{\"1\":{\"name\":\"keyword.control.with_attr\"},\"2\":{\"name\":\"entity.name.function\"}},\"contentName\":\"source.cairo0\",\"end\":\"}\",\"endCaptures\":{\"0\":{\"name\":\"keyword.control.end\"}},\"name\":\"meta.control.with_attr\",\"patterns\":[{\"include\":\"source.cairo0\"}]},{\"match\":\"\\\\belse\\\\b\",\"name\":\"keyword.control.else\"},{\"match\":\"\\\\b(call|jmp|ret|abs|rel|if)\\\\b\",\"name\":\"keyword.other.opcode\"},{\"match\":\"\\\\b([af]p)\\\\b\",\"name\":\"keyword.other.register\"},{\"match\":\"\\\\b(const|let|local|tempvar|felt|as|from|import|static_assert|return|assert|cast|alloc_locals|with|with_attr|nondet|dw|codeoffset|new|using|and)\\\\b\",\"name\":\"keyword.other.meta\"},{\"match\":\"\\\\b(SIZE(?:OF_LOCALS|))\\\\b\",\"name\":\"markup.italic\"},{\"match\":\"//[^\\\\n]*\\\\n\",\"name\":\"comment.line.sharp\"},{\"match\":\"\\\\b[A-Z_a-z][0-9A-Z_a-z]*:\\\\s*$\",\"name\":\"entity.name.function\"},{\"begin\":\"\\\\b(func)\\\\s+([A-Z_a-z][0-9A-Z_a-z]*)\\\\s*[({]\",\"beginCaptures\":{\"1\":{\"name\":\"storage.type.function.cairo\"},\"2\":{\"name\":\"entity.name.function\"}},\"contentName\":\"source.cairo0\",\"end\":\"}\",\"endCaptures\":{\"0\":{\"name\":\"storage.type.function.cairo\"}},\"name\":\"meta.function.cairo\",\"patterns\":[{\"include\":\"source.cairo0\"}]},{\"begin\":\"\\\\b(struct|namespace)\\\\s+([A-Z_a-z][0-9A-Z_a-z]*)\\\\s*\\\\{\",\"beginCaptures\":{\"1\":{\"name\":\"storage.type.function.cairo\"},\"2\":{\"name\":\"entity.name.function\"}},\"contentName\":\"source.cairo0\",\"end\":\"}\",\"endCaptures\":{\"0\":{\"name\":\"storage.type.function.cairo\"}},\"name\":\"meta.function.cairo\",\"patterns\":[{\"include\":\"source.cairo0\"}]},{\"match\":\"\\\\b[-+]?[0-9]+\\\\b\",\"name\":\"constant.numeric.decimal\"},{\"match\":\"\\\\b[-+]?0x\\\\h+\\\\b\",\"name\":\"constant.numeric.hexadecimal\"},{\"match\":\"'[^']*'\",\"name\":\"string.quoted.single\"},{\"match\":\"\\\"[^\\\"]*\\\"\",\"name\":\"string.quoted.double\"},{\"begin\":\"%\\\\{\",\"beginCaptures\":{\"0\":{\"name\":\"punctuation.section.embedded.begin.python\"}},\"contentName\":\"source.python\",\"end\":\"%}\",\"endCaptures\":{\"0\":{\"name\":\"punctuation.section.embedded.end.python\"},\"1\":{\"name\":\"source.python\"}},\"name\":\"meta.embedded.block.python\",\"patterns\":[{\"include\":\"source.python\"}]}],\"scopeName\":\"source.cairo0\",\"embeddedLangs\":[\"python\"]}"));
const cairo = [
...python.default,
lang
];
exports.default = cairo;
-10
View File
@@ -1,10 +0,0 @@
import python from './python-CRy0opiU.js';
const lang = Object.freeze(JSON.parse("{\"displayName\":\"Cairo\",\"name\":\"cairo\",\"patterns\":[{\"begin\":\"\\\\b(if).*\\\\(\",\"beginCaptures\":{\"1\":{\"name\":\"keyword.control.if\"},\"2\":{\"name\":\"entity.name.condition\"}},\"contentName\":\"source.cairo0\",\"end\":\"}\",\"endCaptures\":{\"0\":{\"name\":\"keyword.control.end\"}},\"name\":\"meta.control.if\",\"patterns\":[{\"include\":\"source.cairo0\"}]},{\"begin\":\"\\\\b(with)\\\\s+(.+)\\\\s*\\\\{\",\"beginCaptures\":{\"1\":{\"name\":\"keyword.control.with\"},\"2\":{\"name\":\"entity.name.identifiers\"}},\"contentName\":\"source.cairo0\",\"end\":\"}\",\"endCaptures\":{\"0\":{\"name\":\"keyword.control.end\"}},\"name\":\"meta.control.with\",\"patterns\":[{\"include\":\"source.cairo0\"}]},{\"begin\":\"\\\\b(with_attr)\\\\s+([A-Z_a-z][0-9A-Z_a-z]*)\\\\s*[({]\",\"beginCaptures\":{\"1\":{\"name\":\"keyword.control.with_attr\"},\"2\":{\"name\":\"entity.name.function\"}},\"contentName\":\"source.cairo0\",\"end\":\"}\",\"endCaptures\":{\"0\":{\"name\":\"keyword.control.end\"}},\"name\":\"meta.control.with_attr\",\"patterns\":[{\"include\":\"source.cairo0\"}]},{\"match\":\"\\\\belse\\\\b\",\"name\":\"keyword.control.else\"},{\"match\":\"\\\\b(call|jmp|ret|abs|rel|if)\\\\b\",\"name\":\"keyword.other.opcode\"},{\"match\":\"\\\\b([af]p)\\\\b\",\"name\":\"keyword.other.register\"},{\"match\":\"\\\\b(const|let|local|tempvar|felt|as|from|import|static_assert|return|assert|cast|alloc_locals|with|with_attr|nondet|dw|codeoffset|new|using|and)\\\\b\",\"name\":\"keyword.other.meta\"},{\"match\":\"\\\\b(SIZE(?:OF_LOCALS|))\\\\b\",\"name\":\"markup.italic\"},{\"match\":\"//[^\\\\n]*\\\\n\",\"name\":\"comment.line.sharp\"},{\"match\":\"\\\\b[A-Z_a-z][0-9A-Z_a-z]*:\\\\s*$\",\"name\":\"entity.name.function\"},{\"begin\":\"\\\\b(func)\\\\s+([A-Z_a-z][0-9A-Z_a-z]*)\\\\s*[({]\",\"beginCaptures\":{\"1\":{\"name\":\"storage.type.function.cairo\"},\"2\":{\"name\":\"entity.name.function\"}},\"contentName\":\"source.cairo0\",\"end\":\"}\",\"endCaptures\":{\"0\":{\"name\":\"storage.type.function.cairo\"}},\"name\":\"meta.function.cairo\",\"patterns\":[{\"include\":\"source.cairo0\"}]},{\"begin\":\"\\\\b(struct|namespace)\\\\s+([A-Z_a-z][0-9A-Z_a-z]*)\\\\s*\\\\{\",\"beginCaptures\":{\"1\":{\"name\":\"storage.type.function.cairo\"},\"2\":{\"name\":\"entity.name.function\"}},\"contentName\":\"source.cairo0\",\"end\":\"}\",\"endCaptures\":{\"0\":{\"name\":\"storage.type.function.cairo\"}},\"name\":\"meta.function.cairo\",\"patterns\":[{\"include\":\"source.cairo0\"}]},{\"match\":\"\\\\b[-+]?[0-9]+\\\\b\",\"name\":\"constant.numeric.decimal\"},{\"match\":\"\\\\b[-+]?0x\\\\h+\\\\b\",\"name\":\"constant.numeric.hexadecimal\"},{\"match\":\"'[^']*'\",\"name\":\"string.quoted.single\"},{\"match\":\"\\\"[^\\\"]*\\\"\",\"name\":\"string.quoted.double\"},{\"begin\":\"%\\\\{\",\"beginCaptures\":{\"0\":{\"name\":\"punctuation.section.embedded.begin.python\"}},\"contentName\":\"source.python\",\"end\":\"%}\",\"endCaptures\":{\"0\":{\"name\":\"punctuation.section.embedded.end.python\"},\"1\":{\"name\":\"source.python\"}},\"name\":\"meta.embedded.block.python\",\"patterns\":[{\"include\":\"source.python\"}]}],\"scopeName\":\"source.cairo0\",\"embeddedLangs\":[\"python\"]}"));
const cairo = [
...python,
lang
];
export { cairo as default };
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More