-
Notifications
You must be signed in to change notification settings - Fork 40
feat(local-mode): local-first developer experience with zero-ceremony setup #2544
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
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 c1d7d56
fix(local-mode): security hardening, UX improvements, and reliability…
vibegui 6166f86
fix(chat): stabilize fresh-chat initializer across remounts
vibegui 546b73e
fix: resolve CI test and e2e failures
vibegui 46ddee0
fix: remove unused getMeshHome export flagged by knip
vibegui ca6303a
fix(local-mode): trusted origins, internal URLs, empty state, and title
vibegui f13042e
feat(studio): add @decocms/studio wrapper package for npm alias
vibegui 58d0349
fix(oauth): use localhost origin for redirect URIs behind proxy
vibegui 144b7ac
fix: gate localhost trusted origin to local mode, restore package.jso…
vibegui aaea0c4
fix(local-mode): security hardening and reliability improvements
vibegui a42b778
fix(tests): update OAuth callback tests for cross-origin postMessage
vibegui a587bfa
fix(local-mode): use socket-level IP check and fix tilde expansion
vibegui 29471e5
feat(studio): rename package to decocms with deco CLI command
vibegui 7e0cf03
docs(studio): update decocms README and package metadata for npm
vibegui 1fc227e
fix(config): only expose internalUrl in local mode
vibegui 2de9069
fix: remove unused getBaseUrl import in org.ts
vibegui d67c7dc
docs(studio): align README with decocms.com/studio positioning
vibegui 3ae22ab
fix: ignore decocms runtime dependency in knip config
vibegui 7a63ed7
chore: rebrand CLI and docs from @decocms/mesh to npx decocms / deco
vibegui cbfe8a4
fix(studio): use bun runtime in deco CLI wrapper
vibegui 435c4eb
chore: rebrand CLI banners from MCP Mesh to Deco Studio
vibegui 66b6c13
fix(studio): require bun runtime and update instructions to bunx
vibegui 982eebf
fix(docs): align section headings with bunx commands
vibegui 89fb8ed
fix(dev): respect existing DATABASE_URL and fix path resolution
vibegui 7cecc73
fix: harden local-first DX — random password, seed gate, postMessage,…
vibegui fd0ce93
fix: security hardening, OAuth flow extraction, and deferred debt tra…
vibegui 3f19c45
fix: explicit MESH_ALLOW_LOCAL_PROD check and postMessage target for …
vibegui 8dd9079
fix(local-mode): probe ~/deco for secrets.json when MESH_HOME is unset
vibegui 61d02a2
fix(dev): check non-interactive before defaultPath existence in resol…
vibegui 327e1b4
fix: rename system prompt identity from "decopilot" to "Deco Pilot"
vibegui File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,3 +36,5 @@ jobs: | |
|
|
||
| - name: Run e2e tests | ||
| run: bun run test:e2e | ||
| env: | ||
| MESH_LOCAL_MODE: "false" | ||
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
| 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 }} |
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
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
| 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) |
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
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
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
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
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
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
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
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
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
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
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
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.