Skip to content

feat(cli): base44 code — terminal agent session over Base44 apps (builder + imported) - #629

Open
ayal wants to merge 73 commits into
mainfrom
imported-commands
Open

ayal wants to merge 73 commits into
mainfrom
imported-commands

Conversation

@ayal

@ayal ayal commented Sep 17, 2026

Copy link
Copy Markdown

Note

Description

Adds Base44 Code (base44 code) — an interactive, Claude-Code-style terminal agent session over a Base44 app, rendered with Ink. From an empty directory the first prompt creates the app: --builder (the default) makes a normal Base44 app (React template + builder agent), while --import makes an imported app (a fresh GitHub repo, or /headless to scaffold a Wix Headless storefront). Inside a linked project the session just opens on that app. The PR also ships the supporting surface: the non-interactive base44 imported * commands, top-level base44 new, an account-wide builder-model picker (base44 model + in-session /model), and base44 target for pointing every command at a staging/preview host.

Related Issue

None — depends on backend apper PR #24793 (imported blank mode + preview). The builder-flow create needs no new backend.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)
  • Other (please describe):

Changes Made

  • base44 code (src/cli/commands/code.ts): TTY-only interactive session. Inside a linked app it resolves the app context and opens on it; elsewhere it runs a genesis session whose first prompt bootstraps the app — bootstrapBuilderApp (template + agent) or, with --import, bootstrapBlankApp (fresh private repo). --builder and --import are mutually exclusive; the active mode shows in the header label and footer chip.
  • Session UI (imported/session.tsx, session-engine.ts, render.ts, paste.ts): Ink/React session on the alternate screen with internal scrollback, live turn timer, status line, and a footer of OSC-8 clickable repo/editor/preview links (wrap-safe). Esc stops the running turn (Ctrl+C clears input, then exits); wheel/PageUp/PageDown scroll; typing mid-turn queues a message server-side. session-engine.ts holds the UI-free conversation watcher, turn-state derivation and submit path (including tolerance for a 5xx-after-delivery when a long turn trips the edge request timeout). paste.ts adds a bracketed-paste stdin proxy that flattens multi-line pastes into one input line.
  • Streaming/API core (core/resources/imported/api.ts, stream.ts): Zod-validated imported-app API (create builder/imported app, chat message/stop, full conversation, app state, git status/commit/discard/PR, preview URL, GitHub OAuth re-initiate) plus a polling differ that emits each conversation item exactly once, splits present/past tool labels, and detects turn settle from the newest user message's outcome stamp.
  • base44 imported commands (imported/index.ts, create.ts, chat.ts, git.ts): create (--repo / --blank / --mode direct|fork|copy / --prompt / …), chat, status, commit, discard, pr, preview; plus top-level base44 new [nameOrPrompt] [prompt] sugar that invents a base44-* repo/app/directory name from the prompt. All respect the global --json flag.
  • Model selection (core/model.ts, commands/model.ts): customer model registry mirroring the web picker, fuzzy name/id resolution, api/auth/me + update-user persistence, and a X-Builder-Model-Selection: user-v1 request header so the backend honors the saved pick. base44 model lists/sets/clears it; /model opens an arrow-navigable in-session picker.
  • base44 target (commands/target.ts, core/config.ts): persists a staging/preview API base URL (and an optional X-FF-Override feature-flag header) in the global Base44 dir; getBase44ApiUrl() now layers env → stored target → production, and --clear returns to prod.
  • Prompt expansions (imported/expansions.ts): /name tokens in a prompt expand to canned instruction blocks; ships /headless with the Wix Headless Fast playbook (flat /app layout, astro host binding vs. allowlist, compose service on :3000, MPA navigation via navigate(path, { reload: true })).
  • GitHub reconnect: a create that 401s on an expired GitHub token now prints a clickable "Reconnect GitHub" link instead of a bare error.
  • Build/tooling: jsx: react-jsx in tsconfig.json, knip project glob widened to src/**/*.{ts,tsx}, an esbuild plugin that stubs Ink's dev-only react-devtools-core import, @types/react devDependency, and ink / ink-text-input / react added as runtime dependencies.

Testing

  • I have tested these changes locally
  • I have added/updated tests as needed
  • All tests pass (npm test)

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation (if applicable)
  • My changes generate no new warnings
  • I have updated docs/ (AGENTS.md) if I made architectural changes

