Conversation
Build Base44 apps from the terminal — the minimum shippable slice. Non-interactive atoms under `base44 app`: `new` (a prompt → template app, or --import <repo> over an existing GitHub repo), `send`, `status`, `preview`, `stop`. Each is a Base44Command reusing prod plumbing (--app/linked-dir resolution, --branch, global --json) and hits existing backend endpoints — no apper changes. Atoms are branch-aware: an imported app works on its setup branch and a request with no branch targets main, so the active branch is resolved and stamped on send/status/stop. `app new` shows a live spinner while the sandbox provisions (silent under --json). Interactive `base44 code`: a full-screen Ink session, isolated under commands/code and composed from the same createAndLinkApp helper the atoms use. In an empty dir the first prompt creates the app (--import <repo> for a repo); in a linked dir it reopens the app. Enter sends, Esc stops the turn server-side, arrows scroll. No slash commands. Shared layer core/resources/apps: create (builder | import), send, status, preview, stop, branch resolution, GitHub re-auth link, and the poll-and-diff conversation stream. Deps for the Ink session: ink, ink-text-input, react (+ @types/react), jsx react-jsx, and a bun plugin stubbing Ink's dev-only react-devtools import. bun.lock updated. Tests: tests/cli/app.spec.ts covers the atoms; tests/core/stream.spec.ts the stream. Full suite green. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Account-wide model selection on the existing backend contract: `GET /api/auth/me`
reads the saved pick, `POST /api/auth/{id}/update-user` writes it, and the
`X-Builder-Model-Selection: user-v1` request header makes the backend honor it
(the web editor's contract — safe with no pick, it falls back to the app
default). Gated server-side by PER_USER_BUILDER_MODEL_SELECTION; a 400 on save
surfaces as a clear "this account can't pick a model" error.
`base44 app model` lists the catalog with the current pick (--json returns
{current, models}); `app model <name>` resolves a name/id loosely and saves it;
`default` clears it. In the interactive session, `/model` opens an
arrow-navigable picker (Enter selects, Esc cancels), `/model <name>` switches
directly, and the current pick shows in the footer.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A local install on the Wix VPN rewrote every bun.lock tarball URL to an explicit https://npm.dev.wixpress.com/... address. CI resolves only the default registry (registry.npmjs.org, pinned to the embargo gateway), so the newly added Ink/React entries failed with DNSResolveFailed; the pre-existing ones only installed from the restored bun cache. Restore main's shape: "" (registry default) on every entry, main's exact @deno/loader line, and only the additions bun made for ink, ink-text-input, react and @types/react. Versions and sha512 integrity are unchanged; a frozen-lockfile install from a clean checkout succeeds. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Contributor
🚀 Package Preview Available!Install this PR's preview build with npm: npm i @base44-preview/cli@0.1.15-pr.630.30a3a78Prefer not to change any import paths? Install using npm alias so your code still imports npm i "base44@npm:@base44-preview/cli@0.1.15-pr.630.30a3a78"Or add it to your {
"dependencies": {
"base44": "npm:@base44-preview/cli@0.1.15-pr.630.30a3a78"
}
}
Preview published to npm registry — try new features instantly! |
…pplies
Ink imports react-devtools-core, an optional peer we do not ship, from a
module that only loads under DEV=true. The dist build already replaces it
with an inert stub via a bundler plugin, but the standalone binaries were
compiled by spawning the bun CLI, which has no plugin hook, and failed to
resolve the package. Marking it external is not an option: the compiled
binary hoists the import and exits at startup with "Cannot find package".
Move the externals list and the stub into infra/bundle.ts and compile the
binaries with Bun.build({ compile }) using both, keeping the Windows-host
icon rule. Verified: the darwin-arm64 binary builds and runs --version and
app --help.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
knip flagged ten symbols exported from the new app/code modules that are only used inside their own files. Keep them module-private. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Both commands create ./<app-name>/ under the current directory, and the only hint was a "Next: cd" suffix on the outro (app new) or nothing at all (code). Print one shared block at the end of both: the directory, and the cd + base44 code / base44 app send lines to pick the app up again. The genesis session also keeps "dir ./<name>" in its footer for the whole run, a linked-directory session prints its project root on exit, and app new --json gains dir and path. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The first entry is "Automatic — matched with the best model", as the web
picker names it, with `default` and `auto` accepted as typed aliases;
Gemini 3.8 Flash reads "fast responses for everyday tasks" instead of an
invented "fast". Fable 5 already matched ("uses more credits").
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Align with `base44 create`: when the current directory is empty it is the
project — link it and name the app after the folder; otherwise create
./<name> as before. `--path <dir>` on both commands picks the directory
explicitly (and names the app after it unless --name is given). Every
label, the next-steps block, the session footer and the --json `dir`
("." when linked here) follow the same rule.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- `base44 app` becomes `base44 builder` (new, send, status, stop, model): the group names the counterpart you talk to, next to `sandbox` and the prod `agents` group. - `preview` moves to `sandbox preview`; it reads the sandbox preview URL. - `code` and `builder send` refuse a code-first project (base44 create, is_managed_source_code=false) and a Superagent, naming the app kind and what to run instead. - `code --app-id <id>` opens that app from anywhere; help and the idle hint name --app-id and `base44 link` as the ways to attach to an existing app. - Session chips name the app kind from its state (web app, game, mobile app, slides) or show the repository for apps built over one; "Import" is no longer used as a label. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Port of `circle.py -d 6 --gap 3.5r --gap-height=0.8r`: a supersampled disc in sub-cell block glyphs, aspect-corrected, with a thin slot centred on row 4. Octant-capable terminals (ghostty, kitty, wezterm, foot, contour) get the 2x4 tier with circle.py's fitted table; everything else gets quadrant blocks. Fully covered cells are painted as background so fonts whose blocks stop short of the line height don't stripe the fill. Golden tests pin both tiers to the script's exact output. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The input box and model picker were capped at 100 columns while the transcript already wrapped to the full width. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Build Base44 apps from the terminal. This adds five non-interactive
base44 buildercommands (create, send a turn, status, stop, pick the model),base44 sandbox preview, and an interactivebase44 codesession, all built on one shared resource layer. Everything hits existing backend endpoints — no apper changes.What it looks like
base44 codein an empty directory, before the first prompt — the rendered mark, the account, the directory, the kind of app:The same session a few minutes into the first build — tool results as they land, the agent's current thought, the tool in flight, and the footer chips:
Layout
program.tsregistersbuilderandcode; the existingsandboxgroup gainspreview.base44-client.tsadds one request header,X-Builder-Model-Selection: user-v1, so the backend honors the saved model pick (the web editor's contract; with no pick it falls back to the app default).Command reference
Every command and flag this PR adds. Globals from the existing CLI apply where marked:
--json(machine output on stdout),--app-id <id>(alsoBASE44_APP_ID; otherwise the linked directory),--branch <name>where a command is branch-aware.base44 builder new [prompt]--import <repo>build over an existing GitHub repository ·--mode <direct|fork|copy>how to import (defaultdirect) ·--repo-name <name>name for the new repo when forking/copying ·--from-branch <name>import a specific branch ·--name <name>directory and app name (invented when omitted) ·--path <dir>directory to link (default: the current directory when empty, else./<name>)--jsonbase44 builder send <message>{"queued":true}when the agent is busy--json·--app-id·--branchbase44 builder status--json·--app-idbase44 builder stop--app-id·--branchbase44 builder model [model]Automatic/default/autoclears the pick)--jsonbase44 sandbox preview--json·--app-idbase44 code--import <repo>·--path <dir>·--app-id <id>opens that app from anywhereInside
base44 code: Enter sends · Esc stops the running turn, or snaps back to live when scrolled · ↑/↓ · PgUp/PgDn scroll the transcript · Ctrl+C clears the input, then exits · Ctrl+D exits ·/modelopens the picker,/model <name>switches directly.builder sendandcoderefuse a code-first project (base44 create) and a Superagent;--mode,--repo-nameand--from-branchare refused without--import;--importand--pathare refused inside a linked directory.Non-interactive —
base44 builderWhere the app lands (same rule as
base44 create): an empty current directory is the project itself and names the app; otherwise./<name>/is created.--path <dir>picks the directory explicitly.builder newand a genesisbase44 codesession share this, and both end by printing the directory and thecd … && base44 codeline to pick the app up again. The block also says the app's files live remotely (base44 sandbox lsto look,base44 ejectfor a copy) — a linked directory is a handle, likebase44 link, not a checkout.Each command is a
Base44Command, so it gets the existing plumbing for free:--app-id <id>/ linked-dir resolution,--branch, and the global--json.Only builder-managed apps.
builder send(andcode) first read the app and refuse two kinds with a one-line message: a code-first project (base44 create,is_managed_source_code: false, where you own the source and a turn would edit a copy nobody sees) and a Superagent (user_agent, which has no builder conversation).builder new— create an app and start its first build. A prompt makes a template app;--import <repo>builds over an existing GitHub repo.Without
--jsonit shows a live spinner while the sandbox provisions, then streams the agent's tool calls, printsrepo/editor/linked ./<dir>, then the preview URL. Flags:--import <repo>,--mode direct|fork|copy,--name,--repo-name,--from-branch. Inputs are validated before any API call.builder send— one agent turn; blocks until it finishes and streams it.builder status·sandbox preview·builder stopbuilder model— pick the builder model for your turns, account-wide. No argument lists the catalog and the current pick;defaultclears it.Branch-aware by design
A request with no branch targets
main— right for a template app. An app built over a repo works on its setup branch, sosend/status/stopresolve it and stamp it, or they'd silently hit the wrong line:sequenceDiagram participant CLI as base44 builder send participant BE as backend (existing endpoints) CLI->>BE: GET /api/apps/{id}/branches BE-->>CLI: [setup branch] — or [] for a template app CLI->>BE: POST chat/message?branch_id=… (none → main) BE-->>CLI: turn outcomeInteractive —
base44 codeA full-screen Ink session, composed from the same helper the atoms use — there is one create path, not two. The header mark is rendered, not hand-drawn: a supersampled, aspect-corrected disc in sub-cell block glyphs with a thin slot, octant glyphs on terminals that draw them and quadrant blocks elsewhere (
code/logo.ts, pinned by golden tests).In a linked directory it reopens that app's session;
base44 code --app-id <id>opens any app from anywhere, andbase44 linkattaches a directory to an existing app (the help text and the idle hint name both). The footer chip names the kind of app from its state —web app,game,mobile app,slides— or shows the repository for an app built over one; "import" is never used as a label. In-session: Enter sends, Esc stops the running turn (server-side), arrows/PgUp/PgDn scroll, Ctrl+C/D exit. The mode shows in the header line and a footer chip./modelopens an arrow-navigable model picker (/model <name>switches directly); the current pick shows in the footer.Dependencies added — flagged for review
For the Ink session:
ink,ink-text-input,react(+@types/react);"jsx": "react-jsx"intsconfig.json; a small bun plugin ininfra/build.tsstubbing Ink's dev-onlyreact-devtoolsimport so the bundle builds;knip.jsonscans.tsx.bun.lockupdated.Lockfile — flagged for review.
bun.lockgains only the entries for these four packages and their tree, recorded in registry-default form (""URL) like every existing entry; bun also re-nests the olderstring-width/wrap-ansifamily undercliui,yargs,@inquirer/coreandmsw. Versions and sha512 integrity are unchanged.Build.
infra/bundle.tsowns the runtime externals list and a bundler plugin that stubs Ink's dev-onlyreact-devtools-coreimport. Standalone binaries now compile throughBun.build({ compile })instead of spawningbun build --compile, so the same stub applies to them (marking the package external is not enough: the binary hoists the import and exits at startup).Tests
tests/cli/builder.spec.ts(16): template create → settled turn → preview; create over a repository; empty-directory and--pathlinking; input validation;sendbranch-scoping + queued;sendrefuses a code-first project and a Superagent;status,sandbox preview,stop;modellist, set, anddefault;coderefuses without a TTY.tests/core/stream.spec.ts(18): the poll-and-diff stream.bunbuild OK.Caveat — the agent's preview-verification tools need the editor open
Not specific to either flow. The agent's
preview_screenshot/preview_execute_codeare tab-bound: the backend sends a command into the app's socket room and waits for the preview iframe's builder-bridge, and the relay connecting them runs in the web editor tab. Driving the agent from the terminal with no editor open → those tools returniframe_unavailable, for both template and repo apps.The agent still builds fine from the terminal; only its "look at the running app" step depends on the editor. Building over a repo additionally needs the
IMPORTED_APPSfeature flag on the user, and model picking needsPER_USER_BUILDER_MODEL_SELECTION— both existing gates.Next steps — not part of this PR
Listed so the line is explicit; none of this ships here.
T2 — CLI
--clonefor apps built over a repository: clone into the linked directory on the setup branch, so git is the pull/push pair. Thenbuilder commit/builder pr(refused on template apps).agents chat <name> "<msg>"andagents conversationsunder the existingagentsgroup — the runtime endpoint answers synchronously and accepts the platform token. A/agentslash incodedecided after.superagent chat | conversations— same shape, separate product; needs its owner and a confirmation story for side effects.builder open <id>or a picker incodereusinglink's app list; show recent history on attach; handle several active branches instead of falling back tomain.claude -pstyle: when stdout is not a TTY, the reply goes to stdout and progress to stderr (today settled tool lines go to stdout and the reply is not printed);--stream-jsonfor NDJSON events with a final envelope; exit codes reflecting the final status and--timeoutonbuilder newandbuilder send./api/auth/me(feature_flags) at the start ofbuilder new,builder sendandcode, failing with one line that names it — the same list the web client uses; one newFeatureFlagon apper.ink-text-input(TODO insession.tsx).T3 — CLI
sandboxfile commands, with checkpoints — the prerequisite for anycreate --promptthat brings files onto disk.Apper
is_managed_source_code: false), or the editor hides it for them — the CLI guards its side only.github_reauth_requirederror carrying the reconnect URL (replacing the CLI's string match).BACKEND_URL.🤖 Generated with Claude Code