Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
148 commits
Select commit Hold shift + click to select a range
f83d3d2
feat(sidebar): add agents accordion section and simplify sidebar layout
tlgimenes Mar 24, 2026
b3fe360
feat(spaces): unify projects and agents into spaces with pinned sidebar
tlgimenes Mar 24, 2026
d5e723d
feat(sidebar): refactor project sidebar with spaces list and simplifi…
tlgimenes Mar 24, 2026
27dce57
feat(spaces): redesign project card and restore home page agents list
tlgimenes Mar 24, 2026
c2183c3
feat(sidebar): add settings gear icon to space menu items
tlgimenes Mar 24, 2026
949ee7c
refactor(spaces): remove breadcrumb from virtual MCP detail view
tlgimenes Mar 24, 2026
1755795
feat(sidebar): enhance spaces popover with details, create new, and s…
tlgimenes Mar 24, 2026
4cf3d11
before resizing
tlgimenes Mar 24, 2026
442dd5f
feat(sidebar): double collapsed sidebar width and center icons
tlgimenes Mar 24, 2026
678d6b8
fix(sidebar): make collapsed spaces list HTML-compliant and fill width
tlgimenes Mar 24, 2026
04945a5
fix(sidebar): make collapsed menu buttons square
tlgimenes Mar 24, 2026
0a41e7b
fix(sidebar): use w-full aspect-square for collapsed menu buttons
tlgimenes Mar 24, 2026
13d09e5
feat(sidebar): make space icons fill collapsed button area
tlgimenes Mar 24, 2026
ca18f53
refactor(sidebar): simplify sidebar components and add settings layout
tlgimenes Mar 24, 2026
67ae000
merge: resolve conflicts from origin/main
tlgimenes Mar 24, 2026
edc6728
fix(sidebar): pin+open spaces and reduce collapsed width
tlgimenes Mar 24, 2026
d569dd9
fix(sidebar): reduce collapsed sidebar width and unify button styles
tlgimenes Mar 24, 2026
90324c0
fix(sidebar): pin new spaces and increase sidebar gap
tlgimenes Mar 24, 2026
2fa9173
feat(tasks-panel): add gear icon and use URL for virtualMcpId
tlgimenes Mar 24, 2026
af6b7ab
merge: resolve conflicts from origin/main
tlgimenes Mar 24, 2026
9d8ff5f
fix(ui): fix tasks panel syntax error and remove settings padding
tlgimenes Mar 24, 2026
3533382
feat(sidebar): project sidebar refactor + remove panel dividers
rafavalls Mar 25, 2026
201836b
feat(ui): remove page headers inside spaces and clean up chat panel c…
rafavalls Mar 25, 2026
b5cc937
feat(sidebar): add agents accordion section and simplify sidebar layout
tlgimenes Mar 24, 2026
1f130c5
feat(spaces): unify projects and agents into spaces with pinned sidebar
tlgimenes Mar 24, 2026
15d7176
feat(sidebar): refactor project sidebar with spaces list and simplifi…
tlgimenes Mar 24, 2026
a3d057f
feat(spaces): redesign project card and restore home page agents list
tlgimenes Mar 24, 2026
1683462
feat(sidebar): add settings gear icon to space menu items
tlgimenes Mar 24, 2026
6da34ae
refactor(spaces): remove breadcrumb from virtual MCP detail view
tlgimenes Mar 24, 2026
550aaf4
feat(sidebar): enhance spaces popover with details, create new, and s…
tlgimenes Mar 24, 2026
c3d7e9b
before resizing
tlgimenes Mar 24, 2026
e0fe97e
feat(sidebar): double collapsed sidebar width and center icons
tlgimenes Mar 24, 2026
e0ea3ae
fix(sidebar): make collapsed spaces list HTML-compliant and fill width
tlgimenes Mar 24, 2026
d783dc8
fix(sidebar): make collapsed menu buttons square
tlgimenes Mar 24, 2026
c361cf8
fix(sidebar): use w-full aspect-square for collapsed menu buttons
tlgimenes Mar 24, 2026
5502f69
feat(sidebar): make space icons fill collapsed button area
tlgimenes Mar 24, 2026
2a2d34c
refactor(sidebar): simplify sidebar components and add settings layout
tlgimenes Mar 24, 2026
0509d10
fix(sidebar): pin+open spaces and reduce collapsed width
tlgimenes Mar 24, 2026
f8688ee
fix(sidebar): reduce collapsed sidebar width and unify button styles
tlgimenes Mar 24, 2026
0ab8376
fix(sidebar): pin new spaces and increase sidebar gap
tlgimenes Mar 24, 2026
2cfb8d4
feat(tasks-panel): add gear icon and use URL for virtualMcpId
tlgimenes Mar 24, 2026
384fc0e
fix(ui): fix tasks panel syntax error and remove settings padding
tlgimenes Mar 24, 2026
33c0da8
feat(shell): scope tasks/chat panels to space routes only
tlgimenes Mar 25, 2026
a02d0b1
fix(connections): fix navigation route after rebase conflict resolution
tlgimenes Mar 25, 2026
6c45310
fix(knip): remove unused files and unexport unused function
tlgimenes Mar 25, 2026
8365b35
feat(shell): refactor space layout — show settings as home, consolida…
tlgimenes Mar 25, 2026
9d63dc2
feat(tasks): add Incoming section showing space automations in tasks …
tlgimenes Mar 25, 2026
b94f3b6
fix(shell): simplify virtual MCP mount effect and fix panel layout
tlgimenes Mar 25, 2026
b097a30
fix(lint): use cn() for className interpolation in side-panel-tasks
tlgimenes Mar 25, 2026
3552efa
fix(shell): replace CSS panel collapse with react-resizable-panels na…
tlgimenes Mar 25, 2026
862309d
merge: resolve conflict in use-project-sidebar-items after merging main
tlgimenes Mar 25, 2026
318e6b3
new sidebar and onboarding wip
rafavalls Mar 25, 2026
79ac112
refactor(ui): extract cron utilities to shared module
tlgimenes Mar 25, 2026
bbe5b7d
refactor(ui): extract shared automation sub-components
tlgimenes Mar 25, 2026
ba4394f
feat(ui): parameterize SettingsTab for embedded mode with fixed agent
tlgimenes Mar 25, 2026
a96dc72
feat(ui): add automations tab entry to project settings
tlgimenes Mar 25, 2026
e7c83c2
feat(ui): add automations tab list+detail component
tlgimenes Mar 25, 2026
b08ab6d
feat(ui): wire automations tab into project settings view
tlgimenes Mar 25, 2026
1a1897b
merge: integrate sidebar changes from #2870, excluding onboarding
tlgimenes Mar 25, 2026
4160d87
refactor(ui): move settings to nav item, remove /settings route, rest…
tlgimenes Mar 25, 2026
fd53b62
feat(ui): add toolbar breadcrumb for spaces routes, unify agent/proje…
tlgimenes Mar 25, 2026
92cc0be
merge: integrate main into project-sidebar-refactor
tlgimenes Mar 25, 2026
f171646
fix(ui): resolve lint error and remove unused files
tlgimenes Mar 25, 2026
f24d102
fix(ui): remove sidebar border and fix padding in settings pages
rafavalls Mar 25, 2026
8ec78fe
fix(ui): reduce user avatar size in sidebar footer
rafavalls Mar 25, 2026
5a72fd1
feat(ui): add account popover with org switcher and update sidebar la…
rafavalls Mar 25, 2026
056b8ad
refactor(ui): move virtual-mcp and automations views out of component…
tlgimenes Mar 25, 2026
e36e726
merge: integrate main into project-sidebar-refactor
tlgimenes Mar 25, 2026
43d5dda
fix(ui): restore branch's simplified sidebar after merge
tlgimenes Mar 25, 2026
d564ae9
fix(ui): compact space identity header in task panel
rafavalls Mar 25, 2026
2c836f1
fix(deco-sites): remove hardcoded demo email override and stub sites
rafavalls Mar 25, 2026
5ed655b
fix(ui): prevent chat panel race condition when navigating back from …
tlgimenes Mar 25, 2026
20faec9
refactor(ui): migrate settings to route-based pages and clean up comp…
tlgimenes Mar 25, 2026
27b0418
fix(ui): normalize panel spacing so all gaps are a consistent 6px
rafavalls Mar 25, 2026
8c795b0
fix(ui): move tasks toggle button to left toolbar next to nav arrows
rafavalls Mar 25, 2026
32c8a6c
fix(ui): move tasks toggle to the left of nav arrows
rafavalls Mar 25, 2026
342da84
fix(ui): hide main panel toggle on org home
rafavalls Mar 25, 2026
b1f15e6
fix(ui): skip main panel on org home to prevent it stealing space
rafavalls Mar 26, 2026
6da7e25
fix(ui): remove redundant chat/close toggles from tasks panel header
rafavalls Mar 26, 2026
35b6322
fix(ui): consistent icon button styles in tasks panel + always-open s…
rafavalls Mar 26, 2026
8caec4c
fix(ui): toggle search in tasks panel + uniform size-7/size-16 icon b…
rafavalls Mar 26, 2026
7ea0814
fix(ui): owner filter button active/hover state matches other icon bu…
rafavalls Mar 26, 2026
710d66a
fix(ui): remove persistent active state from owner filter button
rafavalls Mar 26, 2026
294d582
fix(ui): use CollectionSearch component when search is open in tasks …
rafavalls Mar 26, 2026
975ea38
feat(ui): add automation create/toggle in sidebar and ?main= central …
tlgimenes Mar 26, 2026
9d00a99
merge main into branch
tlgimenes Mar 26, 2026
0af33ae
fix(ci): resolve merge conflicts with main and clean up dead code
tlgimenes Mar 26, 2026
27864b1
fix(ui): address PR review feedback — migration constraint, ref loops…
tlgimenes Mar 26, 2026
6a8b779
feat(ui): add new task button in toolbar and fix chat panel default w…
rafavalls Mar 26, 2026
e06e90e
feat(ui): restore sidebar alignment and chat panel fixes after rebase
rafavalls Mar 26, 2026
084738e
fix(ui): fix connection create dialog navigation route
rafavalls Mar 26, 2026
b558e76
fix(ui): remove agents/capabilities tabs, fix test-agent button, and …
tlgimenes Mar 26, 2026
fd82837
merge origin/main into tlgimenes/project-sidebar-refactor
tlgimenes Mar 26, 2026
a0786b2
refactor(ui): rename selectedAgent to selectedVirtualMcp, pass virtua…
tlgimenes Mar 26, 2026
fcac9c1
fix(ui): key ChatProvider by virtualMcpId to force clean remount on s…
tlgimenes Mar 26, 2026
be8f544
refactor(ui): rename spaces to agents across codebase and UI
tlgimenes Mar 26, 2026
3557873
refactor(ui): simplify toolApprovalLevel flow, remove task item avata…
tlgimenes Mar 26, 2026
750c688
fix(ui): address PR review feedback — remove dead code, fix bugs, cle…
tlgimenes Mar 26, 2026
8855c77
fix(ui): address PR review feedback — remove dead code, fix bugs, cle…
tlgimenes Mar 26, 2026
8fca475
Merge remote-tracking branch 'origin/main' into tlgimenes/project-sid…
tlgimenes Mar 26, 2026
db5c6a1
fix(ci): remove unused files and stale knip ignores
tlgimenes Mar 26, 2026
55c15d7
fix(ci): format knip.jsonc with biome
tlgimenes Mar 26, 2026
09bbb99
fix(auth): handle invalid baseUrl in getTrustedOrigins during test lo…
tlgimenes Mar 26, 2026
9851b86
fix(core): fallback port to 3000 in getBaseUrl when settings.port is …
tlgimenes Mar 26, 2026
fcd2df2
feat(ui): redesign mobile layout — full-screen chat with sidebar sheet
rafavalls Mar 26, 2026
2945709
feat(threads): replace agent_ids with virtual_mcp_id + SSE-driven badges
tlgimenes Mar 26, 2026
109b957
feat(chat): add 3-context ChatContextProvider and new hooks
tlgimenes Mar 26, 2026
357ce38
refactor(chat): integrate 3-context provider, migrate consumers, dele…
tlgimenes Mar 26, 2026
e9960cd
Merge remote-tracking branch 'origin/main' into tlgimenes/project-sid…
tlgimenes Mar 26, 2026
56481e6
fix(chat): stabilize useStreamManager subscribe to prevent infinite r…
tlgimenes Mar 26, 2026
ba35855
Revert "fix(chat): stabilize useStreamManager subscribe to prevent in…
tlgimenes Mar 26, 2026
037afe6
fix(chat): seed taskId in router validateSearch to prevent mount loop
tlgimenes Mar 26, 2026
666aaeb
fix(chat): skip message query when taskId is null
tlgimenes Mar 26, 2026
29ab245
fix(chat): remove safety-net polling from useStreamManager
tlgimenes Mar 26, 2026
9662b0a
fix(shell): remove 8 useEffect cascades from ShellLayoutInner
tlgimenes Mar 26, 2026
0caa527
chore: cherry-pick non-effect changes from 8f13459c6
tlgimenes Mar 26, 2026
4aa5678
wip
tlgimenes Mar 26, 2026
645aae2
fix(ui): move panel toggle to left of nav arrows, align sidebar top w…
rafavalls Mar 26, 2026
207d83e
refactor(web): project sidebar refactor - use Sidebar components, rem…
tlgimenes Mar 26, 2026
7bb7456
fix(chat): correct virtualMcpId resolution, remove debug logs
tlgimenes Mar 26, 2026
381f70d
Merge remote-tracking branch 'origin/main' into tlgimenes/project-sid…
tlgimenes Mar 26, 2026
8e1310f
refactor(web): remove unused createTask from project sidebar
tlgimenes Mar 26, 2026
5244946
refactor(web): consolidate panel context and simplify project sidebar
tlgimenes Mar 26, 2026
beb9426
feat(web): add right-click context menu and delayed X icon on sidebar…
rafavalls Mar 26, 2026
aa0c664
refactor(web): extract useNavigateToNewTask hook for sidebar navigation
tlgimenes Mar 26, 2026
3946979
refactor(web): simplify Suspense boundaries and expand sidebar on set…
tlgimenes Mar 26, 2026
d4cfad1
fix(decopilot): set virtual_mcp_id on threads created via chat stream
tlgimenes Mar 27, 2026
e25428d
refactor(web): simplify tasks panel and rename agent context to virtu…
tlgimenes Mar 27, 2026
643c089
refactor(web): remove agent prop from TaskRow, add automation delete,…
tlgimenes Mar 27, 2026
bb2ed0f
fix(web): improve tasks panel UX and SSE cache invalidation
tlgimenes Mar 27, 2026
afccfc1
fix(web): show active starter count in incoming section header
tlgimenes Mar 27, 2026
3a6d1b5
refactor(web): lazy-load AI provider and model fetches in chat
tlgimenes Mar 27, 2026
021af3a
fix(threads): update test to match in_progress default status
tlgimenes Mar 27, 2026
ef81c7f
fix(web): remove unused files and exports flagged by knip
tlgimenes Mar 27, 2026
822fdb6
refactor(web): decouple tasks panel from ChatContextProvider lifecycle
tlgimenes Mar 27, 2026
2b97add
fix(web): don't throw when taskId is absent on non-agent routes
tlgimenes Mar 27, 2026
3b4bf51
fix(web): add validateSearch to orgHomeRoute to seed taskId
tlgimenes Mar 27, 2026
74beb56
fix: resolve TypeScript errors and update test expectations
tlgimenes Mar 27, 2026
f5610ea
fix(web): debounced autosave for virtual MCP settings and tasks panel
tlgimenes Mar 27, 2026
094b819
fix(web): navigate to settings tab when clicking virtual MCP edit icon
tlgimenes Mar 27, 2026
8289bbf
fix e2e
tlgimenes Mar 27, 2026
8a43b10
fix e2e: handle query params in org home URL regex
tlgimenes Mar 27, 2026
8eb7413
fix(e2e): loosen waitForURL regex to allow nested post-signup routes
tlgimenes Mar 27, 2026
e312569
fix(web): address PR review feedback across 39 comments
tlgimenes Mar 27, 2026
b473bf2
fix(web): use KEYS constants for automation query keys and add sound …
tlgimenes Mar 27, 2026
6f6ab84
fix(ci): remove unused use-notification.ts and fix e2e connection test
tlgimenes Mar 27, 2026
08f4cf3
fix(web): sort threads by most recently updated first
tlgimenes Mar 27, 2026
acb69ff
fix(schema): add layout field to VirtualMcpUISchema to fix output val…
tlgimenes Mar 27, 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
16 changes: 12 additions & 4 deletions apps/mesh/e2e/tests/connection-create.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,17 @@ test.describe("Connection creation flow", () => {
await signUp(page);

// 2. Wait for the auto-redirect to the org page and extract slug from URL
await page.waitForURL(/\/[a-z0-9-]+\/?$/, { timeout: 15_000 });
await page.waitForURL(
(url) => {
const slug = url.pathname.split("/")[1];
return !!slug && slug !== "login" && slug !== "api";
},
{ timeout: 15_000 },
);
const orgSlug = new URL(page.url()).pathname.split("/")[1];

// 3. Navigate directly to the connections page
await page.goto(`/${orgSlug}/mcps`);
await page.goto(`/${orgSlug}/settings/connections`);

// 4. Open the create connection dialog
await page.getByRole("button", { name: "Custom Connection" }).click();
Expand All @@ -34,7 +40,9 @@ test.describe("Connection creation flow", () => {
.click();

// 7. Should navigate to the connection detail page (slug derived from URL)
await page.waitForURL(/\/mcps\/examplecom-mcp/, { timeout: 10_000 });
await expect(page).toHaveURL(/\/mcps\/examplecom-mcp/);
await page.waitForURL(/\/settings\/connections\/examplecom-mcp/, {
timeout: 10_000,
});
await expect(page).toHaveURL(/\/settings\/connections\/examplecom-mcp/);
});
});
73 changes: 73 additions & 0 deletions apps/mesh/migrations/052-spaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import type { Kysely } from "kysely";
import { sql } from "kysely";