Additional Notes

  • New tests: tests/cli/imported.spec.ts (13 cases: status/commit/pr/chat, blank + named create, new name invention, code refusing a non-TTY), tests/cli/target.spec.ts, tests/core/expansions.spec.ts, tests/core/imported-stream.spec.ts (differ, tool metadata, rendering, ANSI hard-wrap, paste sanitizer, turn-settle). The suite was not executed while generating this description (no node_modules in the review environment), so "all tests pass" is left for CI to confirm.
  • Deliberate deviations from CLAUDE.md worth a reviewer's eye: ink, ink-text-input, and react land as real runtime dependencies (rule 6 allows only the workerd runtime packages as exceptions), and the interactive session renders with Ink and writes raw ANSI via process.stdout.write rather than @clack/prompts (rule 3) — unavoidable for an alternate-screen TUI, but neither exception is documented yet.
  • Docs not updated: nothing under docs/ changed, though this adds a new command family, a new core/ module (model.ts), and a new core/resources/imported/ area — worth a follow-up per rule 9.
  • base44 target writes the host/flag override in plaintext under the user's home dir; X-FF-Override is staging-only and production ignores it.
  • Local/manual verification is inferred from the branch's ~30 iterative UI-tuning commits (logo geometry, header layout, /headless wording), not from a recorded test run.

🤖 Generated by Claude | 2026-09-17 06:28 UTC | 1286712

ayal and others added 30 commits September 15, 2026 17:03
…iew, pr

