Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
91a2332
feat(local-mode): local-first developer experience with zero-ceremony…
viktormarinho Mar 2, 2026
c1d7d56
fix(local-mode): security hardening, UX improvements, and reliability…
vibegui Mar 4, 2026
6166f86
fix(chat): stabilize fresh-chat initializer across remounts
vibegui Mar 4, 2026
546b73e
fix: resolve CI test and e2e failures
vibegui Mar 4, 2026
46ddee0
fix: remove unused getMeshHome export flagged by knip
vibegui Mar 4, 2026
ca6303a
fix(local-mode): trusted origins, internal URLs, empty state, and title
vibegui Mar 5, 2026
f13042e
feat(studio): add @decocms/studio wrapper package for npm alias
vibegui Mar 5, 2026
58d0349
fix(oauth): use localhost origin for redirect URIs behind proxy
vibegui Mar 5, 2026
144b7ac
fix: gate localhost trusted origin to local mode, restore package.jso…
vibegui Mar 5, 2026
aaea0c4
fix(local-mode): security hardening and reliability improvements
vibegui Mar 5, 2026
a42b778
fix(tests): update OAuth callback tests for cross-origin postMessage
vibegui Mar 5, 2026
a587bfa
fix(local-mode): use socket-level IP check and fix tilde expansion
vibegui Mar 5, 2026
29471e5
feat(studio): rename package to decocms with deco CLI command
vibegui Mar 5, 2026
7e0cf03
docs(studio): update decocms README and package metadata for npm
vibegui Mar 5, 2026
1fc227e
fix(config): only expose internalUrl in local mode
vibegui Mar 5, 2026
2de9069
fix: remove unused getBaseUrl import in org.ts
vibegui Mar 5, 2026
d67c7dc
docs(studio): align README with decocms.com/studio positioning
vibegui Mar 5, 2026
3ae22ab
fix: ignore decocms runtime dependency in knip config
vibegui Mar 5, 2026
7a63ed7
chore: rebrand CLI and docs from @decocms/mesh to npx decocms / deco
vibegui Mar 5, 2026
cbfe8a4
fix(studio): use bun runtime in deco CLI wrapper
vibegui Mar 5, 2026
435c4eb
chore: rebrand CLI banners from MCP Mesh to Deco Studio
vibegui Mar 5, 2026
66b6c13
fix(studio): require bun runtime and update instructions to bunx
vibegui Mar 5, 2026
982eebf
fix(docs): align section headings with bunx commands
vibegui Mar 5, 2026
89fb8ed
fix(dev): respect existing DATABASE_URL and fix path resolution
vibegui Mar 5, 2026
7cecc73
fix: harden local-first DX — random password, seed gate, postMessage,…
vibegui Mar 5, 2026
fd0ce93
fix: security hardening, OAuth flow extraction, and deferred debt tra…
vibegui Mar 5, 2026
3f19c45
fix: explicit MESH_ALLOW_LOCAL_PROD check and postMessage target for …
vibegui Mar 5, 2026
8dd9079
fix(local-mode): probe ~/deco for secrets.json when MESH_HOME is unset
vibegui Mar 5, 2026
61d02a2
fix(dev): check non-interactive before defaultPath existence in resol…
vibegui Mar 5, 2026
327e1b4
fix: rename system prompt identity from "decopilot" to "Deco Pilot"
vibegui Mar 5, 2026
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
2 changes: 2 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ jobs:

- name: Run e2e tests
run: bun run test:e2e
env:
MESH_LOCAL_MODE: "false"
74 changes: 74 additions & 0 deletions .github/workflows/publish-studio-npm.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: Publish decocms

on:
push:
branches: [main]
paths:
- "apps/mesh/package.json"
- "packages/studio/**"
workflow_dispatch:

jobs:
publish:
name: Publish to npm
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "24"
registry-url: "https://registry.npmjs.org"

- name: Read mesh version
id: mesh-version
run: |
VERSION=$(node -e "console.log(require('./apps/mesh/package.json').version)")
echo "version=$VERSION" >> $GITHUB_OUTPUT

if [[ "$VERSION" == *-* ]]; then
echo "npm-tag=next" >> $GITHUB_OUTPUT
else
echo "npm-tag=latest" >> $GITHUB_OUTPUT
fi

echo "📦 @decocms/mesh version: $VERSION"

- name: Check if already published
id: check
run: |
VERSION=${{ steps.mesh-version.outputs.version }}
if npm view "decocms@$VERSION" version >/dev/null 2>&1; then
echo "skip=true" >> $GITHUB_OUTPUT
echo "⏭️ decocms@$VERSION already published"
else
echo "skip=false" >> $GITHUB_OUTPUT
echo "✅ Will publish decocms@$VERSION"
fi

