Commit 158a038
feat(local-mode): local-first developer experience with zero-ceremony setup (#2544)
* feat(local-mode): local-first developer experience with zero-ceremony setup
Running `bunx @decocms/mesh` (or `bun run dev`) now works with no config:
- Prompts for a data directory on first run (defaults to ~/deco/)
- Auto-generates and persists BETTER_AUTH_SECRET + ENCRYPTION_KEY
- Seeds an admin user from the OS username (e.g. viktor@localhost.mesh)
and a default "Viktor Local" org on fresh databases
- Auto-logs in the browser without a login form (MESH_LOCAL_MODE=true)
- Skips org selection and redirects straight to the first org
- Enables local filesystem object storage (/mcp/dev-assets) for assets
- Adds --home and --no-local-mode CLI flags; renames old dev to dev:saas
New files:
- apps/mesh/scripts/dev.ts — mirrors CLI setup for `bun run dev`
- apps/mesh/src/auth/local-mode.ts — seedLocalMode, getLocalAdminUser
- POST /api/auth/custom/local-session — auto-sign-in endpoint (local only)
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
* fix(local-mode): security hardening, UX improvements, and reliability fixes
- Generate random ENCRYPTION_KEY instead of empty string (cli.ts, dev.ts)
- Restrict secrets.json file permissions to 0o600 (cli.ts, dev.ts)
- Add non-TTY guard to prevent prompt() hang in Docker/CI (cli.ts)
- Normalize org slug from OS username to valid [a-z0-9-] (local-mode.ts)
- Retry auto-login on 5xx with exponential backoff (login.tsx)
- Always start with fresh chat on page load (use-task-manager.ts)
- Autofocus chat input on load (tiptap/input.tsx)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(chat): stabilize fresh-chat initializer across remounts
Use module-level UUID constant so the fresh-chat behavior is stable
within a session while still generating a new chat on each page load.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: resolve CI test and e2e failures
- Fix TS2345 errors: add non-null assertions for Hono route params
(threadId, toolName) that are always present in route patterns
- Respect MESH_LOCAL_MODE env var in dev.ts instead of hardcoding true
- Set MESH_LOCAL_MODE=false in e2e workflow so signup form is shown
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove unused getMeshHome export flagged by knip
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(local-mode): trusted origins, internal URLs, empty state, and title
- Add localhost:PORT to Better Auth trusted origins for proxy hostnames
- Add getInternalUrl() for server-to-server connections (mcp/self, dev-assets)
- Use BASE_URL in startup logs and CLI banner
- Simplify no-LLM empty state (remove tasks panel when no model connected)
- Change HTML title to "Deco Studio"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(studio): add @decocms/studio wrapper package for npm alias
Transitional package so `bunx @decocms/studio` works while the canonical
package remains @decocms/mesh. Includes local publish script and CI workflow
that auto-publishes with the same version as mesh.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(oauth): use localhost origin for redirect URIs behind proxy
External OAuth servers (e.g. OpenRouter MCP) reject .localhost subdomains
as redirect URIs. When running behind a proxy (tokyo.localhost → localhost:3000),
the OAuth flow now uses localhost:PORT for the redirect URI.
- Add setOAuthRedirectOrigin() to mesh-sdk for configuring redirect origin
- Expose internalUrl in /api/config public endpoint
- Set redirect origin from config on app init in ThemeProvider
- Accept cross-origin postMessage between .localhost variants in local dev
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: gate localhost trusted origin to local mode, restore package.json on failure
- Only add localhost:PORT to Better Auth trusted origins in local mode
- Add EXIT trap to studio publish script to restore package.json on failure
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(local-mode): security hardening and reliability improvements
- Restrict /local-session endpoint to loopback requests only (127.0.0.1/::1)
to prevent LAN access when server is bound to 0.0.0.0
- Fix tilde expansion in dev.ts and cli.ts: ~/dir was resolving to /dir
instead of $HOME/dir (slice(1) → slice(2) to skip the ~/)
- Gate local-session behind seed completion to prevent 500s on race
- Respect user-provided DATABASE_URL in CLI instead of always overwriting
- Add security comment documenting that loopback check (not password)
is the security boundary for local-mode auto-login
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(tests): update OAuth callback tests for cross-origin postMessage
Update test mocks to include hostname/port/protocol on window.location
and adjust assertion for postMessage target origin ("*" in local dev).
Also add DEBT.md tracking technical debt for local-first DX work.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(local-mode): use socket-level IP check and fix tilde expansion
- Replace spoofable X-Forwarded-For header check with Bun's getConnInfo()
(socket-level requestIP) for the local-session loopback guard
- Pass Bun server as env to Hono so getConnInfo can access requestIP
- Fix tilde expansion: only expand bare ~ and ~/path, not ~user inputs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(studio): rename package to decocms with deco CLI command
Publish as `decocms` on npm so users can run `npx decocms` or
`npm i -g decocms && deco`. Renamed bin from studio.js to deco.js
and updated CI workflow, publish script, README, and DEBT.md.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs(studio): update decocms README and package metadata for npm
Replace internal wrapper docs with a proper product README showing
features, quick start, and MCP client config. Add descriptive keywords
and update main README to reference `npx decocms`.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(config): only expose internalUrl in local mode
Production deployments don't need the localhost URL in /api/config.
Gate it behind isLocalMode() so it's only sent when running locally
behind a proxy (e.g. tokyo.localhost).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove unused getBaseUrl import in org.ts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs(studio): align README with decocms.com/studio positioning
Rewrite to lead with agents and tools, not just MCP plumbing.
Matches the landing page: hire agents, connect 50+ integrations,
track costs, run locally or scale to teams.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: ignore decocms runtime dependency in knip config
@decocms/mesh is resolved via require() in bin/deco.js at runtime,
which knip can't trace. Add ignoreDependencies for packages/studio.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: rebrand CLI and docs from @decocms/mesh to npx decocms / deco
Update all user-facing references: CLI help text, release workflow,
docs quickstart pages (en + pt-br), dev script comment, and OAuth
client name to use "Deco Studio" / "npx decocms" / "deco".
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(studio): use bun runtime in deco CLI wrapper
The built CLI uses Bun APIs (Bun.file, Bun.serve), so the wrapper
must run it with bun, not node. Auto-detects bun availability.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: rebrand CLI banners from MCP Mesh to Deco Studio
Update startup banners, prompts, and subtitle in cli.ts and dev.ts
to show "Deco Studio" instead of "MCP Mesh".
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(studio): require bun runtime and update instructions to bunx
The built CLI uses Bun APIs so bun is a hard requirement. Show a
clear error with install instructions if bun is missing. Update all
docs, CLI help, README, and release workflow from npx to bunx.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(docs): align section headings with bunx commands
Update "(npx)" headings to "(bunx)" in quickstart docs and change
"Install via npm" to "Install via Bun" in release workflow to match
the actual bunx decocms commands.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(dev): respect existing DATABASE_URL and fix path resolution
- Use nullish coalescing for DATABASE_URL to not override user-provided
values (e.g., PostgreSQL connection strings), matching cli.ts behavior
- Replace brittle string replace with join(import.meta.dir, "..") for
cross-platform path handling
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: harden local-first DX — random password, seed gate, postMessage, prod guard
- Extract shared bootstrap module (scripts/bootstrap.ts) from cli.ts and dev.ts
- Generate per-install LOCAL_ADMIN_PASSWORD in secrets.json instead of hardcoded value
- Fix seed gate: resolve immediately when not in local mode (prevents hang)
- Add .catch() to dynamic import chain in index.ts
- Tighten postMessage target from "*" to getOAuthRedirectOrigin()
- Refuse local mode in production (NODE_ENV=production) unless explicitly overridden
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: security hardening, OAuth flow extraction, and deferred debt tracking
- Remove hardcoded "admin@mesh" fallback password — throw on missing secrets.json
- Fix seed gate hang when local-mode module import fails (markSeedComplete in catch)
- Fix directory traversal in sanitizeKey() — use path.resolve() + containment check
- Unify DEV_ASSETS_BASE_DIR to use MESH_HOME in both dev-assets files
- Use crypto.timingSafeEqual() for HMAC signature verification
- Remove production console.log leaking taskId on every stream resume
- Cherry-pick OAuth flow extraction from feat/oauth-flow-extraction
- Update DEBT.md with deferred review issues from merged PRs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: explicit MESH_ALLOW_LOCAL_PROD check and postMessage target for proxy setups
- Use `!== "true"` instead of truthiness check for MESH_ALLOW_LOCAL_PROD
to prevent unintended bypass with values like "false"
- Use "*" as postMessage target in local dev so OAuth callbacks work
behind proxies where opener origin differs from redirect origin
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(local-mode): probe ~/deco for secrets.json when MESH_HOME is unset
getLocalAdminPassword() now checks the default ~/deco directory as a
fallback when MESH_HOME is not set. This fixes auto-login when running
via `bun run dev:server` directly (which doesn't set MESH_HOME), while
still refusing to use a hardcoded credential.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(dev): check non-interactive before defaultPath existence in resolveMeshHome
Swap the order so CI/non-TTY environments always use the CI-safe
.mesh-dev path, even when ~/deco exists from a prior local run.
Previously, existsSync(~/deco) was checked first, causing CI on
shared runners to use the developer's real data directory.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: rename system prompt identity from "decopilot" to "Deco Pilot"
The LLM was self-identifying as "decoCopilot" which reads as "decoco"
in Portuguese. Use properly spaced "Deco Pilot" and "Deco Studio".
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Guilherme Rodrigues <gui@deco.cx>1 parent 7ed212a commit 158a038
49 files changed
Lines changed: 1687 additions & 308 deletions
File tree
- .github/workflows
- apps
- docs/client/src/content
- draft
- en/mcp-mesh/self-hosting
- pt-br
- mcp-mesh
- latest
- en
- mcp-mesh
- pt-br
- mcp-mesh
- mesh
- scripts
- src
- api
- routes
- decopilot
- auth
- core
- database
- web
- components
- chat
- task
- tiptap
- details/connection
- lib
- providers
- routes
- orgs/home
- packages
- mesh-sdk/src
- lib
- studio
- bin
- scripts
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
36 | 36 | | |
37 | 37 | | |
38 | 38 | | |
| 39 | + | |
| 40 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
143 | 143 | | |
144 | 144 | | |
145 | 145 | | |
146 | | - | |
| 146 | + | |
147 | 147 | | |
148 | | - | |
| 148 | + | |
149 | 149 | | |
150 | | - | |
| 150 | + | |
151 | 151 | | |
152 | | - | |
| 152 | + | |
153 | 153 | | |
154 | | - | |
| 154 | + | |
155 | 155 | | |
156 | 156 | | |
157 | 157 | | |
| |||
175 | 175 | | |
176 | 176 | | |
177 | 177 | | |
178 | | - | |
| 178 | + | |
179 | 179 | | |
180 | 180 | | |
181 | 181 | | |
182 | | - | |
| 182 | + | |
183 | 183 | | |
184 | 184 | | |
185 | 185 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
61 | 61 | | |
62 | 62 | | |
63 | 63 | | |
64 | | - | |
| 64 | + | |
65 | 65 | | |
66 | 66 | | |
67 | 67 | | |
| |||
Lines changed: 2 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
13 | | - | |
| 13 | + | |
14 | 14 | | |
15 | 15 | | |
16 | | - | |
| 16 | + | |
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
28 | | - | |
| 28 | + | |
29 | 29 | | |
30 | 30 | | |
31 | | - | |
| 31 | + | |
32 | 32 | | |
33 | 33 | | |
34 | 34 | | |
| |||
Lines changed: 2 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
13 | | - | |
| 13 | + | |
14 | 14 | | |
15 | 15 | | |
16 | | - | |
| 16 | + | |
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
29 | | - | |
| 29 | + | |
30 | 30 | | |
31 | 31 | | |
32 | | - | |
| 32 | + | |
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
| |||
Lines changed: 2 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
13 | | - | |
| 13 | + | |
14 | 14 | | |
15 | 15 | | |
16 | | - | |
| 16 | + | |
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
| |||
0 commit comments