Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ internal/model/registry_generated.go
web/src/styles/tokens.generated.css
web/src/composables/themes.generated.ts

# Node / pnpm (root monorepo + per-app workspaces)
node_modules/
**/node_modules/
*.tsbuildinfo
packages/*/dist/
web-react/dist/

# Lockfile — committed at repo root for the monorepo
# (pnpm-lock.yaml IS committed; do NOT ignore it)

# Jekyll
docs/_site/
docs/.jekyll-cache/
Expand All @@ -14,4 +24,5 @@ docs/.jekyll-metadata
.claude
site/dist
site/node_modules
.jcode
.jcode/jcode-new
*.tsbuildinfo
4 changes: 4 additions & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# pnpm config for the React migration workspace.
# (pnpm settings that live in package.json pnpm.onlyBuiltDependencies or
# pnpm-workspace.yaml are preferred; this file is reserved for npmrc-style keys.)
auto-install-peers=true
23 changes: 21 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ internal/
telemetry/ # Optional Langfuse tracing
tui/ # BubbleTea v2 TUI components
web/ # HTTP server (REST + WS + PTY) + embedded Vue dist
web/ # Vue 3 + Vite + TypeScript frontend source (the product UI)
web/ # Vue 3 + Vite + TypeScript frontend source (the CURRENT product UI)
web-react/ # React 18 + Vite + RTK product app (migration in progress; parallel to web/)
packages/ # pnpm workspace: the reusable jcode-ui component library
jcode-ui/ # published styled React chat components (→ npm: jcode-ui)
jcode-ui-core/ # framework-agnostic core: types, ChatRuntime, headless primitives
site/ # React + Vite marketing/docs site → www.j-code.net (docs markdown in site/docs/)
desktop/ # Tauri 2 desktop shell; the Go binary runs as a sidecar
extension/ # jcode Browser Bridge Chrome extension (MV3) for the browser-use extension backend
Expand All @@ -62,6 +66,19 @@ script/ # Build-time code generation + install.sh
agent-eval/ # Agent evaluation harness + showcase generation
```

### Frontend migration (Vue → React) — in progress

The product UI is migrating from Vue 3 (`web/`) to React 18 (`web-react/`),
built on a new reusable component library (`packages/jcode-ui` + `jcode-ui-core`).
**During the migration both coexist:**

- `make build-web` (default) builds the **Vue** app → `internal/web/dist/` (production).
- `make build-web-react` builds the **React** app + packages → `internal/web/dist-react/` (parallel validation).
- `make lint-react` typechecks the React app + both packages.
- The Go `embed.FS` and Tauri `frontendDist` still point at the Vue `dist/`. The switch-over happens once `web-react` reaches feature parity.

The component library is the migration's organizing principle — see `packages/jcode-ui/README.md` and `site/docs/chat-ui/`. It's published to npm as `jcode-ui` (styled) + `jcode-ui-core` (headless). The runtime abstraction (`ChatRuntime` + `createExternalStoreRuntime`) is the seam that lets the components render from any Redux-shaped store.

### Key Design Decisions

- **Three transports, one interface:** TUI, ACP (JSON-RPC), and Web all implement `AgentEventHandler`. New transports only need to implement this interface.
Expand Down Expand Up @@ -175,7 +192,9 @@ agent-eval/ # Agent evaluation harness + showcase generation

---

## Frontend (web/)
## Frontend (web/) — Vue (production)

> **Note:** the product UI is migrating to React (`web-react/` + `packages/jcode-ui`). The Vue app remains the production build during the migration. New reusable UI work goes in `packages/jcode-ui` (React); see the migration section above and `packages/jcode-ui/README.md`.

- **Stack:** Vue 3 + TypeScript + Vite
- **Build:** `cd web && pnpm install && npx vite build` (or `make build-web`)
Expand Down
58 changes: 55 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ LDFLAGS := -s -w \

export GOFLAGS := -buildvcs=false

.PHONY: build build-binary run doctor version install clean build-web fmt lint lint-go lint-web generate setup-hooks desktop-icons desktop-sidecar desktop-dev desktop-build desktop-clean
.PHONY: build build-binary run doctor version install clean build-web build-web-react fmt lint lint-go lint-web lint-react generate setup-hooks desktop-icons desktop-sidecar desktop-dev desktop-build desktop-react-dev desktop-react-build desktop-clean

fmt:
@echo "Formatting Go..."
Expand All @@ -26,19 +26,54 @@ lint-go:
golangci-lint run

lint-web:
@echo "Linting frontend..."
@echo "Linting frontend (Vue)..."
cd web && (pnpm install --frozen-lockfile 2>/dev/null || pnpm install)
cd web && pnpm lint

lint-react:
@echo "Type-checking React frontend + packages..."
cd packages/jcode-ui-core && pnpm install --frozen-lockfile 2>/dev/null || pnpm install
cd packages/jcode-ui-core && npx tsc --noEmit -p tsconfig.json
cd packages/jcode-ui && npx tsc --noEmit -p tsconfig.json
cd web-react && npx tsc --noEmit -p tsconfig.app.json

generate:
@echo "Generating code..."
go generate ./internal/model/...
go generate ./internal/theme/...

# The frontend build. FRONTEND selects which app to build:
# web (default) — the current Vue app (production)
# web-react — the new React app (migration in progress; produces dist-react/)
# During the migration both coexist. The switch-over to React-as-default happens
# once web-react reaches feature parity and the Go embed points at dist-react.
FRONTEND ?= web

build-web: generate
@echo "Building frontend..."
@echo "Building frontend ($(FRONTEND))..."
ifeq ($(FRONTEND),web-react)
$(MAKE) build-web-react
else
cd web && (pnpm install --frozen-lockfile 2>/dev/null || pnpm install)
cd web && npx vite build
endif

# Build the React frontend + the two component-library packages it depends on.
# Output goes to ../internal/web/dist-react (kept separate from the Vue dist
# until the embed path is switched). The packages are workspace-linked, so this
# also builds jcode-ui-core (a dependency of jcode-ui).
#
# NOTE: pnpm's ERR_PNPM_IGNORED_BUILDS (esbuild/@parcel/watcher native scripts)
# returns a non-zero exit even when deps are fully installed. We tolerate that
# exit code from the install step — the build steps below don't depend on those
# build scripts having run.
build-web-react: generate
@echo "Building React frontend + packages..."
-pnpm install --frozen-lockfile 2>/dev/null || true
cd packages/jcode-ui-core && npx tsc -p tsconfig.build.json
cd packages/jcode-ui && npx tsc -p tsconfig.build.json
cd packages/jcode-ui && npx tailwindcss -i src/styles/entry.css -o dist/styles.css --minify
cd web-react && npx vite build

# The main binary never links CoreBluetooth (whose eager init triggers the macOS
# Bluetooth permission prompt at startup). BLE runs in a separate `jcode-ble`
Expand Down Expand Up @@ -120,5 +155,22 @@ desktop-dev: desktop-sidecar
desktop-build: desktop-sidecar
cd $(DESKTOP_DIR) && (pnpm install 2>/dev/null || npm install) && pnpm tauri build

# ─── React desktop variants ────────────────────────────────────────────────
# Same as desktop-dev/desktop-build but load the React frontend (web-react/)
# instead of the Vue app (web/). Uses tauri.react.conf.json to override the
# build block (frontendDist / beforeDevCommand / beforeBuildCommand) — every
# other Tauri setting (window, tray, sidecar, capabilities) is inherited.
# Requires `pnpm install` to have run once at the repo root (the React
# workspace lives there, not under desktop/).
desktop-react-dev: desktop-sidecar
@echo "Launching desktop (React frontend)…"
cd $(DESKTOP_DIR) && (pnpm install 2>/dev/null || npm install) && \
pnpm tauri dev --config src-tauri/tauri.react.conf.json

desktop-react-build: desktop-sidecar
@echo "Bundling desktop (React frontend)…"
cd $(DESKTOP_DIR) && (pnpm install 2>/dev/null || npm install) && \
pnpm tauri build --config src-tauri/tauri.react.conf.json

desktop-clean:
rm -rf $(SIDECAR_DIR) $(DESKTOP_DIR)/src-tauri/target
8 changes: 8 additions & 0 deletions desktop/src-tauri/tauri.react.conf.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"build": {
"frontendDist": "../../internal/web/dist-react",
"beforeDevCommand": "pnpm --dir ../web-react dev",
"devUrl": "http://localhost:5173",
"beforeBuildCommand": "make -C .. build-web-react"
}
}
Loading
Loading