base44 imported create imports a GitHub repo (direct/fork/copy) or starts
from scratch (--blank, a fresh private repo via the backend's blank mode),
links the directory, and with --prompt waits for the first build.
base44 imported chat drives one agent turn over the synchronous
/chat/message endpoint; status/commit/discard/pr wrap the imported/git
routes (branch-scoped via the global --branch); preview resolves the live
sandbox URL. BASE44_FF_OVERRIDE forwards an X-FF-Override header for
staging flag testing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
chat and the create kickoff now print the agent's activity as it happens —
thinking, text, tool calls and their results — by polling the app's
chat/full-conversation endpoint (messages persist per agent round) while
the turn request is open. The diff engine is pure and unit-tested; --json
keeps the single-document contract and skips streaming. chat also scopes
to the app's sole active branch so messages land on the working branch
(an unscoped send hits the unpushable main line) and accepts --branch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The stream now renders like the editor transcript: dim thinking, plain
prose, tool lines showing the salient argument (the command, the path, the
PR title — parsed from arguments_string, never the raw JSON blob), and a
dim one-line result under each settled tool with failures in red. The diff
engine emits typed events; the command layer styles them.

create --prompt no longer trusts the app status field, which flaps
mid-turn and ended the wait after the first round ('First build finished'
30 seconds in). Completion is now the outcome stamp the backend writes
onto the turn's user message at end-of-loop, on success and error alike.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… app

`imported create <name>` is from-scratch mode without ceremony: it makes
./<name>, links it, names the fresh GitHub repo and the app after it, and
hints the cd. --blank/--repo-name keep working; a bare name with no --repo
implies blank. Name is validated against directory/repo-safe characters.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…stamp

MessageOutcome is written with backend_status="pending" at turn START —
the previous check settled on the first poll, before the assistant message
even existed (no stream, instant 'First build finished'). Settle now
requires a terminal backend_status, which also keeps the stream alive
through post-turn auto-fix.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…output

The stream now reads like an agent transcript: a single spinner status line
at the bottom shows what is running right now (aliased tool + salient arg +
elapsed seconds, '+N more' for parallel calls) while settled items print as
compact one-liners above it — ✓ write path, ✓ bash cmd with a dim one-line
result, ✗ in red with the error. Tool names are aliased (run_shell_command→
bash, *_repo_file→read/write/edit, …) and quiet tools (read/write/edit/
reload) print no result on success. Poll interval down to 1s. Non-TTY and
--json keep plain output with no cursor codes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…r deep link

After create --prompt or chat finishes (TTY), the CLI stays in the session
and keeps taking prompts, each run as a streamed turn on the same working
branch; empty input or cancel ends it. The preview URL gets its https://
scheme (imported apps return a bare proxied host), and the editor link now
lands on the preview tab (/editor/preview) instead of the workspace
overview.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Quiet gaps between agent rounds now show a rotating gerund (Shmoozing…,
Percolating…, Noodling…) instead of a static waiting label — random start,
new word every 6s; a running tool still takes over the line.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s the close

The repo/editor/linked lines print dimmed right after creation (the editor
is usable during the build); the end of the turn adds only the preview URL,
so the agent's final message keeps the attention.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The repo/editor(/preview) links ride as a pinned footer under the live
stream — always visible and clickable while the agent works — and are
printed permanently when the stream ends, including through iteration-mode
turns. Tool summaries now salvage the salient key (path/command/title) out
of arguments JSON the wire truncated mid-string, so a big write shows the
file path instead of a raw half-JSON blob.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…otals

Every builder tool call carries a human title in its `summary` argument —
the same one the editor shows ('Confirmed Wix login', 'Built plan') — and
the stream now leads with it: ✓ Title  alias: salient-arg · 12s, with the
raw argument as dim detail and a duration when a call ran 3s or longer.
The spinner shows the running tool's title too. Turn ends print the total
(Turn finished · 4m 32s; First build finished · 6m 02s).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`base44 target <url> [--ff <override>]` persists a staging/preview host
(~/.base44/target.json) that every command then hits — env vars still win,
--clear returns to production, bare `target` shows the active host.
`base44 new <name> ["<prompt>"]` is the from-scratch flow as a first-class
command: directory + fresh private repo + app + streamed first build.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The preview URL is fetched while the stream still ticks and pushed into the
live footer array, so stop() prints one complete, visually separated block
(blank line, then repo/editor/preview) instead of links glued to the prose
plus a separate clack spinner and orphan preview line. The pinned block also
carries a leading blank line while streaming.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
new and chat (TTY) now run a persistent session: the conversation streams
into normal scrollback while a redrawn bottom region pins the footer links,
a status line — running tool + per-tool elapsed + LIVE turn timer, or
'ready — last turn 4m 32s' between turns — and an always-present input
line. Typing works mid-turn (Enter sends; the backend queues it behind the
running turn) with cursor editing, Ctrl+A/E/U, and paste flattening. One
long-lived conversation watcher covers every turn including server-queued
ones, so turn state derives from the newest user message's outcome stamp.
Each settle prints '— turn finished · <time>' into scrollback; Ctrl+C
clears input then exits (turns keep running server-side). --json and
non-TTY keep their previous plain output paths; the old prompt-loop module
is gone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…low input

The session clears the visible screen on start (shell history stays in
scrollback), the pinned region opens with a full-width dim rule so the
footer reads as a footer, and the key hints live on their own dim line
under the input instead of posing as placeholder text. Cursor parks on the
input line above the hint; clearing steps back down first.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
create now writes a minimal base44/config.jsonc alongside .app.jsonc — root
discovery (findProjectRoot) keys on a PROJECT config, so without it every
later command run from the created directory failed with 'No Base44 app ID
found'. Verified live: imported status resolves the app from a created-dir
shape with no --app-id. Never clobbers an existing config (wx flag).

The session also no longer claims '· ready' during the 10-30s before the
kickoff turn's user message exists (sandbox provisioning): create passes an
awaiting label, shown with a spinner and elapsed time, and the kickoff's
turn timer counts from session start rather than first detection.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The session UI is now React/Ink — the same architecture Claude Code uses:
history renders permanently into scrollback via <Static> while the bottom
region (rule, footer links, status with live turn timer, text input, hints)
re-renders in place. This replaces ~150 lines of hand-rolled ANSI cursor
arithmetic and buys correct input editing, wrapping, and resize behavior
from the framework. The session logic itself moved unchanged into a
render-free engine (session-engine.ts): persistent conversation watcher,
outcome-stamp turn state, mid-turn queued sends, kickoff-awaiting phase.

Containment: runInteractiveSession keeps its exact signature, so create/
chat are untouched beyond imports; no other command loads React. Bundling:
ink's dev-only react-devtools-core import is stubbed by a build plugin
(it otherwise lands as an eager import of an unshipped package); knip's
project glob learns .tsx. Deps: ink, react, ink-text-input.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ks below

Status line above (✻ musing with turn time, or spinner + running tool), a
rounded-border input box, and the footer links + hints as dim lines under
it — same layout grammar as Claude Code's bottom region. The rule line is
gone; the border carries the separation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Clear the viewport and park the cursor on the bottom row before mounting
Ink, so the input widget owns the bottom of the terminal from the first
frame and the conversation fills the space above — the Claude Code launch
feel, still without the alternate screen (scrollback survives).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sessions open with a bordered welcome box as the first history item — the
Base44 Code name and version in the border title, welcome-back with the
logged-in identity, the brand-orange dome logo, and the active target host
and cwd — scrolling away naturally like Claude Code's header.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The session starts at the top row — header first, then a fixed-height
dynamic region that bottom-justifies the input widget at the terminal's
bottom, conversation filling the space between (the actual Claude Code
layout). The mark is now a full circle with its bottom slice cut flat, per
the real logo, instead of a dome.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
base44 new "online store selling tmnt figures" is now the whole ceremony:
a lone argument that reads like a sentence is the prompt, and the repo,
directory, and app get an invented name from its words
(base44-online-store-selling-x7k) — recognizable in a repo list and
renameable later. create --blank without a name invents one the same way;
an explicit name still wins everywhere.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… placement

The bottom widget's spacer now SHRINKS as history accumulates (wrap-aware
line estimate), hitting zero when the screen fills — so the input stays on
the bottom row forever and only the conversation scrolls, instead of the
fixed-height box pushing the widget off-screen. The create call runs inside
the full-page frame (header top, spinner bottom) rather than a clack task
before it. The logo's missing slice moved to one row above the bottom cap,
matching the mark.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A real circle — computed on a 14×14 subpixel grid with half-blocks doubling
vertical resolution — with the slice above the bottom cap removed, per the
mark. All rows padded to equal width so per-row centering keeps alignment.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
base44 code opens the Base44 Code page with nothing but the header and the
input. In an empty directory the first prompt creates everything — invented
repo name, fresh private repo, linked directory, kickoff build — via a
genesis engine that swaps itself for a real session engine once the app
exists. Inside a linked directory it opens a session on that app instead.
TTY required; --json/non-TTY refuse with guidance.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
appConfigExists globs **/.app.jsonc recursively, so a parent directory of
several app dirs read as 'linked' and code crashed on init instead of
opening genesis mode. Detection is now try-initAppContext, falling back to
genesis when the cwd resolves to no project.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Re-rasterized as a 16x14 ellipse (x-radius 7.9 vs y 6.9) — terminal cells
run taller than 2:1, so the geometrically round version rendered narrow.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The session enables bracketed paste (mode 2004) — which also stops the
terminal's multi-line paste warning — and Ink reads stdin through a proxy
that strips the paste markers and flattens pasted newlines/tabs to spaces.
A multi-line paste lands as one editable line instead of a submit per line
with marker garbage. Sanitizer is pure and covered, including markers split
across chunks; typed Enter outside a paste is untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ayal and others added 29 commits September 16, 2026 08:15
…not circle+triangle