- name: Patch studio package.json
if: steps.check.outputs.skip == 'false'
run: |
VERSION=${{ steps.mesh-version.outputs.version }}
cd packages/studio
node -e "
const pkg = require('./package.json');
pkg.version = '$VERSION';
pkg.dependencies['@decocms/mesh'] = '$VERSION';
require('fs').writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
"
echo "✅ Patched to v$VERSION"
cat package.json

- name: Publish to npm
if: steps.check.outputs.skip == 'false'
run: npm publish --access public --tag ${{ steps.mesh-version.outputs.npm-tag }} --provenance
working-directory: packages/studio
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
14 changes: 7 additions & 7 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -143,15 +143,15 @@ jobs:
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ steps.version-check.outputs.current-version }}
name: "@decocms/mesh v${{ steps.version-check.outputs.current-version }}"
name: "Deco Studio v${{ steps.version-check.outputs.current-version }}"
body: |
## MCP Mesh v${{ steps.version-check.outputs.current-version }}
## Deco Studio v${{ steps.version-check.outputs.current-version }}

Self-hostable Virtual MCP for managing AI connections and tools.
Open-source control plane for your AI agents.

### Install via npm
### Install via Bun
```bash
bunx @decocms/mesh@${{ steps.version-check.outputs.current-version }}
bunx decocms@${{ steps.version-check.outputs.current-version }}
```

### Install via Docker
Expand All @@ -175,11 +175,11 @@ jobs:
run: |
echo "## Release Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "🎉 **@decocms/mesh v${{ steps.version-check.outputs.current-version }} Released**" >> $GITHUB_STEP_SUMMARY
echo "🎉 **Deco Studio v${{ steps.version-check.outputs.current-version }} Released**" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### npm" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
echo "bunx @decocms/mesh@${{ steps.version-check.outputs.current-version }}" >> $GITHUB_STEP_SUMMARY
echo "bunx decocms@${{ steps.version-check.outputs.current-version }}" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Docker" >> $GITHUB_STEP_SUMMARY
Expand Down
98 changes: 98 additions & 0 deletions DEBT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Technical Debt — Local-First DX

Items to address after the core local-first DX lands.

## NATS onboarding in local mode

The agentic onboarding flow should detect whether NATS is available and, if not,
offer to install and start it (via `brew install nats-server` or Docker). NATS
enables stream recovery (switch tabs / refresh → restore in-progress AI
responses). Without it, `NoOpStreamBuffer` is used and late-join replay is
disabled.

- Relevant code: `apps/mesh/src/api/app.ts` (NATS_URL detection),
`apps/mesh/src/api/routes/decopilot/stream-buffer.ts` (NoOpStreamBuffer fallback)

## decocms package rename

`packages/studio/` publishes as `decocms` on npm (`bunx decocms` / `deco` CLI).
It's a thin wrapper that depends on `@decocms/mesh`. Eventually the source
should move to `decocms` as the canonical package and `@decocms/mesh` becomes
the wrapper (or is deprecated).

## Playwright e2e excluded from `bun test`

The Playwright e2e test (`apps/mesh/src/**/*.e2e.test.ts`) is picked up by
`bun test` and fails because `@playwright/test` conflicts with bun's test
runner. Should be excluded via bun test config or file naming convention.

---

## Items from PR review (deferred — belong to already-merged PRs)

### PROJECT_PINNED_VIEWS_UPDATE missing org ownership check (PR #2567)

The tool calls `requireAuth(ctx)` + `ctx.access.check()` but does not call
`requireOrganization(ctx)` or validate `project.organizationId !== organization.id`.
An authenticated user from org A could update pinned views on org B's project.

- File: `apps/mesh/src/tools/projects/pinned-views-update.ts`

### N+1 query in PROJECT_CONNECTION_LIST (PR #2567)

Each connection is fetched individually via `findById` inside `Promise.all(map(...))`.
No `findByIds` batch method exists on `ConnectionStorage`.

- Fix: Add `findByIds(ids: string[])` using `WHERE id IN (...)`
- File: `apps/mesh/src/tools/projects/connection-list.ts:52-56`

### COLLECTION_CONNECTIONS_GET write side-effect in readOnly tool (PR #2567)

The GET handler (annotated `readOnlyHint: true`) backfills missing tools via
`fetchToolsFromMCP` with a 2s timeout and calls `ctx.storage.connections.update()`.
A read operation should not have write side-effects.

- Fix: Move backfill to an explicit tool or post-OAuth event trigger
- File: `apps/mesh/src/tools/connection/get.ts`

### TaskStreamManager useSyncExternalStore misuse (PR #2563)

`subscribe` is a new function reference every render, causing interval leaks.
`useSyncExternalStore` is used as a lifecycle hook rather than for external store
subscription, which is semantically incorrect under React 19.

- Fix: Stabilize `subscribe` via `useRef` or restructure
- File: `apps/mesh/src/web/components/chat/context.tsx`

### ResizeObserver memory leak in monitoring dashboard (PR #2554)

