Skip to content

Commit 15e816b

Browse files
authored
v0.9.28: mship contract updates, library
2 parents e0fb406 + 9a72a84 commit 15e816b

86 files changed

Lines changed: 3102 additions & 1951 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎AGENTS.md‎

Lines changed: 0 additions & 1 deletion
This file was deleted.

‎AGENTS.md‎

Lines changed: 162 additions & 0 deletions
Large diffs are not rendered by default.

‎apps/desktop/package.json‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
"@xterm/headless": "6.0.0",
4343
"electron-updater": "6.8.9",
4444
"micromatch": "4.0.8",
45-
"safe-regex2": "5.1.0",
45+
"safe-regex2": "5.1.2",
4646
"pdf-lib": "1.17.1"
4747
},
4848
"devDependencies": {
@@ -51,19 +51,19 @@
5151
"@sim/emcn": "workspace:*",
5252
"@sim/tsconfig": "workspace:*",
5353
"@types/micromatch": "4.0.10",
54-
"@types/node": "24.2.1",
54+
"@types/node": "24.19.2",
5555
"@types/react": "^19",
5656
"@types/react-dom": "^19",
5757
"electron": "43.5.0",
5858
"electron-builder": "26.15.3",
59-
"esbuild": "0.28.1",
59+
"esbuild": "0.28.2",
6060
"jsdom": "^26.0.0",
61-
"postcss": "^8",
61+
"postcss": "^8.5.30",
6262
"postcss-load-config": "6.0.1",
6363
"postgres": "^3.4.5",
6464
"react": "19.2.4",
6565
"react-dom": "19.2.4",
6666
"typescript": "^7.0.2",
67-
"vitest": "^5.0.1"
67+
"vitest": "^5.0.4"
6868
}
6969
}

‎apps/docs/package.json‎

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@
2727
"@sim/logger": "workspace:*",
2828
"@sim/utils": "workspace:*",
2929
"@sim/workflow-renderer": "workspace:*",
30-
"@xyflow/react": "12.11.3",
30+
"@xyflow/react": "12.12.0",
3131
"class-variance-authority": "^0.7.1",
32-
"drizzle-orm": "^0.45.2",
32+
"drizzle-orm": "^0.45.4",
3333
"fumadocs-core": "16.8.5",
3434
"fumadocs-mdx": "14.3.2",
3535
"fumadocs-openapi": "10.8.1",
@@ -39,21 +39,22 @@
3939
"react": "19.2.4",
4040
"react-dom": "19.2.4",
4141
"remark-breaks": "^4.0.0",
42-
"shiki": "4.3.1",
42+
"remark-gfm": "4.0.1",
43+
"shiki": "4.5.0",
44+
"streamdown": "2.5.0",
4345
"framer-motion": "^12.5.0",
4446
"zod": "4.3.6"
4547
},
4648
"devDependencies": {
4749
"@sim/tsconfig": "workspace:*",
48-
"@tailwindcss/postcss": "^4.0.12",
49-
"@types/node": "24.2.1",
50-
"@types/react": "^19.1.2",
51-
"@types/react-dom": "^19.0.4",
52-
"gray-matter": "^4.0.3",
53-
"jsdom": "^26.0.0",
54-
"postcss": "^8.5.3",
55-
"tailwindcss": "^4.0.12",
50+
"@tailwindcss/postcss": "^4.3.3",
51+
"@types/node": "24.19.2",
52+
"@types/react": "^19",
53+
"@types/react-dom": "^19",
54+
"gray-matter": "4.0.3",
55+
"postcss": "^8.5.30",
56+
"tailwindcss": "^4.3.3",
5657
"typescript": "^7.0.2",
57-
"vitest": "^5.0.1"
58+
"vitest": "^5.0.4"
5859
}
5960
}

‎apps/realtime/package.json‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,21 @@
3232
"@sim/workflow-persistence": "workspace:*",
3333
"@sim/workflow-types": "workspace:*",
3434
"@socket.io/redis-adapter": "8.3.0",
35-
"drizzle-orm": "^0.45.2",
36-
"lib0": "0.2.117",
35+
"drizzle-orm": "^0.45.4",
36+
"lib0": "0.2.119",
3737
"postgres": "^3.4.5",
3838
"redis": "5.10.0",
39-
"socket.io": "^4.8.1",
39+
"socket.io": "^4.8.4",
4040
"y-protocols": "1.0.7",
41-
"yjs": "13.6.31",
41+
"yjs": "13.6.33",
4242
"zod": "4.3.6"
4343
},
4444
"devDependencies": {
4545
"@sim/testing": "workspace:*",
4646
"@sim/tsconfig": "workspace:*",
47-
"@types/node": "24.2.1",
48-
"socket.io-client": "4.8.1",
47+
"@types/node": "24.19.2",
48+
"socket.io-client": "4.8.4",
4949
"typescript": "^7.0.2",
50-
"vitest": "^5.0.1"
50+
"vitest": "^5.0.4"
5151
}
5252
}

‎apps/sim/app/(landing)/comparisons/[provider]/page.tsx‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { LIBRARY_SECTION } from '@/lib/library/seo'
99
import { COMPARISON_SECTIONS, getFactGroup } from '@/app/(landing)/comparisons/comparison-sections'
1010
import { BrandIconTile, SimIconTile } from '@/app/(landing)/comparisons/components/brand-icon-tile'
1111
import { ComparisonCards } from '@/app/(landing)/comparisons/components/comparison-cards'
12+
import { ComparisonLinkRow } from '@/app/(landing)/comparisons/components/comparison-link-row'
1213
import { ComparisonTable } from '@/app/(landing)/comparisons/components/comparison-table'
1314
import { ProseText } from '@/app/(landing)/comparisons/components/prose-text'
1415
import { getLibraryPostsForCompetitor } from '@/app/(landing)/comparisons/library-links'
@@ -91,6 +92,7 @@ export default async function ComparisonProviderPage({
9192
const relatedPosts = await getLibraryPostsForCompetitor(competitor)
9293
const verdict = buildBottomLine(competitor)
9394
const CompetitorIcon = competitor.brand?.icon
95+
const otherCompetitors = ALL_COMPETITORS.filter((other) => other.id !== competitor.id)
9496

9597
const breadcrumbJsonLd = {
9698
'@context': 'https://schema.org',
@@ -378,6 +380,22 @@ export default async function ComparisonProviderPage({
378380
</>
379381
) : null}
380382

383+
<section aria-labelledby='more-comparisons-heading'>
384+
<h2
385+
id='more-comparisons-heading'
386+
className='px-6 pt-10 pb-6 text-[var(--text-primary)] text-xl leading-[100%] tracking-[-0.02em] lg:text-2xl'
387+
>
388+
More comparisons
389+
</h2>
390+
<ul className='grid grid-cols-1 gap-px border-[var(--border)] border-y bg-[var(--border)] lg:grid-cols-2'>
391+
{otherCompetitors.map((other) => (
392+
<li key={other.id} className='bg-[var(--bg)] lg:odd:last:col-span-2'>
393+
<ComparisonLinkRow competitor={other} />
394+
</li>
395+
))}
396+
</ul>
397+
</section>
398+
381399
<section aria-labelledby='faq-heading' className='px-6 py-10'>
382400
<h2
383401
id='faq-heading'

‎apps/sim/app/(landing)/comparisons/utils.ts‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,11 @@ export interface ComparisonVerdict {
9595

9696
export function buildBottomLine(competitor: CompetitorProfile): ComparisonVerdict {
9797
const strength = competitor.standoutFeatures[0]
98-
const chooseCompetitor = strength
99-
? `Choose ${competitor.name} if you specifically need ${lowercaseFirst(strength.title)}: ${strength.description}`
100-
: `Choose ${competitor.name} if its specific strengths, documented above, matter more to your team than an AI-native, self-hostable workspace.`
98+
const chooseCompetitor =
99+
competitor.chooseCompetitorAnswer ??
100+
(strength
101+
? `Choose ${competitor.name} if you specifically need ${lowercaseFirst(strength.title)}: ${strength.description}`
102+
: `Choose ${competitor.name} if its specific strengths, documented above, matter more to your team than an AI-native, self-hostable workspace.`)
101103

102104
return {
103105
chooseSim: `Choose Sim if you want an open-source, self-hostable AI workspace that treats AI agents as first-class citizens: native multi-LLM support, real-time multiplayer editing, human-in-the-loop approvals, and, on the Enterprise plan, environment promotion (dev/qa/prod) and governance (SSO, credential-level permissions, audit logs) built in rather than bolted on.`,

‎apps/sim/app/_shell/providers/theme-provider.tsx‎

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useState } from 'react'
44
import { usePathname } from 'next/navigation'
55
import type { ThemeProviderProps } from 'next-themes'
66
import { ThemeProvider as NextThemesProvider } from 'next-themes'
7-
import { LANDING_ROUTES } from '@/lib/landing/routes'
7+
import { isLandingPath } from '@/lib/landing/routes'
88

99
/**
1010
* First path segments outside the `(landing)` group whose pages pin the light
@@ -41,6 +41,8 @@ const NON_LANDING_LIGHT_SEGMENTS = [
4141
*/
4242
const LIGHT_MODE_SEGMENTS: ReadonlySet<string> = new Set(NON_LANDING_LIGHT_SEGMENTS)
4343

44+
const APP_SURFACE = { defaultTheme: 'system', storageKey: 'sim-theme' } as const
45+
4446
/**
4547
* The marketing surface: the root plus every `app/(landing)` segment. These
4648
* pages keep their own stored theme, written only by the landing footer's
@@ -50,16 +52,8 @@ const LIGHT_MODE_SEGMENTS: ReadonlySet<string> = new Set(NON_LANDING_LIGHT_SEGME
5052
* every signed-in user, which would render the marketing site in the OS theme
5153
* and overwrite any choice the footer toggle made.
5254
*/
53-
const LANDING_SEGMENTS: ReadonlySet<string> = new Set(LANDING_ROUTES)
54-
55-
const APP_SURFACE = { defaultTheme: 'system', storageKey: 'sim-theme' } as const
5655
const LANDING_SURFACE = { defaultTheme: 'light', storageKey: 'sim-landing-theme' } as const
5756

58-
function isLandingPath(pathname: string): boolean {
59-
const firstSegment = pathname.split('/')[1]
60-
return firstSegment === '' || LANDING_SEGMENTS.has(firstSegment)
61-
}
62-
6357
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
6458
const pathname = usePathname()
6559

‎apps/sim/app/api/mcp/oauth/start/route.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const DCR_UNSUPPORTED_MESSAGE =
4949
/**
5050
* The MCP SDK throws a plain `Error` (no typed class or code) when an auth server lacks a
5151
* `registration_endpoint`, so this string-match is the only available signal. Pinned to
52-
* `@modelcontextprotocol/sdk` v1.31.0 `registerClient` (client/auth.js): "Incompatible auth
52+
* `@modelcontextprotocol/sdk` v1.32.1 `registerClient` (client/auth.js): "Incompatible auth
5353
* server: does not support dynamic client registration". If a version bump rephrases this, the
5454
* 422 branch silently stops firing (users get a generic 500) — update the substring here.
5555
*/

‎apps/sim/app/api/webhooks/agentmail/route.test.ts‎

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,8 @@ const { mockVerify, mockExecuteInboxTask } = vi.hoisted(() => ({
1515
mockExecuteInboxTask: vi.fn(),
1616
}))
1717

18-
vi.mock('svix', () => ({
19-
Webhook: class {
20-
private readonly secret: string
21-
constructor(secret: string) {
22-
this.secret = secret
23-
}
24-
verify(payload: string, headers: Record<string, string>) {
25-
return mockVerify(this.secret, payload, headers)
26-
}
27-
},
18+
vi.mock('@sim/security/standard-webhooks', () => ({
19+
verifyStandardWebhook: mockVerify,
2820
}))
2921

3022
vi.mock('@/lib/core/admission/gate', () => admissionGateMock)
@@ -92,9 +84,7 @@ describe('POST /api/webhooks/agentmail', () => {
9284

9385
mockTryAdmit.mockReturnValue({ release: mockRelease })
9486
mockExecuteInboxTask.mockResolvedValue(undefined)
95-
mockVerify.mockImplementation(() => {
96-
throw new Error('signature mismatch')
97-
})
87+
mockVerify.mockReturnValue({ valid: false, reason: 'no_matching_signature' })
9888
})
9989

10090
it('checks the signature against only the secret the payload routes to', async () => {
@@ -106,12 +96,14 @@ describe('POST /api/webhooks/agentmail', () => {
10696
expect(mockEq).toHaveBeenCalledWith(schemaMock.workspace.inboxProviderId, TARGET_INBOX_ID)
10797
expect(dbChainMockFns.limit).toHaveBeenCalledWith(1)
10898
expect(mockVerify).toHaveBeenCalledTimes(1)
109-
expect(mockVerify).toHaveBeenCalledWith('whsec_b', expect.any(String), expect.any(Object))
99+
expect(mockVerify).toHaveBeenCalledWith(
100+
expect.objectContaining({ secret: 'whsec_b', headerPrefix: 'svix' })
101+
)
110102
})
111103

112104
it('rejects a payload naming an inbox no workspace owns, without hashing it', async () => {
113105
queueTableRows(schemaMock.workspace, [])
114-
mockVerify.mockReturnValue(undefined)
106+
mockVerify.mockReturnValue({ valid: true })
115107

116108
const response = await POST(
117109
webhookRequest(envelope({ inbox_id: 'agent-unknown@agentmail.to' }))

0 commit comments

Comments
 (0)