Matched to Logo_v5.png: a solid disc whose lower half is cut by thin horizontal
slits, so the bands shorten with the circle's curve — one mark, not a circle
plus a separate triangle of bars. Below the split each row draws on its top
pixel only (▀), leaving the gap beneath.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Split at the circle's centre so the top half is a solid sun and the bottom half
is exactly three shortening slit-bars; radius 6 makes it smaller.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…r sun, low stripe

Claude-Code-style header: the sun mark on the left with the title/account/cwd
lines stacked to its right, no box. Smaller sun (radius 5) with the single blank
stripe low in the circle.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds a server-side stop: chat/stop (branch-scoped) via engine.stopTurn(). Esc
stops when a turn is running; when nothing runs it still snaps to live. The
poller settles the stopped turn through the normal transcript path. Genesis
delegates to the inner engine (app creation isn't stoppable).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Footer now shows only the current model; drops the SessionView sessionStartedAt
prop (the session-end line keeps its own local timer).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bare http(s) URLs in agent text/results are wrapped as OSC 8 hyperlinks
(linkifyUrls) with a per-link id, and hardWrapAnsi now closes+reopens the active
OSC 8 link on every continuation row. So a URL split by the hard wrap re-emits
its full target on each row (same id) — ctrl/cmd-click opens the whole URL
instead of just the fragment up to the newline. Control bytes are built from
char codes to keep the source free of raw ESC/BEL.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds the known facts the agent otherwise rediscovers: dev command is `wix dev`
(wraps Astro) on port 3000; bind 0.0.0.0 + allow all hosts via astro.config.mjs
vite.server; first boot is slow (auth + content sync + type-gen) so use high
timeouts; and verify with curl, not the in-editor preview tools (unavailable for
imported apps here).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e agent stops looping

The big time-sink is the host allowlist: wix dev wraps astro dev, which empties
allowedHosts unless --allowed-hosts is passed, overriding astro.config. Tell the
agent the working command (wix dev --allowed-hosts .$BASE44_SANDBOX_HOST_DOMAIN),
the creds mount, node_modules-volume to avoid reinstall churn, and the right Host
header to verify with.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…verify trap

Binding and allowlist are different: astro binds localhost unless the TOP-LEVEL
server.host:true is set (vite.server.host is HMR-only and does not bind); the
allowlist needs --allowed-hosts on wix dev. And verify with a plain curl
localhost:3000 (200 = serving+bound) — the previous Host: 3000-<sandbox-id> hint
looped on 000 because there is no sandbox-id var.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ps 403ing create

My earlier additions (npx wix dev …, curl … -w %{http_code} http://…) were
command-shaped, which the edge WAF rejects in the create request body — exactly
what the file's own comment warns against. Reworded to config-key/prose form
(same guidance: top-level server.host to bind, allowed-hosts on the wix dev
command, creds mount, node_modules volume, 200-check verify). Verified the full
expanded prompt now passes the WAF (200, not a Blocked 403).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…th confusion

The skill scaffolds into a subfolder; leaving the app there while
docker-compose.base44.yml sits at the repo root is a split layout that makes
later turns cd into the wrong directory. Tell it to move the whole project to the
root (one flat layout), and only as a fallback keep compose inside the app
subfolder + record the dir in .base44/environment.json. Still prose (WAF-safe).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- session-engine: the poll re-entrancy guard was a plain boolean, so a wedged
  in-flight request blocked every future poll — the turn settled server-side but
  the UI stayed on Shmoozing/running with the timer ticking. Time-bound the guard
  (45s) so settle is still detected after a hung poll.
- /headless: moving the project to root made the agent delete+reinstall
  node_modules (slow, redundant — the compose service installs its own in a
  volume). Tell it to move as-is and not reinstall on the host.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…m root

Agents were operating from / (installed skills to /.agents, scaffolded to
/mutant-metropolis, then 'moved to repo root' = moved into /, which trashed the
container root and forced a recovery + reinstall). Spell out that the repo root
is /app: cd there first, scaffold under /app, and 'move to the repo root' means
into /app, never /.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ck-if-already-flat

The real failure is timing: fast-path starts the dep install and seed in the
background the instant it returns, in the scaffold subfolder; moving the folder
mid-install corrupts node_modules and forces a reinstall. Prose now: check if
fast-path already flattened to /app (don't double-move); else wait for BOTH
done-markers before moving, move as-is (no reinstall), into /app never /.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-safe)

Prefer the skill's --flatten scaffold flag (lands the project flat in /app;
older skill versions ignore it harmlessly) over the fragile hand-flatten; keep
the wait-for-done-markers timing net for when the flag isn't available yet.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…affolds --skip-git

Verified in the wix-cli source that the scaffold git-inits by default but honors
--skip-git; the skill's fast-path now passes it, so there is usually no nested
.git. Keep only a brief conditional cleanup note for the deploy-lag window.
fetch_website re-escapes the markdown (\> \*\* …), so the agent doesn't get an
exact copy. Ask for a raw curl fetch to a file. Phrased as prose (no command
syntax) so it doesn't trip the create-body WAF; verified create still passes.
Half-blocks only add vertical resolution, so the sun's sides came out jagged.
Switch to quadrant blocks (2x2 sub-pixels per cell) for smooth curved edges, and
use 2x sub-columns to correct the ~1:2 quadrant sub-cell aspect so it reads round,
not as a tall oval. Two knobs: LOGO_ROWS (size) and LOGO_GAP_SUBROW (stripe).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The tolerance over-filled the nearly-flat poles, bulging the top/bottom (▟▙ in the
middle of the top row). At radius 7 with an exact boundary the poles read as a
smooth arc.
…-through

The preview bridge's window.__base44_preview.navigate() default is SPA
client-routing; a Wix-Headless (astro MPA) app never emits the route-render
signal it waits for, so a plain navigate() hangs ~35s and reports the iframe
unresponsive. Tell the agent to move pages with navigate(path, { reload: true })
(a real load) and to verify with screenshots + non-navigating reads, not
click-to-navigate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…t for repos; reconnect link on expired GitHub

Genesis mode now picks the app type. `base44 code` (or --builder) creates a
normal user_app — the standard Base44 builder agent + React template — via
POST /api/apps with the first prompt as initial_message (no app_type: the
backend defaults to user_app; no imported repo fields). `base44 code --import`
keeps the imported flow (a fresh repo, or /headless → Wix Headless). The
session, stream, model picker and preview are shared: the chat and
sandbox/preview-url endpoints are app-type-agnostic. The active mode shows in
the header (a labelled line) and footer (a chip).

Also: when a create fails because the caller's GitHub OAuth token is expired
(a 401 from api.github.com while verifying repo access), both create paths now
print a clickable Reconnect-GitHub link (POST /api/github/oauth/initiate) instead
of a bare 401 — a plain retry just 401s again.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant