源码快照 @ 2026-09-02 (source-only, 剔除非源码素材)

This commit is contained in:
agent-radar
2026-09-02 01:05:41 +08:00
commit 04bac1f6e2
2200 changed files with 489415 additions and 0 deletions
+12
View File
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Connection action</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/connection-action.tsx"></script>
</body>
</html>
+42
View File
@@ -0,0 +1,42 @@
{
"name": "@openwork/mcp-apps",
"version": "0.0.0",
"private": true,
"type": "module",
"exports": {
"./skill-created": {
"types": "./dist/skill-created.d.ts",
"default": "./dist/skill-created.js"
},
"./connection-action": {
"types": "./dist/connection-action.d.ts",
"default": "./dist/connection-action.js"
},
"./plugin-flow": {
"types": "./dist/plugin-flow.d.ts",
"default": "./dist/plugin-flow.js"
}
},
"files": [
"dist"
],
"scripts": {
"build": "node scripts/build-apps.mjs",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^1.7.5",
"@openwork/types": "workspace:*",
"react": "catalog:",
"react-dom": "catalog:",
"zod": "^4.3.6"
},
"devDependencies": {
"@types/react": "19.2.14",
"@types/react-dom": "19.2.3",
"@vitejs/plugin-react": "^5.0.4",
"typescript": "^5.9.0",
"vite": "^6.4.3",
"vite-plugin-singlefile": "^2.3.0"
}
}
+12
View File
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Plugin flow</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/plugin-flow.tsx"></script>
</body>
</html>
+52
View File
@@ -0,0 +1,52 @@
import { spawnSync } from "node:child_process"
import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises"
import { fileURLToPath } from "node:url"
const APPS = [
{ entry: "skill-created", exportName: "skillCreatedAppHtml" },
{ entry: "connection-action", exportName: "connectionActionAppHtml" },
{ entry: "plugin-flow", exportName: "pluginFlowAppHtml" },
]
const packageDir = fileURLToPath(new URL("..", import.meta.url))
const distUrl = new URL("../dist/", import.meta.url)
// Concurrent consumers (parallel test files) import from dist while a build
// runs, so never clear dist: stage into a scratch dir and atomically rename
// each artifact into place.
const scratchBase = new URL(`../dist-build-${process.pid}/`, import.meta.url)
await mkdir(distUrl, { recursive: true })
async function writeAtomic(fileName, contents) {
const finalUrl = new URL(fileName, distUrl)
const temporaryUrl = new URL(`${fileName}.tmp-${process.pid}`, distUrl)
await writeFile(temporaryUrl, contents)
await rename(temporaryUrl, finalUrl)
}
try {
for (const app of APPS) {
const scratchDir = new URL(`${app.entry}/`, scratchBase)
const build = spawnSync("pnpm", ["exec", "vite", "build", "--outDir", fileURLToPath(scratchDir)], {
cwd: packageDir,
stdio: "inherit",
env: { ...process.env, OPENWORK_MCP_APP: app.entry },
})
if (build.status !== 0) {
throw new Error(`vite build failed for ${app.entry}`)
}
const html = await readFile(new URL(`${app.entry}.html`, scratchDir), "utf8")
await writeAtomic(`${app.entry}.js`, [
`export const ${app.exportName} = ${JSON.stringify(html)}`,
`export default ${app.exportName}`,
"",
].join("\n"))
await writeAtomic(`${app.entry}.d.ts`, [
`export declare const ${app.exportName}: string`,
`export default ${app.exportName}`,
"",
].join("\n"))
}
} finally {
await rm(scratchBase, { recursive: true, force: true })
}
+12
View File
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Skill created</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/skill-created.tsx"></script>
</body>
</html>
@@ -0,0 +1,81 @@
import { connectionActionPayloadSchema, type ConnectionActionPayload } from "@openwork/types/connection-action-app"
import { mountMcpApp } from "./shared/bridge"
import { AlertIcon, AppHeader, ArrowIcon, CardBody, CardFooter, CheckIcon, KeyValueGrid, PlugIcon, type Tone } from "./shared/ui"
import "./shared/theme.css"
const STATE_PRESENTATION: Record<ConnectionActionPayload["state"], {
tone: Tone
badge: string
title: string
}> = {
connected: { tone: "success", badge: "Connected", title: "Connection ready" },
needs_connection: { tone: "warning", badge: "Not connected", title: "Connection needed" },
reauth_required: { tone: "warning", badge: "Sign-in required", title: "Reconnect needed" },
provider_error: { tone: "danger", badge: "Provider error", title: "Connection error" },
}
const ACTOR_LABEL: Record<NonNullable<ConnectionActionPayload["actor"]>, string> = {
member: "You",
organization_admin: "An organization admin",
provider_admin: "The provider admin",
network_admin: "A network admin",
openwork: "OpenWork support",
}
const SURFACE_LABEL: Record<NonNullable<ConnectionActionPayload["action"]>["surface"], string> = {
openwork_your_connections: "Your Connections",
openwork_organization_connections: "Organization Connections",
provider_admin_console: "Provider admin console",
network_infrastructure: "Network infrastructure",
openwork_support: "OpenWork support",
}
mountMcpApp({
name: "OpenWork Connection Action",
waitingLabel: "Checking the connection...",
schema: connectionActionPayloadSchema,
render: (payload, app) => {
const presentation = STATE_PRESENTATION[payload.state]
const actionUrl = payload.action?.url
const openAction = () => {
if (actionUrl) void app?.openLink({ url: actionUrl })
}
return (
<main className="card">
<AppHeader
tone={presentation.tone}
icon={payload.state === "connected" ? <CheckIcon /> : payload.state === "provider_error" ? <AlertIcon /> : <PlugIcon />}
title={presentation.title}
subtitle={payload.connectionName}
badge={{ tone: presentation.tone, label: presentation.badge }}
/>
<CardBody>
<p className="name">{payload.connectionName}</p>
<p className="description">{payload.message}</p>
{payload.action ? (
<KeyValueGrid
items={[
...(payload.actor ? [{ label: "Who acts", value: ACTOR_LABEL[payload.actor] }] : []),
{ label: "Where", value: SURFACE_LABEL[payload.action.surface] },
]}
/>
) : null}
</CardBody>
<CardFooter
footnote={payload.state === "connected"
? "Tools from this connection are available in chat right now."
: "After it is fixed, ask again in this chat — the agent searches live."}
action={payload.action ? (
actionUrl ? (
<button className="action-primary" type="button" onClick={openAction}>
{payload.action.label} <ArrowIcon />
</button>
) : (
<span className="badge" data-tone={presentation.tone}>{payload.action.label}</span>
)
) : undefined}
/>
</main>
)
},
})
+67
View File
@@ -0,0 +1,67 @@
import { pluginFlowPayloadSchema, type PluginFlowPayload } from "@openwork/types/plugin-flow-app"
import { mountMcpApp } from "./shared/bridge"
import { AppHeader, CardBody, CardFooter, CheckIcon, KeyValueGrid, ShareIcon } from "./shared/ui"
import "./shared/theme.css"
const MODE_PRESENTATION: Record<PluginFlowPayload["mode"], {
title: string
subtitle: string
footnote: string
}> = {
marketplace_plugin_added: {
title: "Plugin added to marketplace",
subtitle: "The plugin is now listed for everyone with marketplace access.",
footnote: "Members with access can install it from the marketplace.",
},
plugin_access_granted: {
title: "Plugin shared",
subtitle: "Access was granted successfully.",
footnote: "The recipient can use this plugin's skills in chat immediately.",
},
marketplace_access_granted: {
title: "Marketplace access granted",
subtitle: "The member can now browse this marketplace.",
footnote: "They can install plugins from it right away.",
},
}
const RECIPIENT_LABEL: Record<NonNullable<PluginFlowPayload["recipient"]>["kind"], string> = {
member: "Member",
team: "Team",
org_wide: "Entire organization",
}
mountMcpApp({
name: "OpenWork Plugin Flow",
waitingLabel: "Finishing up...",
schema: pluginFlowPayloadSchema,
render: (payload) => {
const presentation = MODE_PRESENTATION[payload.mode]
const items: Array<{ label: string; value: string; mono?: boolean }> = []
if (payload.pluginId) items.push({ label: "Plugin", value: payload.pluginId, mono: true })
if (payload.marketplaceId) items.push({ label: "Marketplace", value: payload.marketplaceId, mono: true })
if (payload.recipient) {
items.push({
label: RECIPIENT_LABEL[payload.recipient.kind],
value: payload.recipient.id ?? "org-wide",
mono: payload.recipient.id !== null,
})
if (payload.recipient.role) items.push({ label: "Role", value: payload.recipient.role })
}
return (
<main className="card">
<AppHeader
tone={payload.mode === "marketplace_plugin_added" ? "info" : "success"}
icon={payload.mode === "marketplace_plugin_added" ? <ShareIcon /> : <CheckIcon />}
title={presentation.title}
subtitle={presentation.subtitle}
badge={{ tone: "success", label: "Done" }}
/>
<CardBody>
<KeyValueGrid items={items} />
</CardBody>
<CardFooter footnote={presentation.footnote} />
</main>
)
},
})
+58
View File
@@ -0,0 +1,58 @@
import { StrictMode, useState, type ReactNode } from "react"
import { createRoot } from "react-dom/client"
import { useApp, useHostStyles } from "@modelcontextprotocol/ext-apps/react"
import type { App } from "@modelcontextprotocol/ext-apps"
import type { z } from "zod"
import { StatusCard } from "./ui"
/**
* Standard bootstrap for every first-party OpenWork MCP App: connect to the
* host over the MCP Apps bridge, validate the tool's structuredContent
* against the app's zod contract, and hand a typed payload to the view.
*/
export function mountMcpApp<Schema extends z.ZodType>(config: {
name: string
waitingLabel: string
schema: Schema
render: (payload: z.infer<Schema>, app: App | null) => ReactNode
}) {
function AppRoot() {
const [payload, setPayload] = useState<z.infer<Schema> | null>(null)
const [resultError, setResultError] = useState<string | null>(null)
const { app, error } = useApp({
appInfo: { name: config.name, version: "1.0.0" },
capabilities: {},
onAppCreated: (createdApp) => {
createdApp.ontoolresult = (result) => {
const parsed = config.schema.safeParse(result.structuredContent)
if (!parsed.success) {
setResultError("The result did not match the expected data contract.")
return
}
setResultError(null)
setPayload(parsed.data)
}
createdApp.ontoolcancelled = ({ reason }) => {
setResultError(reason ?? "The tool call was cancelled.")
}
},
})
useHostStyles(app, app?.getHostContext())
if (error || resultError) {
return <StatusCard>{error?.message ?? resultError}</StatusCard>
}
if (!payload) {
return <StatusCard>{config.waitingLabel}</StatusCard>
}
return <>{config.render(payload, app)}</>
}
const root = document.getElementById("root")
if (!root) throw new Error(`${config.name} root element is missing.`)
createRoot(root).render(
<StrictMode>
<AppRoot />
</StrictMode>,
)
}
+289
View File
@@ -0,0 +1,289 @@
:root {
color-scheme: light dark;
color: var(--color-text-primary, #1c2024);
background: transparent;
font-family: var(--font-sans, ui-sans-serif, system-ui, sans-serif);
--app-bg: var(--color-background-primary, #fff);
--app-bg-subtle: var(--color-background-secondary, #f1f3f5);
--app-bg-hover: var(--color-background-tertiary, #f8f9fa);
--app-text: var(--color-text-primary, #1c2024);
--app-muted: var(--color-text-secondary, #60646c);
--app-border: var(--color-border-primary, #f3f4f6);
--app-accent: var(--color-background-inverse, #011627);
--app-accent-fg: var(--color-text-inverse, #fff);
--app-success: var(--color-text-success, #2a7e3b);
--app-success-bg: var(--color-background-success, #e9f6e9);
--app-success-border: var(--color-border-success, rgb(42 126 59 / 25%));
--app-warning: var(--color-text-warning, #ab6400);
--app-warning-bg: var(--color-background-warning, #fff1d6);
--app-warning-border: var(--color-border-warning, rgb(171 100 0 / 28%));
--app-danger: var(--color-text-danger, #ce2c31);
--app-danger-bg: var(--color-background-danger, #feebec);
--app-danger-border: var(--color-border-danger, rgb(206 44 49 / 25%));
--app-info: var(--color-text-info, #0d74ce);
--app-info-bg: var(--color-background-info, #e6f4fe);
--app-info-border: var(--color-border-info, rgb(13 116 206 / 25%));
--app-radius: var(--border-radius-lg, 16px);
--app-radius-sm: 10px;
--app-shadow: var(--shadow-sm, 0 1px 2px rgb(15 23 42 / 5%));
}
* {
box-sizing: border-box;
}
body {
margin: 0;
min-width: 0;
background: transparent;
}
button {
font: inherit;
}
.card {
overflow: hidden;
max-width: 42rem;
border: 1px solid var(--app-border);
border-radius: var(--app-radius);
background: var(--app-bg);
box-shadow: var(--app-shadow);
}
.card-status {
display: grid;
min-height: 96px;
place-items: center;
padding: 16px;
color: var(--app-muted);
font-size: 13px;
}
.header {
display: flex;
gap: 12px;
align-items: flex-start;
padding: 12px 16px;
border-bottom: 1px solid var(--app-border);
}
.mark {
display: flex;
flex-shrink: 0;
width: 32px;
height: 32px;
margin-top: 2px;
align-items: center;
justify-content: center;
border: 1px solid var(--app-border);
border-radius: 999px;
background: var(--app-bg-hover);
color: var(--app-muted);
}
.mark svg {
width: 16px;
height: 16px;
}
.mark[data-tone="success"] {
border-color: var(--app-success-border);
background: var(--app-success-bg);
color: var(--app-success);
}
.mark[data-tone="warning"] {
border-color: var(--app-warning-border);
background: var(--app-warning-bg);
color: var(--app-warning);
}
.mark[data-tone="danger"] {
border-color: var(--app-danger-border);
background: var(--app-danger-bg);
color: var(--app-danger);
}
.mark[data-tone="info"] {
border-color: var(--app-info-border);
background: var(--app-info-bg);
color: var(--app-info);
}
.header-copy {
min-width: 0;
flex: 1;
}
h1 {
overflow: hidden;
margin: 0;
font-size: 14px;
font-weight: 600;
line-height: 1.35;
text-overflow: ellipsis;
white-space: nowrap;
}
.subtitle {
overflow: hidden;
margin: 2px 0 0;
color: var(--app-muted);
font-size: 12px;
line-height: 1.4;
text-overflow: ellipsis;
white-space: nowrap;
}
.badge {
flex-shrink: 0;
margin-top: 4px;
padding: 3px 9px;
border: 1px solid var(--app-border);
border-radius: 999px;
color: var(--app-muted);
font-size: 11px;
font-weight: 600;
white-space: nowrap;
}
.badge[data-tone="success"] {
border-color: var(--app-success-border);
background: var(--app-success-bg);
color: var(--app-success);
}
.badge[data-tone="warning"] {
border-color: var(--app-warning-border);
background: var(--app-warning-bg);
color: var(--app-warning);
}
.badge[data-tone="danger"] {
border-color: var(--app-danger-border);
background: var(--app-danger-bg);
color: var(--app-danger);
}
.badge[data-tone="info"] {
border-color: var(--app-info-border);
background: var(--app-info-bg);
color: var(--app-info);
}
.body {
display: grid;
gap: 12px;
padding: 12px 16px;
}
.name {
overflow: hidden;
margin: 0;
font-size: 14px;
font-weight: 500;
text-overflow: ellipsis;
white-space: nowrap;
}
.description {
margin: 0;
color: var(--app-muted);
font-size: 13px;
line-height: 1.55;
}
.identifiers {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 8px;
margin: 0;
}
.identifiers > div {
min-width: 0;
padding: 8px 11px;
border-radius: var(--app-radius-sm);
background: var(--app-bg-subtle);
}
.identifiers dt {
margin-bottom: 3px;
color: var(--app-muted);
font-size: 10px;
font-weight: 600;
letter-spacing: .05em;
text-transform: uppercase;
}
.identifiers dd {
overflow: hidden;
margin: 0;
font-size: 12px;
text-overflow: ellipsis;
white-space: nowrap;
}
.identifiers dd[data-mono="true"] {
font-family: var(--font-mono, ui-monospace, monospace);
font-size: 11px;
}
.footer {
display: flex;
gap: 12px;
align-items: center;
justify-content: space-between;
padding: 12px 16px;
border-top: 1px solid var(--app-border);
}
.footnote {
min-width: 0;
flex: 1;
margin: 0;
color: var(--app-muted);
font-size: 12px;
line-height: 1.45;
}
.action-primary {
display: inline-flex;
flex-shrink: 0;
gap: 6px;
align-items: center;
padding: 7px 12px;
border: 0;
border-radius: var(--app-radius-sm);
background: var(--app-accent);
color: var(--app-accent-fg);
cursor: pointer;
font-size: 12px;
font-weight: 600;
}
.action-primary:hover {
opacity: .9;
}
.action-primary svg {
width: 13px;
height: 13px;
}
@media (max-width: 480px) {
.badge {
display: none;
}
.identifiers {
grid-template-columns: 1fr;
}
.footer {
flex-direction: column;
align-items: stretch;
}
}
+105
View File
@@ -0,0 +1,105 @@
import type { ReactNode } from "react"
export type Tone = "neutral" | "success" | "warning" | "danger" | "info"
export function CheckIcon() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
<path d="M20 6 9 17l-5-5" />
</svg>
)
}
export function PlugIcon() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
<path d="M12 22v-5" />
<path d="M9 8V2" />
<path d="M15 8V2" />
<path d="M18 8v5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z" />
</svg>
)
}
export function AlertIcon() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
<path d="M12 9v4" />
<path d="M12 17h.01" />
<path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0Z" />
</svg>
)
}
export function ShareIcon() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
<path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8" />
<path d="m16 6-4-4-4 4" />
<path d="M12 2v13" />
</svg>
)
}
export function ArrowIcon() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
<path d="M7 17 17 7" />
<path d="M8 7h9v9" />
</svg>
)
}
export function AppHeader(props: {
tone: Tone
icon: ReactNode
title: string
subtitle?: string
badge?: { tone: Tone; label: string } | null
}) {
return (
<header className="header">
<span className="mark" data-tone={props.tone === "neutral" ? undefined : props.tone} aria-hidden="true">{props.icon}</span>
<div className="header-copy">
<h1>{props.title}</h1>
{props.subtitle ? <p className="subtitle">{props.subtitle}</p> : null}
</div>
{props.badge ? (
<span className="badge" data-tone={props.badge.tone === "neutral" ? undefined : props.badge.tone}>
{props.badge.label}
</span>
) : null}
</header>
)
}
export function CardBody(props: { children: ReactNode }) {
return <div className="body">{props.children}</div>
}
export function CardFooter(props: { footnote: string; action?: ReactNode }) {
return (
<footer className="footer">
<p className="footnote">{props.footnote}</p>
{props.action ?? null}
</footer>
)
}
export function KeyValueGrid(props: { items: Array<{ label: string; value: string; mono?: boolean }> }) {
if (props.items.length === 0) return null
return (
<dl className="identifiers">
{props.items.map((item) => (
<div key={item.label}>
<dt>{item.label}</dt>
<dd data-mono={item.mono === true ? "true" : undefined}>{item.value}</dd>
</div>
))}
</dl>
)
}
export function StatusCard(props: { children: ReactNode }) {
return <main className="card card-status">{props.children}</main>
}
+47
View File
@@ -0,0 +1,47 @@
import { skillCreatedPayloadSchema } from "@openwork/types/skill-created-app"
import { mountMcpApp } from "./shared/bridge"
import { AppHeader, ArrowIcon, CardBody, CardFooter, CheckIcon, KeyValueGrid } from "./shared/ui"
import "./shared/theme.css"
mountMcpApp({
name: "OpenWork Skill Saved",
waitingLabel: "Finishing your skill...",
schema: skillCreatedPayloadSchema,
render: (payload, app) => {
const updated = payload.mode === "updated"
const openLibrary = () => {
if (payload.libraryUrl) void app?.openLink({ url: payload.libraryUrl })
}
return (
<main className="card">
<AppHeader
tone="success"
icon={<CheckIcon />}
title={updated ? "Skill updated" : "Skill created"}
subtitle={updated
? "A new version is live for everyone with access."
: "Private to you until you share it or add it to a marketplace."}
badge={{ tone: "success", label: "Ready" }}
/>
<CardBody>
<p className="name">{payload.name}</p>
<p className="description">{payload.description}</p>
<KeyValueGrid
items={[
{ label: "Plugin", value: payload.pluginId, mono: true },
{ label: "Skill", value: payload.skillId, mono: true },
]}
/>
</CardBody>
<CardFooter
footnote="Usable in this chat right now."
action={payload.libraryUrl ? (
<button className="action-primary" type="button" onClick={openLibrary}>
Open in Library <ArrowIcon />
</button>
) : undefined}
/>
</main>
)
},
})
+12
View File
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"jsx": "react-jsx",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"module": "ESNext",
"moduleResolution": "Bundler",
"noEmit": true,
"strict": true,
"target": "ES2022"
},
"include": ["src", "vite.config.ts"]
}
+20
View File
@@ -0,0 +1,20 @@
import react from "@vitejs/plugin-react"
import { defineConfig } from "vite"
import { viteSingleFile } from "vite-plugin-singlefile"
const app = (process.env.OPENWORK_MCP_APP ?? "skill-created").trim()
export default defineConfig({
plugins: [react(), viteSingleFile({ removeViteModuleLoader: true })],
build: {
cssCodeSplit: false,
// The build script stages each app into its own scratch outDir and
// renames artifacts into dist atomically, so nothing here may clear
// shared output that concurrent consumers are importing.
emptyOutDir: true,
modulePreload: { polyfill: false },
rollupOptions: {
input: `${app}.html`,
},
},
})