feat(local-dev): native folder picker and simplified project creation#2691
feat(local-dev): native folder picker and simplified project creation#2691
Conversation
🧪 BenchmarkShould we run the Virtual MCP strategy benchmark for this PR? React with 👍 to run the benchmark.
Benchmark will run on the next push after you react. |
Release OptionsShould a new version be published when this PR is merged? React with an emoji to vote on the release type:
Current version: Deployment
|
There was a problem hiding this comment.
7 issues found across 671 files
Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/docs/client/src/content/2025-10-10/pt-br/no-code-guides/creating-agents.mdx">
<violation number="1" location="apps/docs/client/src/content/2025-10-10/pt-br/no-code-guides/creating-agents.mdx:93">
P2: The PT-BR refund limit guidance is inconsistent with the English source (R$500 vs $100), which can lead to different agent behavior depending on locale.
(Based on your team's feedback about treating English documentation as the authoritative source.) [FEEDBACK_USED]</violation>
</file>
<file name=".github/workflows/release.yaml">
<violation number="1" location=".github/workflows/release.yaml:70">
P1: The npm version check queries the wrong package (`decocms` instead of `@decocms/mesh`), which can incorrectly force publish attempts for already-released versions.</violation>
</file>
<file name=".cursor/skills/respond-to-pr-review/SKILL.md">
<violation number="1" location=".cursor/skills/respond-to-pr-review/SKILL.md:52">
P2: Filter replies by the authenticated user before considering a comment addressed; otherwise replies from other users incorrectly suppress unaddressed review items.
(Based on your team's feedback about only treating comments as addressed when the current authenticated user replied.) [FEEDBACK_USED]</violation>
</file>
<file name="apps/docs/astro.config.mjs">
<violation number="1" location="apps/docs/astro.config.mjs:16">
P2: `publicDir` is relative to the configured `root`. With `root: "client"`, setting `publicDir: "client/public"` resolves to `client/client/public` and will break static asset resolution. Use `public` (relative to root) or an absolute URL if you meant the repo root.</violation>
</file>
<file name="apps/docs/client/src/content/2026-03-10/pt-br/mcp-mesh/self-hosting/deploy/kubernetes.mdx">
<violation number="1" location="apps/docs/client/src/content/2026-03-10/pt-br/mcp-mesh/self-hosting/deploy/kubernetes.mdx:37">
P2: The architecture image URL is broken due to an invalid GitHub owner path (`deco CMS` with a space).</violation>
</file>
<file name="apps/docs/client/src/layouts/DocsLayout.astro">
<violation number="1" location="apps/docs/client/src/layouts/DocsLayout.astro:22">
P2: Avoid hardcoding the fallback docs version; use a non-date alias/source of truth so this doesn’t drift on future version bumps.</violation>
</file>
<file name=".claude/settings.json">
<violation number="1" location=".claude/settings.json:8">
P1: Validate `name` before building `DIR`/`BRANCH`; currently path segments like `../` can escape the intended `.claude/worktrees` directory.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| # Check if this specific version already exists in npm | ||
| # This works for both stable and prerelease versions (unlike checking 'latest' tag) | ||
| if npm view @decocms/mesh@$CURRENT_VERSION version >/dev/null 2>&1; then | ||
| if npm view decocms@$CURRENT_VERSION version >/dev/null 2>&1; then |
There was a problem hiding this comment.
P1: The npm version check queries the wrong package (decocms instead of @decocms/mesh), which can incorrectly force publish attempts for already-released versions.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/release.yaml, line 70:
<comment>The npm version check queries the wrong package (`decocms` instead of `@decocms/mesh`), which can incorrectly force publish attempts for already-released versions.</comment>
<file context>
@@ -66,7 +67,7 @@ jobs:
# Check if this specific version already exists in npm
# This works for both stable and prerelease versions (unlike checking 'latest' tag)
- if npm view @decocms/mesh@$CURRENT_VERSION version >/dev/null 2>&1; then
+ if npm view decocms@$CURRENT_VERSION version >/dev/null 2>&1; then
echo "version-changed=false" >> $GITHUB_OUTPUT
echo "⏭️ Version $CURRENT_VERSION already published, skipping publish"
</file context>
| if npm view decocms@$CURRENT_VERSION version >/dev/null 2>&1; then | |
| if npm view @decocms/mesh@$CURRENT_VERSION version >/dev/null 2>&1; then |
| "hooks": [ | ||
| { | ||
| "type": "command", | ||
| "command": "sh -c 'INPUT=$(cat); NAME=$(echo \"$INPUT\" | jq -r .name); CWD=$(echo \"$INPUT\" | jq -r .cwd); DIR=\"$CWD/.claude/worktrees/$NAME\"; BRANCH=\"claude/$NAME\"; git -C \"$CWD\" worktree add -b \"$BRANCH\" \"$DIR\" HEAD >&2; cp \"$CWD/apps/mesh/.env\" \"$DIR/apps/mesh/.env\" 2>/dev/null >&2 || true; echo \"$DIR\"'" |
There was a problem hiding this comment.
P1: Validate name before building DIR/BRANCH; currently path segments like ../ can escape the intended .claude/worktrees directory.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .claude/settings.json, line 8:
<comment>Validate `name` before building `DIR`/`BRANCH`; currently path segments like `../` can escape the intended `.claude/worktrees` directory.</comment>
<file context>
@@ -0,0 +1,14 @@
+ "hooks": [
+ {
+ "type": "command",
+ "command": "sh -c 'INPUT=$(cat); NAME=$(echo \"$INPUT\" | jq -r .name); CWD=$(echo \"$INPUT\" | jq -r .cwd); DIR=\"$CWD/.claude/worktrees/$NAME\"; BRANCH=\"claude/$NAME\"; git -C \"$CWD\" worktree add -b \"$BRANCH\" \"$DIR\" HEAD >&2; cp \"$CWD/apps/mesh/.env\" \"$DIR/apps/mesh/.env\" 2>/dev/null >&2 || true; echo \"$DIR\"'"
+ }
+ ]
</file context>
| Você pode processar reembolsos de até R$500. Para valores maiores, abra um ticket | ||
| e informe o cliente que um gerente fará a revisão. | ||
| Você pode: | ||
| - Processar reembolsos abaixo de R$500 usando @PROCESS_REFUND |
There was a problem hiding this comment.
P2: The PT-BR refund limit guidance is inconsistent with the English source (R$500 vs $100), which can lead to different agent behavior depending on locale.
(Based on your team's feedback about treating English documentation as the authoritative source.)
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/docs/client/src/content/2025-10-10/pt-br/no-code-guides/creating-agents.mdx, line 93:
<comment>The PT-BR refund limit guidance is inconsistent with the English source (R$500 vs $100), which can lead to different agent behavior depending on locale.
(Based on your team's feedback about treating English documentation as the authoritative source.) </comment>
<file context>
@@ -79,89 +73,114 @@ O system prompt define as características do seu agent:
-Você pode processar reembolsos de até R$500. Para valores maiores, abra um ticket
-e informe o cliente que um gerente fará a revisão.
+Você pode:
+- Processar reembolsos abaixo de R$500 usando @PROCESS_REFUND
+- Redefinir senhas usando @RESET_PASSWORD
+- Consultar status da conta usando @GET_ACCOUNT_STATUS
</file context>
| # Get IDs that have been replied to | ||
| REPLIED_IDS=$(gh api "repos/${REPO}/pulls/${PR_NUMBER}/comments" \ | ||
| --paginate \ | ||
| --jq '[.[] | select(.in_reply_to_id != null) | .in_reply_to_id] | unique') |
There was a problem hiding this comment.
P2: Filter replies by the authenticated user before considering a comment addressed; otherwise replies from other users incorrectly suppress unaddressed review items.
(Based on your team's feedback about only treating comments as addressed when the current authenticated user replied.)
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .cursor/skills/respond-to-pr-review/SKILL.md, line 52:
<comment>Filter replies by the authenticated user before considering a comment addressed; otherwise replies from other users incorrectly suppress unaddressed review items.
(Based on your team's feedback about only treating comments as addressed when the current authenticated user replied.) </comment>
<file context>
@@ -0,0 +1,122 @@
+# Get IDs that have been replied to
+REPLIED_IDS=$(gh api "repos/${REPO}/pulls/${PR_NUMBER}/comments" \
+ --paginate \
+ --jq '[.[] | select(.in_reply_to_id != null) | .in_reply_to_id] | unique')
+```
+
</file context>
| "/": "/latest/en/introduction", | ||
| }, | ||
| outDir: "dist/client/", | ||
| publicDir: "client/public", |
There was a problem hiding this comment.
P2: publicDir is relative to the configured root. With root: "client", setting publicDir: "client/public" resolves to client/client/public and will break static asset resolution. Use public (relative to root) or an absolute URL if you meant the repo root.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/docs/astro.config.mjs, line 16:
<comment>`publicDir` is relative to the configured `root`. With `root: "client"`, setting `publicDir: "client/public"` resolves to `client/client/public` and will break static asset resolution. Use `public` (relative to root) or an absolute URL if you meant the repo root.</comment>
<file context>
@@ -1,52 +1,21 @@
- "/": "/latest/en/introduction",
- },
outDir: "dist/client/",
+ publicDir: "client/public",
srcDir: "client/src",
- integrations: [mdx(), react(), patchCsrRedirect()],
</file context>
| publicDir: "client/public", | |
| publicDir: "public", |
| ### Arquitetura | ||
|
|
||
|  | ||
|  |
There was a problem hiding this comment.
P2: The architecture image URL is broken due to an invalid GitHub owner path (deco CMS with a space).
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/docs/client/src/content/2026-03-10/pt-br/mcp-mesh/self-hosting/deploy/kubernetes.mdx, line 37:
<comment>The architecture image URL is broken due to an invalid GitHub owner path (`deco CMS` with a space).</comment>
<file context>
@@ -1,103 +1,103 @@
### Arquitetura
-
+
## Pré-requisitos
</file context>
|  | |
|  |
dcc6353 to
1026dcf
Compare
421ad07 to
7476141
Compare
There was a problem hiding this comment.
4 issues found across 4 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/mesh/src/web/routes/projects-list.tsx">
<violation number="1" location="apps/mesh/src/web/routes/projects-list.tsx:52">
P2: Show the picker error before returning when `/pick-folder` fails without a path.</violation>
<violation number="2" location="apps/mesh/src/web/routes/projects-list.tsx:173">
P2: Selecting "Blank Project" from the empty-state cards now reopens the selection step instead of the blank-project form.</violation>
</file>
<file name="apps/mesh/src/web/components/create-project-dialog.tsx">
<violation number="1" location="apps/mesh/src/web/components/create-project-dialog.tsx:90">
P1: `From Folder` becomes a no-op in local mode when this dialog is opened from callers that do not pass `onPickFolder`.</violation>
</file>
<file name="apps/mesh/src/mcp-clients/local/index.ts">
<violation number="1" location="apps/mesh/src/mcp-clients/local/index.ts:394">
P2: Script injection via unescaped `JSON.stringify` inside `<script>` tag. `JSON.stringify` doesn't escape `</` sequences, so a crafted `rootPath` or `detection.command` (from `.deco/preview.json`) can close the script tag and inject arbitrary HTML/JS. Use `.replace(/</g, '\\u003c')` after stringifying to neutralize the sequence.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| }); | ||
| const pick: { path?: string; cancelled?: boolean; error?: string } = | ||
| await pickRes.json(); | ||
| if (!pick.path) return; |
There was a problem hiding this comment.
P2: Show the picker error before returning when /pick-folder fails without a path.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/web/routes/projects-list.tsx, line 52:
<comment>Show the picker error before returning when `/pick-folder` fails without a path.</comment>
<file context>
@@ -27,16 +28,109 @@ export default function ProjectsListPage() {
+ });
+ const pick: { path?: string; cancelled?: boolean; error?: string } =
+ await pickRes.json();
+ if (!pick.path) return;
+
+ // 2. Validate folder (gets name/slug, checks for existing project)
</file context>
| if (!pick.path) return; | |
| if (!pick.path) { | |
| if (pick.error) { | |
| toast.error(pick.error); | |
| } | |
| return; | |
| } |
| var ROOT = ${JSON.stringify(rootPath)}; | ||
| var BASE_FILE_URL = ${JSON.stringify(baseFileUrl)}; | ||
| var detection = ${JSON.stringify(detection)}; |
There was a problem hiding this comment.
P2: Script injection via unescaped JSON.stringify inside <script> tag. JSON.stringify doesn't escape </ sequences, so a crafted rootPath or detection.command (from .deco/preview.json) can close the script tag and inject arbitrary HTML/JS. Use .replace(/</g, '\\u003c') after stringifying to neutralize the sequence.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/mcp-clients/local/index.ts, line 394:
<comment>Script injection via unescaped `JSON.stringify` inside `<script>` tag. `JSON.stringify` doesn't escape `</` sequences, so a crafted `rootPath` or `detection.command` (from `.deco/preview.json`) can close the script tag and inject arbitrary HTML/JS. Use `.replace(/</g, '\\u003c')` after stringifying to neutralize the sequence.</comment>
<file context>
@@ -192,46 +302,117 @@ function getPreviewHtml(rootPath: string): string {
+// ---- Preview state ----
+
+var ROOT = ${JSON.stringify(rootPath)};
+var BASE_FILE_URL = ${JSON.stringify(baseFileUrl)};
+var detection = ${JSON.stringify(detection)};
</file context>
| var ROOT = ${JSON.stringify(rootPath)}; | |
| var BASE_FILE_URL = ${JSON.stringify(baseFileUrl)}; | |
| var detection = ${JSON.stringify(detection)}; | |
| var ROOT = ${JSON.stringify(rootPath).replace(/</g, "\\u003c")}; | |
| var BASE_FILE_URL = ${JSON.stringify(baseFileUrl).replace(/</g, "\\u003c")}; | |
| var detection = ${JSON.stringify(detection).replace(/</g, "\\u003c")}; |
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/mesh/src/mcp-clients/local/index.ts">
<violation number="1" location="apps/mesh/src/mcp-clients/local/index.ts:72">
P2: This static-site early return prevents `.deco/preview.json` from overriding preview detection for folders without `package.json`. A manually configured preview command/port will now be ignored for those projects.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/mesh/src/mcp-clients/local/index.ts">
<violation number="1" location="apps/mesh/src/mcp-clients/local/index.ts:73">
P1: This broadens static-site detection too far: projects with both `index.html` and `package.json` are now misclassified as static, so Vite/dev-server previews never start.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
… flow Simplify the local folder project creation with native macOS folder picker (osascript) instead of custom directory browser. Add git panel with branch management and commit history, file watching via SSE, and integration with object-storage and preview plugins. Local connections now use empty connection_url instead of null to satisfy DB constraints. - Add /api/local-dev/pick-folder endpoint (native Finder dialog via osascript) - Simplify FolderStep UI to single dashed card for folder selection - Add GitPanel component with branch switching, commit history, and diff viewing - Add file watch support via SSE (useConnectionWatch hook) - Add git operation helpers (gitStatus, gitCommit, gitBranch, gitLog) - Fix MeshContext middleware ordering (local-dev routes mounted after context injection) - Adapt git-panel AI features to new AI provider system (useAiProviderKeyList) - Add query keys for git operations (KEYS.gitBranch, gitStatus, etc.) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…d MCP App preview - From Folder click directly opens OS picker and auto-creates project (no modal) - Add connection to project via projectConnections.add() so it appears in settings - Preserve _meta field when saving tools so preview UI resource URI is discoverable - Rewrite preview tool with proper MCP ext-apps protocol (JSON-RPC handshake) - Server-side preview detection: static sites (index.html), dev servers, manual config - Remove FolderStep dialog component (replaced by inline pickFolderAndCreate flow) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Static sites (index.html without package.json) should always use direct file serving, regardless of any leftover .deco/preview.json config. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
zero-build-slides has both index.html and package.json (with `npx serve`). A root index.html always means the project can be previewed directly. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…auth - Update CSP domain regex to accept wildcard ports (http://localhost:*) and ws/wss schemes for connect-src - Add _meta.ui.csp to resource content (where the renderer reads it) with frameDomains and connectDomains for localhost - Remove requireAuth from file serving route since iframe requests inside sandboxed MCP Apps don't carry session cookies Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
451c685 to
e3e6a1c
Compare
What is this contribution about?
Simplifies local folder project creation from complex daemon discovery to a single-click native folder picker. Users can now:
Includes a complete Git Panel for branch management, commit history, diffs, and AI-powered commit messages. File watching via SSE, file serving for preview/storage plugins, and bash tool integration.
Screenshots/Demonstration
How to Test
MESH_LOCAL_MODE=true bun run dev~/my-project)Migration Notes
metadata: { sourceProvider: "local-filesystem", localDevRoot: "/path" }connection_url: ""(not null) for local connections/api/local-dev/files/:connectionId/*Review Checklist
🤖 Generated with Claude Code
Summary by cubic
Adds a one‑click “From Folder” flow with a native macOS folder picker that auto‑creates the project, binds a local filesystem connection, and starts an in‑process MCP for zero‑config dev. Also ships a Git panel, live SSE file watching, secure local file serving, and a smarter preview/file viewer; root index.html is always treated as a static preview.
New Features
/api/local-dev/pick-folder,/validate-folder,/create-project, SSE watch at/api/local-dev/watch/:connectionId, and presigned file serving at/api/local-dev/files/:connectionId/*with path traversal protection.bash, SSE file watch, secure path resolution; clients created in‑process for local connections (no HTTP proxy).index.htmlalways renders as a static preview (even with apackage.json), detected before any.deco/preview.json; starts/stops viabash; sets CSP to allowlocalhost:*andws/wss; unauthenticated file serving for sandboxed iframes; preserves_metaso the UI can discover the preview resource URI./viewer?key=...) with Markdown preview and image rendering; clicking a file opens the viewer; sidebar item simplified.localModeto show local‑only UI like “From Folder”; login accepts a localhost‑onlyredirectTofor CLI auth.DECOCMS_HOME/assetsin local mode; deleting a project cleans up unused localhost connections and virtual MCPs.Dependencies
@decocms/local-dev.Written for commit e3e6a1c. Summary will update on new commits.