Inline ref callback creates a new `ResizeObserver` on every render without
disconnecting the old one. Use React 19 ref callback cleanup:
`return () => observer.disconnect();`

- File: monitoring dashboard component (TBD exact location)

### Monitoring fetches 2000 raw rows to browser (PR #2554)

Dashboard fetches 2000 full `MonitoringLog` rows (including `input`/`output` JSON)
to the browser for client-side bucketing. Only 5 scalar fields are needed.

- Fix: Push aggregation server-side or add field projection to `MONITORING_LOGS_LIST`
- File: `apps/mesh/src/web/components/monitoring/hooks.ts:37`

### ondownloadfile handler should validate URI scheme (PR #2571)

`window.open(item.uri, "_blank")` accepts arbitrary URIs including `javascript:`.
Validate scheme is `http:` or `https:` before calling `window.open`.

- File: `apps/mesh/src/mcp-apps/use-app-bridge.ts`

### Thread/Task naming asymmetry

UI uses "task" but backend protocol uses "thread" everywhere (`COLLECTION_THREADS_LIST`,
`thread_id`, etc.). Either rename fully or document the mapping explicitly.

### Large component files should be split

- `apps/mesh/src/web/components/settings-modal/pages/org-billing.tsx` (1,732 lines)
- `apps/mesh/src/web/routes/orgs/monitoring.tsx` (1,510 lines)
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ bun run dev

→ runs at [http://localhost:3000](http://localhost:3000) (client) + API server

Or use `npx @decocms/mesh` to instantly get a mesh running.
Or use `bunx decocms` to instantly get a mesh running.

---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import Callout from "../../../../../components/ui/Callout.astro";

Pick one:

### Option A: one-command local setup (npx)
### Option A: one-command local setup (bunx)

```bash
npx @decocms/mesh
bunx decocms
```

### Option B: local setup with Docker Compose
Expand Down
4 changes: 2 additions & 2 deletions apps/docs/client/src/content/draft/pt-br/introduction.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ Se você conheceu a gente antes, como **deco.cx**, e está buscando **headless C

Escolha uma opção:

### Opção A: setup local com um comando (npx)
### Opção A: setup local com um comando (bunx)

```bash
npx @decocms/mesh
bunx decocms
```

### Opção B: setup local com Docker Compose
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import Callout from "../../../../components/ui/Callout.astro";

Escolha uma opção:

### Opção A: setup local com um comando (npx)
### Opção A: setup local com um comando (bunx)

```bash
npx @decocms/mesh
bunx decocms
```

### Opção B: setup local com Docker Compose
Expand Down
4 changes: 2 additions & 2 deletions apps/docs/client/src/content/latest/en/introduction.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ If you know us from before (as **deco.cx**) and you’re looking for **headless

Choose one:

### Option A: one-command local setup (npx)
### Option A: one-command local setup (bunx)

```bash
npx @decocms/mesh
bunx decocms
```

### Option B: local setup with Docker Compose
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import Callout from "../../../../components/ui/Callout.astro";

Pick one:

### Option A: one-command local setup (npx)
### Option A: one-command local setup (bunx)

```bash
npx @decocms/mesh
bunx decocms
```

### Option B: local setup with Docker Compose
Expand Down
4 changes: 2 additions & 2 deletions apps/docs/client/src/content/latest/pt-br/introduction.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ Se você conheceu a gente antes, como **deco.cx**, e está buscando **headless C

Escolha uma opção:

### Opção A: setup local com um comando (npx)
### Opção A: setup local com um comando (bunx)

```bash
npx @decocms/mesh
bunx decocms
```

### Opção B: setup local com Docker Compose
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import Callout from "../../../../components/ui/Callout.astro";

Escolha uma opção:

### Opção A: setup local com um comando (npx)
### Opção A: setup local com um comando (bunx)

```bash
npx @decocms/mesh
bunx decocms
```

### Opção B: setup local com Docker Compose
Expand Down
3 changes: 3 additions & 0 deletions apps/mesh/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ coverage/
# Temporary files
/tmp/

# Dev/test local data directory
.mesh-dev/



# Authentication tokens
Expand Down
2 changes: 1 addition & 1 deletion apps/mesh/index.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>MCP Mesh</title>
<title>Deco Studio</title>
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
</head>
<body>
Expand Down
3 changes: 2 additions & 1 deletion apps/mesh/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
"dist/**/*"
],
"scripts": {
"dev": "bun run migrate && concurrently \"bun run dev:client\" \"bun run dev:server\"",
"dev": "bun run scripts/dev.ts",
"dev:saas": "bun run migrate && concurrently \"bun run dev:client\" \"bun run dev:server\"",
"dev:client": "bun --bun vite dev",
"dev:server": "NODE_ENV=development bun --env-file=.env --hot run src/index.ts",
"build:client": "bun --bun vite build",
Expand Down
Loading