export async function up(db: Kysely<unknown>): Promise<void> {
// Add pinned column
await db.schema
.alterTable("connections")
.addColumn("pinned", "boolean", (col) => col.notNull().defaultTo(false))
.execute();

// Backfill: projects become pinned, agents/null become unpinned
await sql`UPDATE connections SET pinned = true WHERE subtype = 'project' AND connection_type = 'VIRTUAL'`.execute(
db,
);

// Drop the old composite index on (organization_id, connection_type, subtype)
await db.schema
.dropIndex("idx_connections_org_type_subtype")
.ifExists()
.execute();

// Drop the CHECK constraint on subtype
await sql`ALTER TABLE connections DROP CONSTRAINT IF EXISTS chk_connections_subtype`.execute(
db,
);

// Drop the subtype column
await db.schema.alterTable("connections").dropColumn("subtype").execute();

// Add new composite index for pinned queries
await db.schema
.createIndex("idx_connections_org_type_pinned")
.on("connections")
.columns(["organization_id", "connection_type", "pinned"])
.execute();
}

export async function down(db: Kysely<unknown>): Promise<void> {
// Drop new index
await db.schema
.dropIndex("idx_connections_org_type_pinned")
.ifExists()
.execute();

// Re-add subtype column
await db.schema
.alterTable("connections")
.addColumn("subtype", "text")
.execute();

// Backfill: pinned items become projects, unpinned become agents
await sql`UPDATE connections SET subtype = 'project' WHERE pinned = true AND connection_type = 'VIRTUAL'`.execute(
db,
);
await sql`UPDATE connections SET subtype = 'agent' WHERE pinned = false AND connection_type = 'VIRTUAL'`.execute(
db,
);

// Re-add CHECK constraint
await sql`ALTER TABLE connections ADD CONSTRAINT chk_connections_subtype CHECK (subtype IN ('agent', 'project') OR subtype IS NULL)`.execute(
db,
);

// Re-add old index
await db.schema
.createIndex("idx_connections_org_type_subtype")
.on("connections")
.columns(["organization_id", "connection_type", "subtype"])
.execute();

// Drop pinned column
await db.schema.alterTable("connections").dropColumn("pinned").execute();
}
31 changes: 31 additions & 0 deletions apps/mesh/migrations/054-automation-project-scope.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Automation Project Scope Migration
*
* Adds `virtual_mcp_id` column to `automations` table so automations can be
* scoped to a specific project or space (Virtual MCP).
* NULL means org-level (existing behavior).
*/

import { Kysely } from "kysely";

export async function up(db: Kysely<unknown>): Promise<void> {
await db.schema
.alterTable("automations")
.addColumn("virtual_mcp_id", "text")
.execute();

await db.schema
.createIndex("idx_automations_virtual_mcp")
.on("automations")
.columns(["virtual_mcp_id"])
.execute();
}

export async function down(db: Kysely<unknown>): Promise<void> {
await db.schema.dropIndex("idx_automations_virtual_mcp").execute();

await db.schema
.alterTable("automations")
.dropColumn("virtual_mcp_id")
.execute();
}
58 changes: 58 additions & 0 deletions apps/mesh/migrations/055-thread-virtual-mcp-id.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0: This migration is not registered in migrations/index.ts. It needs both an import (import * as migration055threadvirtualmcpid from "./055-thread-virtual-mcp-id.ts") and an entry in the migrations map, otherwise it will never run.

(Based on your team's feedback about checking migrations/index.ts registration before flagging.)

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/migrations/055-thread-virtual-mcp-id.ts, line 17:

<comment>This migration is not registered in `migrations/index.ts`. It needs both an import (`import * as migration055threadvirtualmcpid from "./055-thread-virtual-mcp-id.ts"`) and an entry in the `migrations` map, otherwise it will never run.

(Based on your team's feedback about checking migrations/index.ts registration before flagging.) </comment>

<file context>
@@ -0,0 +1,58 @@
+import type { Kysely } from "kysely";
+import { sql } from "kysely";
+
+export async function up(db: Kysely<unknown>): Promise<void> {
+  await db.schema
+    .alterTable("threads")
</file context>
Fix with Cubic

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already registered — the import is on line 58 and the entry in the migrations object is on line 128 of migrations/index.ts. No changes needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification—looks like it’s already registered. I’ll treat this as a false positive.

* Thread Virtual MCP ID Migration
*
* Replaces the `agent_ids` JSON text column with a simple `virtual_mcp_id`
* foreign key. Each thread is associated with exactly one virtual MCP
* (the agent it was initiated with).
*
* - Adds `virtual_mcp_id` column (NOT NULL, defaults to empty string)
* - Backfills from `agent_ids[0]` where available
* - Adds composite index for efficient querying
* - Drops `agent_ids` column
*/

import type { Kysely } from "kysely";
import { sql } from "kysely";

export async function up(db: Kysely<unknown>): Promise<void> {
await db.schema
.alterTable("threads")
.addColumn("virtual_mcp_id", "text", (col) => col.notNull().defaultTo(""))
.execute();

await sql`
UPDATE threads
SET virtual_mcp_id = (agent_ids::jsonb ->> 0)
WHERE agent_ids IS NOT NULL
AND agent_ids != '[]'
AND agent_ids != ''
AND (agent_ids::jsonb ->> 0) IS NOT NULL
`.execute(db);

await sql`
CREATE INDEX idx_threads_virtual_mcp_id
ON threads (organization_id, virtual_mcp_id, hidden, updated_at DESC)
`.execute(db);

await db.schema.alterTable("threads").dropColumn("agent_ids").execute();
}

export async function down(db: Kysely<unknown>): Promise<void> {
await db.schema
.alterTable("threads")
.addColumn("agent_ids", "text", (col) => col.defaultTo("[]"))
.execute();

await sql`
UPDATE threads
SET agent_ids = CASE
WHEN virtual_mcp_id IS NOT NULL AND virtual_mcp_id != ''
THEN jsonb_build_array(virtual_mcp_id)::text
ELSE '[]'
END
`.execute(db);

await sql`DROP INDEX IF EXISTS idx_threads_virtual_mcp_id`.execute(db);

await db.schema.alterTable("threads").dropColumn("virtual_mcp_id").execute();
}
6 changes: 6 additions & 0 deletions apps/mesh/migrations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,11 @@ import * as migration049removeorgadminprojects from "./049-remove-org-admin-proj
import * as migration050durableagentruns from "./050-durable-agent-runs.ts";
import * as migration051orgsso from "./051-org-sso.ts";
import * as migration052threadagentids from "./052-thread-agent-ids.ts";
import * as migration052spaces from "./052-spaces.ts";
import * as migration053registryconfig from "./053-registry-config.ts";
import * as migration054automationprojectscope from "./054-automation-project-scope.ts";
import * as migration054connectionslug from "./054-connection-slug.ts";
import * as migration055threadvirtualmcpid from "./055-thread-virtual-mcp-id.ts";

/**
* Core migrations for the Mesh application.
Expand Down Expand Up @@ -118,8 +121,11 @@ const migrations: Record<string, Migration> = {
"050-durable-agent-runs": migration050durableagentruns,
"051-org-sso": migration051orgsso,
"052-thread-agent-ids": migration052threadagentids,
"052-spaces": migration052spaces,
"053-registry-config": migration053registryconfig,
"054-automation-project-scope": migration054automationprojectscope,
"054-connection-slug": migration054connectionslug,
"055-thread-virtual-mcp-id": migration055threadvirtualmcpid,
};

export default migrations;
10 changes: 8 additions & 2 deletions apps/mesh/src/ai-providers/coding-agents/claude-code/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,14 @@ export function createClaudeCodeModel(

switch (options?.toolApprovalLevel) {
case "plan":
settings.permissionMode = "plan";
settings.disallowedTools = [...HEADLESS_DISALLOWED_TOOLS];
settings.permissionMode = "bypassPermissions";
settings.disallowedTools = [
...HEADLESS_DISALLOWED_TOOLS,
"Write",
"Edit",
"Bash",
"NotebookEdit",
];
break;
case "readonly":
settings.permissionMode = "bypassPermissions";
Expand Down
1 change: 1 addition & 0 deletions apps/mesh/src/api/access-control.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ describe("Access Control Integration Tests", () => {
metadata: null,
bindings: null,
status: "active",
pinned: false,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
})
Expand Down
6 changes: 3 additions & 3 deletions apps/mesh/src/api/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,8 +329,8 @@ export async function createApp(options: CreateAppOptions = {}) {
const runRegistry = new RunRegistry(cancelReactorDeps, POD_ID);

cancelBroadcast
.start((threadId) => {
runRegistry.execute({ type: "CANCEL", threadId }).catch((err) => {
.start((taskId) => {
runRegistry.execute({ type: "CANCEL", taskId }).catch((err) => {
console.error("[Decopilot] CancelBroadcast execute failed:", err);
});
})
Expand Down Expand Up @@ -986,7 +986,7 @@ export async function createApp(options: CreateAppOptions = {}) {
toolApprovalLevel: config.toolApprovalLevel,
organizationId: thread.organization_id,
userId: thread.created_by,
threadId: thread.id,
taskId: thread.id,
windowSize: config.windowSize,
isResume: true,
},
Expand Down
44 changes: 25 additions & 19 deletions apps/mesh/src/api/routes/deco-sites.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ app.get("/", async (c) => {

const config = getSupabaseConfig();
if (!config) {
return c.json({ error: "Deco integration is not configured" }, 503);
return c.json({ sites: [] });
}
const { supabaseUrl, serviceKey } = config;

Expand Down Expand Up @@ -216,28 +216,34 @@ app.post("/connection", async (c) => {
}

const config = getSupabaseConfig();
if (!config) {
return c.json({ error: "Deco integration is not configured" }, 503);
}
const { supabaseUrl, serviceKey } = config;

try {
const profileId = await resolveProfileId(supabaseUrl, serviceKey, email);
if (!profileId) {
return c.json({ error: "No deco.cx account found for this user" }, 404);
}

const apiKey = await fetchDecoApiKey(supabaseUrl, serviceKey, profileId);
// Local dev fallback: create a stub connection without an API key so the
// full import flow can be tested without Supabase credentials.
const apiKey = config
? await (async () => {
const { supabaseUrl, serviceKey } = config;
const profileId = await resolveProfileId(
supabaseUrl,
serviceKey,
email,
);
if (!profileId) return null;
return fetchDecoApiKey(supabaseUrl, serviceKey, profileId);
})().catch(() => null)
: null;

try {
// Fetch tools and scopes from the MCP server before storing, mirroring
// what COLLECTION_CONNECTIONS_CREATE does so the tools list isn't empty.
const fetchResult = await fetchToolsFromMCP({
id: `pending-${connId}`,
title: `deco.cx — ${siteName}`,
connection_type: "HTTP",
connection_url: ADMIN_MCP,
connection_token: apiKey,
}).catch(() => null);
const fetchResult = apiKey
? await fetchToolsFromMCP({
id: `pending-${connId}`,
title: `deco.cx — ${siteName}`,
connection_type: "HTTP",
connection_url: ADMIN_MCP,
connection_token: apiKey,
}).catch(() => null)
: null;
const tools = fetchResult?.tools?.length ? fetchResult.tools : null;
const configuration_scopes = fetchResult?.scopes?.length
? fetchResult.scopes
Expand Down
4 changes: 2 additions & 2 deletions apps/mesh/src/api/routes/decopilot/cancel-broadcast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

export interface CancelBroadcast {
/** Start listening for cancel broadcasts. When received, call onCancel locally. */
start(onCancel?: (threadId: string) => void): Promise<void>;
start(onCancel?: (taskId: string) => void): Promise<void>;
/** Broadcast a cancellation to all pods (including local). */
broadcast(threadId: string): void;
broadcast(taskId: string): void;
/** Stop listening and release resources. */
stop(): Promise<void>;
}
6 changes: 5 additions & 1 deletion apps/mesh/src/api/routes/decopilot/conversation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,11 @@ export async function processConversation(
.map((part) => {
const p = part as Record<string, unknown>;
if ("providerOptions" in p || "providerMetadata" in p) {
const { providerOptions, providerMetadata, ...rest } = p;
const {
providerOptions: _po,
providerMetadata: _pm,
...rest
} = p;
return rest as typeof part;
}
return part;
Expand Down
10 changes: 5 additions & 5 deletions apps/mesh/src/api/routes/decopilot/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,18 +211,18 @@ export async function validateThreadAccess(
throw new HTTPException(401, { message: "Unauthorized" });
}
const organization = ensureOrganization(c);
const threadId = c.req.param("threadId");
if (!threadId) {
const taskId = c.req.param("threadId");
if (!taskId) {
throw new HTTPException(400, { message: "Missing thread ID" });
}
if (/[.*>\s]/.test(threadId)) {
if (/[.*>\s]/.test(taskId)) {
throw new HTTPException(400, { message: "Invalid thread ID" });
}
const thread = await ctx.storage.threads.get(threadId);
const thread = await ctx.storage.threads.get(taskId);
if (!thread) {
throw new HTTPException(404, { message: "Thread not found" });
}
return { ctx, organization, thread, threadId, userId };
return { ctx, organization, thread, taskId, userId };
}

/**
Expand Down
Loading
Loading