Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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 apps/mesh/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,13 @@
"jose": "^6.0.11",
"lucide-react": "^0.468.0",
"marked": "^15.0.6",
"mesh-plugin-declare": "workspace:*",
"mesh-plugin-object-storage": "workspace:*",
"mesh-plugin-preview": "workspace:*",
"mesh-plugin-private-registry": "workspace:*",
"farmrio-collection-reorder": "workspace:*",
"mesh-plugin-reports": "workspace:*",
"mesh-plugin-site-research": "workspace:*",
"mesh-plugin-user-sandbox": "workspace:*",
"mesh-plugin-workflows": "workspace:*",
"nanoid": "^5.1.6",
Expand Down
13 changes: 6 additions & 7 deletions apps/mesh/src/api/routes/local-dev-discover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,12 +188,8 @@ app.get("/discover", async (c) => {
if (meta?.localDevRoot) {
linkedRoots.add(meta.localDevRoot);

// Reconcile port drift for this connection (best-effort, don't block discovery)
try {
await reconcileLocalDevConnection(conn, meshContext.storage);
} catch {
// Non-critical — discovery continues for other connections
}
// Reconcile port drift for this connection
await reconcileLocalDevConnection(conn, meshContext.storage);

continue;
}
Expand Down Expand Up @@ -276,7 +272,7 @@ app.post("/add-project", async (c) => {
slug,
name,
description: `Local development project (${root})`,
enabledPlugins: ["object-storage", "preview"],
enabledPlugins: ["object-storage", "preview", "declare"],
ui: {
banner: null,
bannerColor: "#10B981",
Expand All @@ -292,6 +288,9 @@ app.post("/add-project", async (c) => {
await ctx.storage.projectPluginConfigs.upsert(project.id, "preview", {
connectionId: connection.id,
});
await ctx.storage.projectPluginConfigs.upsert(project.id, "declare", {
connectionId: connection.id,
});

// 5. Create a Virtual MCP (agent) so the local-dev tools are available in chat
const virtualMcp = await ctx.storage.virtualMcps.create(
Expand Down
22 changes: 8 additions & 14 deletions apps/mesh/src/api/routes/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,21 +136,15 @@ async function createMCPProxyDoNotUseDirectly(
throw new Error(`Connection inactive: ${connection.status}`);
}

// Reconcile local-dev port drift before connecting (only for local-dev connections)
const meta = connection.metadata as { localDevRoot?: string } | null;
if (meta?.localDevRoot) {
const reconciled = await reconcileLocalDevConnection(
connection,
ctx.storage,
// Reconcile local-dev port drift before connecting
const reconciled = await reconcileLocalDevConnection(connection, ctx.storage);
if (reconciled.connection_url === null) {
throw new Error(
"Local dev server is not running. Start it with `deco link` and try again.",
);
if (reconciled.connection_url === null) {
throw new Error(
"Local dev server is not running. Start it with `deco link` and try again.",
);
}
if (reconciled.connection_url !== connection.connection_url) {
connection.connection_url = reconciled.connection_url;
}
}
if (reconciled.connection_url !== connection.connection_url) {
connection.connection_url = reconciled.connection_url;
}

// Create base client with auth + monitoring transports
Expand Down
4 changes: 3 additions & 1 deletion apps/mesh/src/web/components/binding-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ export function BindingSelector({

const isInstalling = isLocalInstalling || isGlobalInstalling;

const allConnections = useConnections();
const allConnections = useConnections({
extraArgs: { include_virtual: true },
});

// Filter connections based on binding type
// Use the hook for string bindings
Expand Down
6 changes: 6 additions & 0 deletions apps/mesh/src/web/layouts/plugin-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { useQuery } from "@tanstack/react-query";
import { KEYS } from "@/web/lib/query-keys";
import { Button } from "@deco/ui/components/button.tsx";
import { Page } from "@/web/components/page";
import { SaveChangesButton } from "@/web/components/topbar/save-changes-button";

interface PluginLayoutProps {
/**
Expand Down Expand Up @@ -289,6 +290,11 @@ export function PluginLayout({
onConnectionChange: () => {},
})}
</Page.Header.Left>
<Page.Header.Right>
<Suspense>
<SaveChangesButton />
</Suspense>
</Page.Header.Right>
</Page.Header>
<Page.Content>
<Suspense
Expand Down
6 changes: 5 additions & 1 deletion apps/mesh/src/web/plugins.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import type { AnyClientPlugin } from "@decocms/bindings/plugins";
import { collectionReorderRankingPlugin } from "farmrio-collection-reorder";
import { objectStoragePlugin } from "mesh-plugin-object-storage";
import { declarePlugin } from "mesh-plugin-declare";
import { previewPlugin } from "mesh-plugin-preview";
import { clientPlugin as privateRegistryPlugin } from "mesh-plugin-private-registry/client";
import { reportsPlugin } from "mesh-plugin-reports";
import { siteResearchPlugin } from "mesh-plugin-site-research";
import { clientPlugin as userSandboxPlugin } from "mesh-plugin-user-sandbox/client";
import { clientPlugin as workflowsPlugin } from "mesh-plugin-workflows/client";

// Registered plugins
export const sourcePlugins: AnyClientPlugin[] = [
objectStoragePlugin,
declarePlugin,
previewPlugin,
objectStoragePlugin,
reportsPlugin,
siteResearchPlugin,
collectionReorderRankingPlugin,
userSandboxPlugin,
privateRegistryPlugin,
Expand Down
5 changes: 1 addition & 4 deletions packages/cli/src/lib/local-dev-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
* instead of spawning a separate binary.
*/

// Static type import so knip detects the dependency (runtime uses dynamic import)
import type {} from "@decocms/local-dev";

const DEFAULT_PORT = 4201;

/** Minimal interface matching LocalDevServer from @decocms/local-dev */
Expand Down Expand Up @@ -65,7 +62,7 @@ export async function stopLocalDev(
* Probe whether a local-dev daemon is alive on the given port.
* Returns the root path of the running instance, or null if nothing is running.
*/
async function probeLocalDev(
export async function probeLocalDev(
port: number = DEFAULT_PORT,
): Promise<string | null> {
try {
Expand Down
Loading
Loading