@appthen/vibe-workspace 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,10 +3,30 @@ import { fileURLToPath } from "node:url";
3
3
  import path from "node:path";
4
4
  import { createHash } from "node:crypto";
5
5
  import { spawnSync } from "node:child_process";
6
+ import { createRequire } from "node:module";
6
7
  import { C as CURRENT_EXTENSION_API_VERSION, a as CURRENT_EXTENSION_MANIFEST_VERSION, v as validateManifest } from "./ExtensionManifestSchema-BIuNTfeS.js";
7
8
  const EXTENSION_WORKSPACE_CONFIG = "appthen-extension-workspace.json";
8
9
  const EXTENSION_PACKAGE_EXTENSION = ".appthen-extension.json";
9
10
  const EXTENSION_BUNDLE_ENTRY = "entry.js";
11
+ function resolveFromPackageRoot(packageRoot, spec) {
12
+ try {
13
+ return createRequire(path.join(packageRoot, "package.json")).resolve(spec);
14
+ } catch {
15
+ return void 0;
16
+ }
17
+ }
18
+ function resolvePackageDirFromPackageRoot(packageRoot, spec) {
19
+ const entry = resolveFromPackageRoot(packageRoot, spec);
20
+ if (!entry) return void 0;
21
+ let dir = path.dirname(entry);
22
+ for (let i = 0; i < 6; i += 1) {
23
+ if (existsSync(path.join(dir, "package.json"))) return dir;
24
+ const parent = path.dirname(dir);
25
+ if (parent === dir) break;
26
+ dir = parent;
27
+ }
28
+ return void 0;
29
+ }
10
30
  function writeExtensionTailwindEntry(workspaceRoot, packageRoot) {
11
31
  const generatedDir = path.join(workspaceRoot, ".appthen", "generated");
12
32
  mkdirSync(generatedDir, { recursive: true });
@@ -15,8 +35,12 @@ function writeExtensionTailwindEntry(workspaceRoot, packageRoot) {
15
35
  const extensionsDir = path.resolve(workspaceRoot, config.extensionsDir);
16
36
  const resolvedPackageRoot = path.resolve(packageRoot);
17
37
  const tailwindConfig = path.join(resolvedPackageRoot, "tailwind.config.js");
18
- const tailwindEntryCss = path.join(resolvedPackageRoot, "node_modules", "tailwindcss", "index.css");
19
- const tailwindImport = existsSync(tailwindEntryCss) ? tailwindEntryCss.replace(/\\/g, "/") : "tailwindcss";
38
+ const tailwindEntryCssCandidates = [
39
+ resolvePackageDirFromPackageRoot(resolvedPackageRoot, "tailwindcss"),
40
+ path.join(resolvedPackageRoot, "node_modules", "tailwindcss")
41
+ ].filter((candidate) => Boolean(candidate)).map((pkgDir) => path.join(pkgDir, "index.css"));
42
+ const tailwindEntryCss = tailwindEntryCssCandidates.find((candidate) => existsSync(candidate));
43
+ const tailwindImport = tailwindEntryCss ? tailwindEntryCss.replace(/\\/g, "/") : "tailwindcss";
20
44
  writeFileSync(
21
45
  cssPath,
22
46
  `@import "${tailwindImport}";
@@ -336,7 +360,8 @@ function createExtensionViteConfigSource(input) {
336
360
  ["@appthen/vibe-workspace", path.join(input.packageRoot, "dist", "index.js")]
337
361
  ] : [];
338
362
  const aliasEntries = packageAliases.map(([find, replacement]) => ` { find: ${JSON.stringify(find)}, replacement: ${JSON.stringify(replacement)} }`).join(",\n");
339
- const tailwindPostcssEntry = input.packageRoot ? path.join(input.packageRoot, "node_modules", "@tailwindcss", "postcss", "dist", "index.mjs") : "";
363
+ const tailwindPostcssPkgDir = input.packageRoot ? resolvePackageDirFromPackageRoot(input.packageRoot, "@tailwindcss/postcss") : void 0;
364
+ const tailwindPostcssEntry = tailwindPostcssPkgDir ? path.join(tailwindPostcssPkgDir, "dist", "index.mjs") : "";
340
365
  const postcssImport = existsSync(tailwindPostcssEntry) ? `import tailwindPostcss from ${JSON.stringify(tailwindPostcssEntry.replace(/\\/g, "/"))};
341
366
  ` : "";
342
367
  return `${postcssImport}import { defineConfig } from 'vite';
@@ -1587,6 +1612,19 @@ ${modules.join(",\n")}
1587
1612
  return { devRoot, count: entries.length, port };
1588
1613
  }
1589
1614
  function createViteConfigSource(workspaceRoot, packageRoot) {
1615
+ let postcssSnippet;
1616
+ let postcssImport = "";
1617
+ const tailwindPostcssPkgDir = packageRoot ? resolvePackageDirFromPackageRoot(packageRoot, "@tailwindcss/postcss") : void 0;
1618
+ const tailwindPostcssEntry = tailwindPostcssPkgDir ? path.join(tailwindPostcssPkgDir, "dist", "index.mjs") : void 0;
1619
+ if (tailwindPostcssEntry && existsSync(tailwindPostcssEntry)) {
1620
+ postcssImport = `import tailwindPostcss from ${JSON.stringify(tailwindPostcssEntry.replace(/\\/g, "/"))};
1621
+ `;
1622
+ postcssSnippet = " css: {\n postcss: {\n plugins: [tailwindPostcss()],\n },\n },";
1623
+ } else {
1624
+ postcssSnippet = ` css: {
1625
+ postcss: ${JSON.stringify(path.join(packageRoot || workspaceRoot, "postcss.config.js"))},
1626
+ },`;
1627
+ }
1590
1628
  const packageAliases = packageRoot ? [
1591
1629
  {
1592
1630
  find: "@appthen/vibe-workspace/extension-dev-workbench",
@@ -1628,13 +1666,11 @@ function createViteConfigSource(workspaceRoot, packageRoot) {
1628
1666
  const aliasEntries = packageAliases.map(
1629
1667
  (entry) => ` { find: ${JSON.stringify(entry.find)}, replacement: ${JSON.stringify(entry.replacement)} }`
1630
1668
  ).join(",\n");
1631
- return `import { defineConfig } from 'vite';
1669
+ return `${postcssImport}import { defineConfig } from 'vite';
1632
1670
  import react from '@vitejs/plugin-react';
1633
1671
 
1634
1672
  export default defineConfig({
1635
- css: {
1636
- postcss: ${JSON.stringify(path.join(packageRoot || workspaceRoot, "postcss.config.js"))},
1637
- },
1673
+ ${postcssSnippet}
1638
1674
  plugins: [react()],
1639
1675
  server: {
1640
1676
  fs: {
@@ -1663,4 +1699,4 @@ export {
1663
1699
  validateExtensionPackageManifest as v,
1664
1700
  writeExtensionDevWorkbenchFiles as w
1665
1701
  };
1666
- //# sourceMappingURL=devWorkbench-DC7468GN.js.map
1702
+ //# sourceMappingURL=devWorkbench-Ifd_a8Pb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devWorkbench-Ifd_a8Pb.js","sources":["../src/extension-dev/workspace.ts","../src/extension-dev/devWorkbench.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { spawnSync } from 'node:child_process';\nimport { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync, cpSync, rmSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { fileURLToPath } from 'node:url';\nimport path from 'node:path';\nimport {\n CURRENT_EXTENSION_API_VERSION,\n CURRENT_EXTENSION_MANIFEST_VERSION,\n validateManifest,\n} from '@/core/ExtensionManifestSchema';\nimport type {\n ExtensionBuildResult,\n ExtensionDevWorkspaceConfig,\n ExtensionPackageArtifact,\n ExtensionPackageFile,\n ExtensionPackageManifest,\n ExtensionValidationResult,\n ExtensionWorkspaceEntry,\n ExtensionWorkspaceTemplate,\n} from './types';\nimport type { ITheme } from '@/services/themeService';\n\nexport const EXTENSION_WORKSPACE_CONFIG = 'appthen-extension-workspace.json';\nexport const EXTENSION_PACKAGE_EXTENSION = '.appthen-extension.json';\nexport const EXTENSION_BUNDLE_ENTRY = 'entry.js';\n\n/**\n * 从指定包根解析依赖的真实入口(兼容 pnpm 虚拟 store:依赖并不位于\n * <packageRoot>/node_modules,而在 .pnpm 的虚拟层,必须走 Node 解析)。\n */\nexport function resolveFromPackageRoot(packageRoot: string, spec: string): string | undefined {\n try {\n return createRequire(path.join(packageRoot, 'package.json')).resolve(spec);\n } catch {\n return undefined;\n }\n}\n\n/**\n * 解析依赖的包目录(不支持 exports \"./package.json\" 的包也能解析:\n * 先 resolve 主入口,再向上回溯到含 package.json 的目录)。\n */\nexport function resolvePackageDirFromPackageRoot(\n packageRoot: string,\n spec: string,\n): string | undefined {\n const entry = resolveFromPackageRoot(packageRoot, spec);\n if (!entry) return undefined;\n let dir = path.dirname(entry);\n for (let i = 0; i < 6; i += 1) {\n if (existsSync(path.join(dir, 'package.json'))) return dir;\n const parent = path.dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return undefined;\n}\n\nexport function writeExtensionTailwindEntry(workspaceRoot: string, packageRoot: string): string {\n const generatedDir = path.join(workspaceRoot, '.appthen', 'generated');\n mkdirSync(generatedDir, { recursive: true });\n const cssPath = path.join(generatedDir, 'extensions.css');\n const config = loadExtensionWorkspaceConfig(workspaceRoot);\n const extensionsDir = path.resolve(workspaceRoot, config.extensionsDir);\n const resolvedPackageRoot = path.resolve(packageRoot);\n const tailwindConfig = path.join(resolvedPackageRoot, 'tailwind.config.js');\n // 裸包名 \"tailwindcss\" 会从扩展工作区向上解析,可能命中宿主仓库并存的\n // v3(JS 入口)导致 postcss 报错;显式指向本包依赖的 v4 index.css。\n // pnpm 虚拟 store 下依赖不在 <packageRoot>/node_modules,需走 Node 解析。\n const tailwindEntryCssCandidates = [\n resolvePackageDirFromPackageRoot(resolvedPackageRoot, 'tailwindcss'),\n path.join(resolvedPackageRoot, 'node_modules', 'tailwindcss'),\n ]\n .filter((candidate): candidate is string => Boolean(candidate))\n .map((pkgDir) => path.join(pkgDir, 'index.css'));\n const tailwindEntryCss = tailwindEntryCssCandidates.find((candidate) => existsSync(candidate));\n const tailwindImport = tailwindEntryCss ? tailwindEntryCss.replace(/\\\\/g, '/') : 'tailwindcss';\n writeFileSync(\n cssPath,\n `@import \"${tailwindImport}\";\\n@config ${JSON.stringify(tailwindConfig)};\\n@source ${JSON.stringify(extensionsDir)};\\n`,\n 'utf8',\n );\n return cssPath;\n}\n\nconst DEFAULT_WORKSPACE_CONFIG: Required<ExtensionDevWorkspaceConfig> = {\n extensionsDir: 'extensions',\n themeCatalog: [],\n devWorkbench: {\n tenantId: 'local-tenant',\n workbenchId: 'local-extension-dev',\n name: 'Local Extension Dev',\n theme: 'acme.sales',\n enabledExtensionIds: [],\n },\n actor: {\n subjectId: 'local-subject',\n subjectClassId: 'developer',\n userId: 'local-user',\n role: 'admin',\n },\n};\n\nconst WORKBENCH_THEME_EXAMPLE = {\n id: 'acme.sales',\n label: 'Acme 销售',\n type: 'dark',\n extends: 'vercel',\n colors: {\n 'workbench.background': '#101820',\n 'editor.background': '#101820',\n 'editor.foreground': '#f4f7fa',\n 'sideBar.background': '#17232d',\n 'activityBar.background': '#0d141a',\n 'button.background': '#2f9e8f',\n 'input.background': '#1d2b35',\n 'panel.border': '#2b414d',\n },\n portalColors: {\n primary: '#2f9e8f',\n 'primary-hover': '#48b6a5',\n card: '#17232d',\n },\n monaco: {\n base: 'vs-dark',\n colors: {\n 'editor.background': '#101820',\n 'editor.foreground': '#f4f7fa',\n },\n rules: [],\n },\n};\n\nconst GENERATED_WORKSPACE_README = `# AppThen Extension Workspace\n\nThis workspace is the offline-first development environment for AppThen Workbench extensions.\n\n## Start\n\n\\`\\`\\`bash\npnpm install\npnpm doctor\npnpm dev\n\\`\\`\\`\n\nThe dev Workbench loads every extension under \\`extensions/*/manifest.json\\`. You can develop multiple extensions in this directory at the same time. Manifest changes regenerate the local Workbench entry; source changes use Vite HMR.\n\nWhen changing the Workbench SDK itself, run \\`pnpm run build:lib -- --watch\\` in the SDK repository and start this workspace with \\`pnpm dev -- --package-root /path/to/vibe-workspace\\`. Do not publish npm for local iteration.\n\n## Verify And Package\n\n\\`\\`\\`bash\npnpm validate\npnpm test\npnpm build\npnpm pack\n\\`\\`\\`\n\n\\`test\\` is a local smoke test. It validates manifests, bundles each extension, creates a package, and checks the runtime entry and integrity metadata. It does not upload or install anything.\n\n## Publish And Install\n\nPublishing uploads the package and updates the tenant extension record. It does not mount the extension into a Workbench by default.\n\n\\`\\`\\`bash\nAPPTHEN_TOKEN=\"...\" pnpm run publish -- \\\\\n --server http://127.0.0.1:1626 \\\\\n --tenant \"tenant-id\" \\\\\n --tag dev\n\nAPPTHEN_TOKEN=\"...\" pnpm run publish -- \\\\\n --server http://127.0.0.1:1626 \\\\\n --tenant \"tenant-id\" \\\\\n --install-tenant \\\\\n --tag dev\n\\`\\`\\`\n\nThe normal runtime flow is: publish -> install to the tenant -> mount in Workbench configuration -> configure availability and permissions. \\`--workbench\\` is an isolated legacy path and should not be used for the default tenant workflow.\n\n## Rules For Extensions\n\n- Use \\`activate(ctx)\\` and return a cleanup function.\n- Use \\`ctx.capabilities.registerSidebarView\\` for the extension panel.\n- Use \\`ctx.capabilities.registerEditorView\\` and \\`ctx.views.openEditor\\` for full pages and sub-pages.\n- Give editor views a stable \\`routeKey\\`; pass serializable props and a stable key.\n- Use \\`ctx.links\\` for shareable links. Do not build URLs by hand.\n- Read tenant and actor context from \\`ctx.runtime\\` and \\`ctx.auth\\`.\n- Do not use host internals such as \\`eventBus\\`, \\`workspaceEditorService\\`, or \\`registerMainView\\` in production extensions.\n- On mobile, turn multi-column layouts into navigation drawer -> list -> full-screen detail.\n\nSee \\`AGENTS.md\\` for the complete Agent handoff rules.\n`;\n\nconst GENERATED_WORKSPACE_AGENTS = `# AppThen Extension Agent Guide\n\nYou are working in an AppThen extension workspace. Keep changes inside this workspace unless the task explicitly asks for a host change.\n\n## Required Workflow\n\n1. Read the target extension's \\`manifest.json\\` and \\`src/index.tsx\\` before editing.\n2. Run \\`pnpm doctor\\` before debugging the host.\n3. Run \\`pnpm dev\\` for offline development. Do not use marketplace data for local iteration.\n4. Run \\`pnpm validate\\`, \\`pnpm test\\`, and \\`pnpm pack\\` before reporting completion.\n5. Only publish after the user provides the target server, tenant ID, and a short-lived token through the environment.\n\n## Stable Extension Contract\n\n- Manifest: \\`manifestVersion: 1\\`, \\`apiVersion: \"1\"\\`, \\`sourceType: \"umd\"\\`.\n- Icon: put a small \\`data:image/svg+xml\\` or HTTPS URL in \\`manifest.icon\\`; relative static asset paths are not part of v1.\n- Lifecycle: export \\`activate(ctx)\\`; return a disposer for every registration and subscription.\n- Sidebar: \\`ctx.capabilities.registerSidebarView\\`.\n- Main content: \\`ctx.capabilities.registerEditorView\\` plus \\`ctx.views.openEditor\\`.\n- Sharing: \\`ctx.links.create\\`, \\`ctx.links.createAbsolute\\`, or \\`ctx.links.open\\`.\n- Runtime: \\`ctx.runtime\\`, \\`ctx.auth\\`, and serializable view props.\n\n## Prohibited By Default\n\n- Do not register or open main views in external extensions.\n- Do not import host internals: \\`extensionRegistry\\`, \\`eventBus\\`, or \\`workspaceEditorService\\`.\n- Do not use the legacy \\`open\\` query parameter or manually concatenate Workbench URLs.\n- Do not put a full application page in a sidebar. Use an editor view.\n- Do not make desktop multi-column layouts vertically stack on mobile. Use a drawer, list, and full-screen detail flow.\n- Treat widths below 768px as mobile. Workbench drawers open from the bottom on mobile; WorkbenchDrawerContent with side=\"right\" already provides this default.\n- Keep mobile panel views mounted when hidden so local state and scroll containers survive returning from a detail view. Do not record scroll position with a scroll listener.\n- Use min-h-0 flex-1 overflow-y-auto for drawer content, explicit gap-2 / gap-3 / gap-4 for form and action groups, and min-width: 0; max-width: 100% for controls.\n- Do not add a dependency without updating \\`package.json\\` and verifying offline installation assumptions.\n\n## Definition Of Done\n\n- The extension has a unique stable ID and valid manifest.\n- The sidebar and editor views work in the offline Workbench.\n- Editor tabs do not duplicate when the same logical resource is opened again.\n- Routes restore the extension and the same serializable resource state.\n- Dialogs and drawers use the shared overlay package.\n- Mobile behavior has been checked at narrow and tablet widths.\n- The extension passes the UI review: no duplicated resource tabs, no overflowing controls, and list/detail return preserves filters and local state.\n- \\`pnpm doctor\\`, \\`pnpm validate\\`, \\`pnpm test\\`, and \\`pnpm pack\\` pass.\n`;\n\nfunction readJsonFile<T>(filePath: string): T {\n return JSON.parse(readFileSync(filePath, 'utf8')) as T;\n}\n\nfunction writeJsonFile(filePath: string, value: unknown) {\n mkdirSync(path.dirname(filePath), { recursive: true });\n writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\\n`, 'utf8');\n}\n\nfunction normalizeWorkspaceConfig(config?: ExtensionDevWorkspaceConfig): Required<ExtensionDevWorkspaceConfig> {\n return {\n extensionsDir: config?.extensionsDir || DEFAULT_WORKSPACE_CONFIG.extensionsDir,\n themeCatalog: config?.themeCatalog || DEFAULT_WORKSPACE_CONFIG.themeCatalog,\n devWorkbench: {\n ...DEFAULT_WORKSPACE_CONFIG.devWorkbench,\n ...(config?.devWorkbench || {}),\n enabledExtensionIds: config?.devWorkbench?.enabledExtensionIds || [],\n },\n actor: {\n ...DEFAULT_WORKSPACE_CONFIG.actor,\n ...(config?.actor || {}),\n },\n };\n}\n\nexport function loadWorkspaceThemeCatalog(root: string): ITheme[] {\n const themesRoot = path.join(root, 'themes');\n if (!existsSync(themesRoot)) return [];\n\n return readdirSync(themesRoot)\n .filter((name) => name.endsWith('.json'))\n .map((name) => {\n try {\n return readJsonFile<ITheme>(path.join(themesRoot, name));\n } catch {\n return null;\n }\n })\n .filter((theme): theme is ITheme => Boolean(theme?.id && theme?.label && theme?.colors));\n}\n\nexport function findExtensionWorkspaceRoot(startDir = process.cwd()): string | null {\n let current = path.resolve(startDir);\n while (true) {\n if (existsSync(path.join(current, EXTENSION_WORKSPACE_CONFIG))) {\n return current;\n }\n const parent = path.dirname(current);\n if (parent === current) return null;\n current = parent;\n }\n}\n\nexport function loadExtensionWorkspaceConfig(root: string): Required<ExtensionDevWorkspaceConfig> {\n const configPath = path.join(root, EXTENSION_WORKSPACE_CONFIG);\n if (!existsSync(configPath)) {\n return normalizeWorkspaceConfig();\n }\n return normalizeWorkspaceConfig(readJsonFile<ExtensionDevWorkspaceConfig>(configPath));\n}\n\nexport function discoverExtensionWorkspace(root = process.cwd()): ExtensionWorkspaceEntry[] {\n const workspaceRoot = findExtensionWorkspaceRoot(root) || path.resolve(root);\n const config = loadExtensionWorkspaceConfig(workspaceRoot);\n const extensionsRoot = path.resolve(workspaceRoot, config.extensionsDir);\n if (!existsSync(extensionsRoot)) {\n return [];\n }\n\n return readdirSync(extensionsRoot)\n .map((name) => path.join(extensionsRoot, name))\n .filter((dir) => statSync(dir).isDirectory())\n .map((dir) => {\n const manifestPath = path.join(dir, 'manifest.json');\n if (!existsSync(manifestPath)) return null;\n const manifest = readJsonFile<ExtensionPackageManifest>(manifestPath);\n return {\n id: manifest.appId || manifest.id,\n dir,\n manifestPath,\n manifest,\n } satisfies ExtensionWorkspaceEntry;\n })\n .filter((entry): entry is ExtensionWorkspaceEntry => Boolean(entry));\n}\n\nexport function validateExtensionPackageManifest(\n manifest: ExtensionPackageManifest,\n): ExtensionValidationResult {\n const base = validateManifest(manifest);\n const errors = [...base.errors];\n const warnings: string[] = [];\n\n if (manifest.appId && manifest.appId !== manifest.id) {\n warnings.push('appId differs from manifest id; runtime appId will use appId.');\n }\n if (manifest.manifestVersion === undefined) {\n warnings.push('manifestVersion is missing; the current manifest contract will be used in compatibility mode.');\n }\n if (manifest.apiVersion === undefined) {\n warnings.push('apiVersion is missing; the current Workbench API will be used in compatibility mode.');\n }\n if (!manifest.sourceType) {\n warnings.push('sourceType is missing; runtime will default to umd when installed.');\n }\n if (!manifest.runtime?.sidebarViewId && !manifest.runtime?.editorProviders?.length && !manifest.mcp?.uiResources?.length) {\n warnings.push('manifest does not declare runtime views, editor providers, or MCP UI resources.');\n }\n\n return {\n valid: base.valid && errors.length === 0,\n errors,\n warnings,\n };\n}\n\nexport function validateExtensionWorkspace(root = process.cwd()): ExtensionValidationResult {\n const entries = discoverExtensionWorkspace(root);\n const errors: string[] = [];\n const warnings: string[] = [];\n const ids = new Set<string>();\n\n if (entries.length === 0) {\n errors.push('No extensions found. Expected extensions/*/manifest.json.');\n }\n\n for (const entry of entries) {\n if (ids.has(entry.id)) {\n errors.push(`Duplicate extension id: ${entry.id}`);\n }\n ids.add(entry.id);\n const result = validateExtensionPackageManifest(entry.manifest);\n errors.push(...result.errors.map((message) => `${entry.id}: ${message}`));\n warnings.push(...result.warnings.map((message) => `${entry.id}: ${message}`));\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\nfunction listFilesRecursive(root: string): string[] {\n if (!existsSync(root)) return [];\n return readdirSync(root).flatMap((name) => {\n const absolutePath = path.join(root, name);\n const relativePath = path.relative(root, absolutePath);\n if (statSync(absolutePath).isDirectory()) {\n return listFilesRecursive(absolutePath).map((child) => path.join(relativePath, child));\n }\n return [relativePath];\n });\n}\n\nexport interface BuildExtensionOptions {\n bundle?: boolean;\n packageRoot?: string;\n}\n\nfunction toUmdGlobalName(appId: string) {\n return appId\n .split(/[.-]/)\n .filter(Boolean)\n .map((part, index) => {\n const normalized = part.replace(/[^a-zA-Z0-9_$]/g, '');\n if (!normalized) return '';\n return index === 0\n ? normalized.replace(/^[^a-zA-Z_$]+/, '') || 'AppthenExtension'\n : normalized.charAt(0).toUpperCase() + normalized.slice(1);\n })\n .join('') || 'AppthenExtension';\n}\n\nfunction resolveViteCommand(workspaceRoot: string, packageRoot?: string) {\n const binName = process.platform === 'win32' ? 'vite.cmd' : 'vite';\n const candidates = [\n path.join(workspaceRoot, 'node_modules', '.bin', binName),\n packageRoot ? path.join(packageRoot, 'node_modules', '.bin', binName) : undefined,\n ].filter((candidate): candidate is string => Boolean(candidate));\n return candidates.find((candidate) => existsSync(candidate)) || 'vite';\n}\n\nfunction createExtensionViteConfigSource(input: {\n appId: string;\n entryPath: string;\n outDir: string;\n globalName: string;\n packageRoot?: string;\n}) {\n const packageAliases = input.packageRoot\n ? [\n ['@appthen/vibe-workspace/overlay', path.join(input.packageRoot, 'dist', 'overlay', 'index.js')],\n ['@appthen/vibe-workspace/coding-kit', path.join(input.packageRoot, 'dist', 'coding-kit', 'index.js')],\n ['@appthen/vibe-workspace/canvas-core', path.join(input.packageRoot, 'dist', 'canvas-core', 'index.js')],\n ['@appthen/vibe-workspace/ui', path.join(input.packageRoot, 'dist', 'ui', 'index.js')],\n ['@appthen/vibe-workspace/components', path.join(input.packageRoot, 'dist', 'components', 'index.js')],\n ['@appthen/vibe-workspace/plugins/base', path.join(input.packageRoot, 'dist', 'plugins', 'base', 'index.js')],\n ['@appthen/vibe-workspace/styles.css', path.join(input.packageRoot, 'dist', 'vibe-workspace.css')],\n ['@appthen/vibe-workspace', path.join(input.packageRoot, 'dist', 'index.js')],\n ]\n : [];\n const aliasEntries = packageAliases\n .map(([find, replacement]) => ` { find: ${JSON.stringify(find)}, replacement: ${JSON.stringify(replacement)} }`)\n .join(',\\n');\n\n // css.postcss 传文件路径会被 vite 当作搜索目录,插件解析不到(pnpm 隔离下\n // 尤其如此)。直接内联 @tailwindcss/postcss 插件的绝对路径 import。\n // pnpm 虚拟 store 下依赖不在 <packageRoot>/node_modules,需走 Node 解析。\n const tailwindPostcssPkgDir = input.packageRoot\n ? resolvePackageDirFromPackageRoot(input.packageRoot, '@tailwindcss/postcss')\n : undefined;\n const tailwindPostcssEntry = tailwindPostcssPkgDir\n ? path.join(tailwindPostcssPkgDir, 'dist', 'index.mjs')\n : '';\n const postcssImport = existsSync(tailwindPostcssEntry)\n ? `import tailwindPostcss from ${JSON.stringify(tailwindPostcssEntry.replace(/\\\\/g, '/'))};\\n`\n : '';\n\n return `${postcssImport}import { defineConfig } from 'vite';\\n\\nexport default defineConfig({\\n css: {\\n postcss: ${postcssImport ? '{\\n plugins: [tailwindPostcss()],\\n }' : JSON.stringify(path.join(input.packageRoot || path.dirname(input.entryPath), 'postcss.config.js'))},\\n },\\n esbuild: {\\n jsx: 'automatic',\\n },\\n build: {\\n emptyOutDir: false,\\n sourcemap: true,\\n minify: false,\\n cssCodeSplit: false,\\n outDir: ${JSON.stringify(input.outDir)},\\n lib: {\\n entry: ${JSON.stringify(input.entryPath)},\\n name: ${JSON.stringify(input.globalName)},\\n formats: ['iife'],\\n fileName: () => ${JSON.stringify(EXTENSION_BUNDLE_ENTRY)},\\n },\\n rollupOptions: {\\n external: ['react', 'react-dom', 'react/jsx-runtime', 'react/jsx-dev-runtime', 'lucide-react'],\\n output: {\\n globals: {\\n react: 'React',\\n 'react-dom': 'ReactDOM',\\n 'react/jsx-runtime': 'ReactJsxRuntime',\\n 'react/jsx-dev-runtime': 'ReactJsxRuntime',\\n 'lucide-react': 'LucideReact',\\n },\\n },\\n },\\n },\\n resolve: {\\n alias: [\\n${aliasEntries}\\n ],\\n dedupe: ['react', 'react-dom'],\\n },\\n});\\n`;\n}\n\nfunction createExtensionBundleEntry(\n workspaceRoot: string,\n entry: ExtensionWorkspaceEntry,\n sourceEntry: string,\n packageRoot: string,\n) {\n const generatedDir = path.join(workspaceRoot, '.appthen', 'generated');\n mkdirSync(generatedDir, { recursive: true });\n const wrapperPath = path.join(generatedDir, `${entry.id.replace(/[^a-zA-Z0-9_.-]/g, '_')}.tsx`);\n const tailwindEntry = writeExtensionTailwindEntry(workspaceRoot, packageRoot);\n writeFileSync(\n wrapperPath,\n `import ${JSON.stringify(tailwindEntry)};\\nimport ${JSON.stringify(sourceEntry)};\\nexport * from ${JSON.stringify(sourceEntry)};\\n`,\n 'utf8',\n );\n return wrapperPath;\n}\n\nfunction bundleExtension(entry: ExtensionWorkspaceEntry, workspaceRoot: string, buildRoot: string, packageRoot?: string) {\n const sourceEntry = path.resolve(entry.dir, entry.manifest.main || './src/index.tsx');\n if (!existsSync(sourceEntry)) {\n throw new Error(`Extension entry does not exist: ${sourceEntry}`);\n }\n\n const resolvedPackageRoot = packageRoot || path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');\n const bundleEntry = createExtensionBundleEntry(workspaceRoot, entry, sourceEntry, resolvedPackageRoot);\n const globalName = toUmdGlobalName(entry.id);\n const configDir = path.join(workspaceRoot, '.appthen', 'build', '.vite');\n mkdirSync(configDir, { recursive: true });\n const configPath = path.join(configDir, `${entry.id.replace(/[^a-zA-Z0-9_.-]/g, '_')}.config.mjs`);\n writeFileSync(\n configPath,\n createExtensionViteConfigSource({\n appId: entry.id,\n entryPath: bundleEntry,\n outDir: buildRoot,\n globalName,\n packageRoot: resolvedPackageRoot,\n }),\n 'utf8',\n );\n\n const command = resolveViteCommand(workspaceRoot, resolvedPackageRoot);\n const result = spawnSync(command, ['build', '--config', configPath], {\n cwd: workspaceRoot,\n stdio: 'pipe',\n shell: process.platform === 'win32',\n encoding: 'utf8',\n });\n if (result.status !== 0) {\n throw new Error(`Failed to build ${entry.id}:\\n${result.stdout || ''}${result.stderr || ''}`.trim());\n }\n\n return {\n globalName,\n entryFile: EXTENSION_BUNDLE_ENTRY,\n cssFiles: listFilesRecursive(buildRoot).filter((file) => file.endsWith('.css')).sort(),\n };\n}\n\nexport function buildExtension(\n entry: ExtensionWorkspaceEntry,\n workspaceRoot: string,\n options: BuildExtensionOptions = {},\n): ExtensionBuildResult {\n const buildRoot = path.join(workspaceRoot, '.appthen', 'build', entry.id);\n rmSync(buildRoot, { recursive: true, force: true });\n mkdirSync(buildRoot, { recursive: true });\n\n let runtime: Pick<ExtensionBuildResult, 'entryFile' | 'cssFiles' | 'globalName'> = {};\n const manifest: ExtensionPackageManifest = {\n ...entry.manifest,\n appId: entry.manifest.appId || entry.id,\n id: entry.manifest.id || entry.id,\n manifestVersion: entry.manifest.manifestVersion ?? CURRENT_EXTENSION_MANIFEST_VERSION,\n apiVersion: entry.manifest.apiVersion ?? CURRENT_EXTENSION_API_VERSION,\n sourceType: 'umd',\n };\n\n if (options.bundle) {\n runtime = bundleExtension(entry, workspaceRoot, buildRoot, options.packageRoot);\n manifest.main = `./${runtime.entryFile}`;\n // cssFiles 让 serve 能打印样式地址、调试面板能自动发现,缺了它本地调试会丢全部样式\n if (runtime.cssFiles.length > 0) {\n manifest.cssFiles = runtime.cssFiles;\n }\n }\n\n const manifestTarget = path.join(buildRoot, 'manifest.json');\n writeJsonFile(manifestTarget, manifest);\n\n if (!options.bundle) {\n const srcDir = path.join(entry.dir, 'src');\n const distDir = path.join(entry.dir, 'dist');\n const sourceToCopy = existsSync(distDir) ? distDir : srcDir;\n\n if (existsSync(sourceToCopy)) {\n const targetDir = path.join(buildRoot, existsSync(distDir) ? 'dist' : 'src');\n cpSync(sourceToCopy, targetDir, { recursive: true });\n }\n }\n\n return {\n id: entry.id,\n buildDir: buildRoot,\n files: listFilesRecursive(buildRoot).sort(),\n ...runtime,\n };\n}\n\nfunction sha256(buffer: Buffer | string) {\n return createHash('sha256').update(buffer).digest('hex');\n}\n\nfunction sha256Base64(buffer: Buffer | string) {\n return createHash('sha256').update(buffer).digest('base64');\n}\n\nfunction createPackageFiles(buildDir: string): ExtensionPackageFile[] {\n return listFilesRecursive(buildDir)\n .sort()\n .map((relativePath) => {\n const absolutePath = path.join(buildDir, relativePath);\n const content = readFileSync(absolutePath);\n return {\n path: relativePath,\n sha256: sha256(content),\n size: content.byteLength,\n contentBase64: content.toString('base64'),\n };\n });\n}\n\nexport interface PackExtensionOptions extends BuildExtensionOptions {\n useExistingBuild?: boolean;\n}\n\nfunction readBuildManifest(buildDir: string) {\n return readJsonFile<ExtensionPackageManifest>(path.join(buildDir, 'manifest.json'));\n}\n\nexport function packExtension(\n entry: ExtensionWorkspaceEntry,\n workspaceRoot: string,\n outDir?: string,\n options: PackExtensionOptions = {},\n): ExtensionPackageArtifact {\n const existingBuildDir = path.join(workspaceRoot, '.appthen', 'build', entry.id);\n if (options.useExistingBuild && !existsSync(existingBuildDir)) {\n throw new Error(`Build output not found for ${entry.id}. Run appthen-extension build ${entry.id} first.`);\n }\n const build = options.useExistingBuild\n ? {\n id: entry.id,\n buildDir: existingBuildDir,\n files: listFilesRecursive(existingBuildDir).sort(),\n entryFile: EXTENSION_BUNDLE_ENTRY,\n cssFiles: listFilesRecursive(existingBuildDir).filter((file) => file.endsWith('.css')).sort(),\n globalName: toUmdGlobalName(entry.id),\n }\n : buildExtension(entry, workspaceRoot, options);\n const sourceManifest = readBuildManifest(build.buildDir);\n const sourceFiles = createPackageFiles(build.buildDir);\n const manifest: ExtensionPackageManifest = {\n ...sourceManifest,\n integrity: {\n algorithm: 'sha256',\n files: Object.fromEntries(\n sourceFiles\n .filter((file) => file.path !== 'manifest.json')\n .map((file) => [file.path, `sha256-${sha256Base64(Buffer.from(file.contentBase64, 'base64'))}`]),\n ),\n },\n };\n writeJsonFile(path.join(build.buildDir, 'manifest.json'), manifest);\n const files = createPackageFiles(build.buildDir);\n const packageWithoutIntegrity = {\n format: 'appthen-extension-package',\n formatVersion: 1,\n appId: entry.id,\n version: manifest.version,\n manifest,\n runtime: {\n sourceType: 'umd',\n entryFile: build.entryFile || manifest.main?.replace(/^\\.\\//, '') || EXTENSION_BUNDLE_ENTRY,\n cssFiles: build.cssFiles || [],\n globalName: build.globalName || toUmdGlobalName(entry.id),\n },\n files,\n createdAt: new Date().toISOString(),\n } satisfies Omit<ExtensionPackageArtifact, 'integrity'>;\n const digest = sha256(JSON.stringify(packageWithoutIntegrity));\n const artifact: ExtensionPackageArtifact = {\n ...packageWithoutIntegrity,\n integrity: {\n algorithm: 'sha256',\n digest,\n },\n };\n\n const targetDir = outDir ? path.resolve(workspaceRoot, outDir) : path.join(workspaceRoot, '.appthen', 'packages');\n mkdirSync(targetDir, { recursive: true });\n const packagePath = path.join(targetDir, `${entry.id}-${manifest.version}${EXTENSION_PACKAGE_EXTENSION}`);\n writeJsonFile(packagePath, artifact);\n return artifact;\n}\n\nfunction writeExtensionFiles(\n workspaceRoot: string,\n extensionsDir: string,\n extensionId: string,\n manifest: ExtensionPackageManifest,\n source: string,\n) {\n const extensionRoot = path.join(workspaceRoot, extensionsDir, extensionId);\n writeJsonFile(path.join(extensionRoot, 'manifest.json'), {\n ...manifest,\n manifestVersion: manifest.manifestVersion ?? CURRENT_EXTENSION_MANIFEST_VERSION,\n apiVersion: manifest.apiVersion ?? CURRENT_EXTENSION_API_VERSION,\n });\n mkdirSync(path.join(extensionRoot, 'src'), { recursive: true });\n writeFileSync(path.join(extensionRoot, 'src', 'index.tsx'), source, 'utf8');\n}\n\nconst EXAMPLE_EXTENSION_ICONS = {\n workbench: 'data:image/svg+xml,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"%3E%3Crect width=\"32\" height=\"32\" rx=\"8\" fill=\"%232F9E8F\"/%3E%3Cpath d=\"M8 9h16v4H8zm0 6h10v4H8zm0 6h16v4H8z\" fill=\"white\"/%3E%3C/svg%3E',\n sidebar: 'data:image/svg+xml,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"%3E%3Crect width=\"32\" height=\"32\" rx=\"8\" fill=\"%233B82F6\"/%3E%3Cpath d=\"M8 9h6l2 2h8v12H8V9zm4 5h8v2h-8zm0 4h6v2h-6z\" fill=\"white\"/%3E%3C/svg%3E',\n sandbox: 'data:image/svg+xml,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"%3E%3Crect width=\"32\" height=\"32\" rx=\"8\" fill=\"%23F59E0B\"/%3E%3Cpath d=\"M16 7a9 9 0 1 0 0 18 9 9 0 0 0 0-18zm0 0c2 2.2 3 5.2 3 9s-1 6.8-3 9c-2-2.2-3-5.2-3-9s1-6.8 3-9zM7 16h18M9 11h14M9 21h14\" fill=\"none\" stroke=\"white\" stroke-width=\"1.7\" stroke-linecap=\"round\"/%3E%3C/svg%3E',\n tool: 'data:image/svg+xml,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"%3E%3Crect width=\"32\" height=\"32\" rx=\"8\" fill=\"%232F9E8F\"/%3E%3Cpath d=\"M18 6l-8 12h6l-2 8 8-12h-6l2-8z\" fill=\"white\"/%3E%3C/svg%3E',\n multi: 'data:image/svg+xml,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"%3E%3Crect width=\"32\" height=\"32\" rx=\"8\" fill=\"%237C3AED\"/%3E%3Crect x=\"8\" y=\"8\" width=\"7\" height=\"16\" rx=\"1.5\" fill=\"white\"/%3E%3Crect x=\"17\" y=\"8\" width=\"7\" height=\"7\" rx=\"1.5\" fill=\"white\"/%3E%3Crect x=\"17\" y=\"17\" width=\"7\" height=\"7\" rx=\"1.5\" fill=\"white\"/%3E%3C/svg%3E',\n} as const;\n\nfunction createWorkbenchKitExampleExtension(extensionId: string): {\n manifest: ExtensionPackageManifest;\n source: string;\n} {\n return {\n manifest: {\n id: extensionId,\n name: '工作台工具包示例',\n version: '0.1.0',\n icon: EXAMPLE_EXTENSION_ICONS.workbench,\n main: './src/index.tsx',\n sourceType: 'umd',\n runtime: {\n sidebarViewId: `sidebar.${extensionId}`,\n autoActivate: true,\n },\n mcp: {\n enabled: true,\n uiResources: [\n {\n uri: `ui://${extensionId}/starter-card`,\n name: '起手式卡片区块',\n description: '由本地扩展提供的可复用卡片区块。',\n mimeType: 'text/html',\n content: '<section data-block=\"starter-card\">工作台起手式卡片</section>',\n metadata: {\n capabilities: ['展示', '起手式'],\n },\n },\n ],\n frontendTools: [\n {\n name: 'starter.echo',\n description: '回显本地扩展收到的输入数据。',\n inputSchema: {\n type: 'object',\n properties: {\n message: { type: 'string' },\n },\n },\n handlerRef: 'echo',\n },\n ],\n },\n },\n source: \"import React from 'react';\\nimport type { PluginContext } from '@appthen/vibe-workspace/plugins/base';\\n\\nconst VIEW_API_GALLERY = 'main.acme.workbench-kit.api-gallery';\\nconst VIEW_COMPONENT_PREVIEW = 'editor.acme.workbench-kit.component-preview';\\nconst VIEW_API_REFERENCE = 'editor.acme.workbench-kit.api-reference';\\n\\ntype OpenEditorTab = (viewId: string, title: string, props?: Record<string, unknown>) => void;\\n\\nlet openMainView: () => void = () => undefined;\\nlet openEditorTab: OpenEditorTab = () => undefined;\\n\\nconst panelStyle: React.CSSProperties = {\\n height: '100%',\\n overflow: 'auto',\\n padding: 16,\\n color: 'var(--vscode-editor-foreground)',\\n background: 'var(--vscode-sideBar-background)',\\n fontFamily: 'system-ui, sans-serif',\\n};\\n\\nconst mainStyle: React.CSSProperties = {\\n height: '100%',\\n overflow: 'auto',\\n padding: 24,\\n color: 'var(--vscode-editor-foreground)',\\n background: 'var(--vscode-editor-background)',\\n fontFamily: 'system-ui, sans-serif',\\n};\\n\\nconst cardStyle: React.CSSProperties = {\\n border: '1px solid var(--vscode-panel-border)',\\n borderRadius: 8,\\n padding: 12,\\n background: 'var(--vscode-panel-background)',\\n};\\n\\nconst buttonStyle: React.CSSProperties = {\\n height: 32,\\n borderRadius: 6,\\n border: '1px solid var(--vscode-panel-border)',\\n color: 'var(--vscode-editor-foreground)',\\n background: 'var(--vscode-input-background)',\\n};\\n\\nconst mutedStyle: React.CSSProperties = {\\n color: 'var(--vscode-input-placeholderForeground)',\\n lineHeight: 1.6,\\n};\\n\\nfunction BlockCard({ title, children }: { title: string; children: React.ReactNode }) {\\n return (\\n <section style={cardStyle}>\\n <div style={{ fontSize: 13, fontWeight: 700 }}>{title}</div>\\n <div style={{ marginTop: 8, fontSize: 12, ...mutedStyle }}>{children}</div>\\n </section>\\n );\\n}\\n\\nfunction Sidebar() {\\n return (\\n <div style={panelStyle}>\\n <h2 style={{ margin: 0, fontSize: 16 }}>Workbench Kit</h2>\\n <p style={{ marginTop: 8, ...mutedStyle }}>\\n A starter extension that documents Workbench APIs, reusable blocks, and editor-tab views.\\n </p>\\n <div style={{ display: 'grid', gap: 10, marginTop: 16 }}>\\n <BlockCard title=\\\"Sidebar view\\\">Registered with ctx.capabilities.registerSidebarView.</BlockCard>\\n <BlockCard title=\\\"Main view\\\">Open a full Workbench view without creating an editor tab.</BlockCard>\\n <BlockCard title=\\\"Editor tab views\\\">Open React components as normal main-area tabs with view:// files.</BlockCard>\\n <button type=\\\"button\\\" style={buttonStyle} onClick={openMainView}>\\n Open API Gallery\\n </button>\\n <button\\n type=\\\"button\\\"\\n style={buttonStyle}\\n onClick={() => openEditorTab(VIEW_COMPONENT_PREVIEW, 'Component Preview', { variant: 'compact' })}\\n >\\n Open Component Preview Tab\\n </button>\\n <button\\n type=\\\"button\\\"\\n style={buttonStyle}\\n onClick={() => openEditorTab(VIEW_API_REFERENCE, 'API Reference', { section: 'capabilities' })}\\n >\\n Open API Reference Tab\\n </button>\\n </div>\\n </div>\\n );\\n}\\n\\nfunction MainView({ onClose }: { onClose?: () => void }) {\\n return (\\n <div style={mainStyle}>\\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 }}>\\n <h1 style={{ margin: 0, fontSize: 22 }}>Extension API Gallery</h1>\\n <button type=\\\"button\\\" style={{ ...buttonStyle, padding: '0 12px' }} onClick={onClose}>\\n Close\\n </button>\\n </div>\\n <p style={{ marginTop: 8, maxWidth: 720, ...mutedStyle }}>\\n This main view is useful for dashboards, settings pages, and full-page extension surfaces.\\n </p>\\n <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 12, marginTop: 20 }}>\\n <BlockCard title=\\\"Component block\\\">Create small React blocks with CSS variables so they inherit the Workbench theme.</BlockCard>\\n <BlockCard title=\\\"Runtime API\\\">Read tenant, workbench and actor context from ctx.runtime and ctx.auth.</BlockCard>\\n <BlockCard title=\\\"Contribution point\\\">Register topbar, explorer or custom contributions with ctx.capabilities.registerContribution.</BlockCard>\\n <BlockCard title=\\\"UI resource\\\">Expose reusable UI assets from manifest.mcp.uiResources for later platform sharing.</BlockCard>\\n </div>\\n </div>\\n );\\n}\\n\\nfunction ComponentPreviewTab(props: { title?: string; variant?: string }) {\\n return (\\n <div style={mainStyle}>\\n <h1 style={{ margin: 0, fontSize: 20 }}>{props.title || 'Component Preview'}</h1>\\n <p style={{ marginTop: 8, ...mutedStyle }}>\\n This React component was opened as a normal editor tab through workspaceEditorService.createViewFile().\\n </p>\\n <div style={{ display: 'grid', gap: 12, marginTop: 20, maxWidth: 520 }}>\\n <BlockCard title=\\\"Reusable block\\\">Use this pattern for tenant-specific components before promoting them to the shared package.</BlockCard>\\n <BlockCard title=\\\"Props\\\">variant = {props.variant || '-'}</BlockCard>\\n </div>\\n </div>\\n );\\n}\\n\\nfunction ApiReferenceTab(props: { title?: string; section?: string }) {\\n return (\\n <div style={mainStyle}>\\n <h1 style={{ margin: 0, fontSize: 20 }}>{props.title || 'API Reference'}</h1>\\n <p style={{ marginTop: 8, ...mutedStyle }}>\\n This tab shows the minimum APIs most local extensions need.\\n </p>\\n <pre style={{ ...cardStyle, marginTop: 20, whiteSpace: 'pre-wrap', fontSize: 12, lineHeight: 1.6 }}>\\n{`ctx.capabilities.registerSidebarView(...)\\nctx.capabilities.registerMainView(...)\\nctx.capabilities.registerEditorView(...)\\nctx.capabilities.registerFrontendToolHandler(...)\\nctx.capabilities.registerContribution(...)`}\\n </pre>\\n <p style={{ marginTop: 12, ...mutedStyle }}>section = {props.section || '-'}</p>\\n </div>\\n );\\n}\\n\\nexport function activate(ctx: PluginContext) {\\n const workspaceEditorService = ctx.services?.workspaceEditorService;\\n\\n openMainView = () => {\\n ctx.eventBus?.emit('workbench', 'mainView.open', { viewId: VIEW_API_GALLERY });\\n };\\n\\n openEditorTab = (viewId, title, props = {}) => {\\n if (!workspaceEditorService) {\\n console.warn('[workbench-kit] workspaceEditorService is not available.');\\n return;\\n }\\n const file = workspaceEditorService.createViewFile(viewId, title, { ...props, title }, title);\\n ctx.eventBus?.emit('workbench', 'layout.forceOpen', { fileId: file.id });\\n };\\n\\n const disposers = [\\n ctx.capabilities.registerSidebarView({\\n id: 'sidebar.acme.workbench-kit',\\n title: 'Workbench Kit',\\n component: Sidebar,\\n }),\\n ctx.capabilities.registerMainView({\\n id: VIEW_API_GALLERY,\\n title: 'Extension API Gallery',\\n component: MainView,\\n showInTabs: true,\\n closable: true,\\n }),\\n ctx.capabilities.registerEditorView({\\n id: VIEW_COMPONENT_PREVIEW,\\n title: 'Component Preview',\\n component: ComponentPreviewTab,\\n }),\\n ctx.capabilities.registerEditorView({\\n id: VIEW_API_REFERENCE,\\n title: 'API Reference',\\n component: ApiReferenceTab,\\n }),\\n ctx.capabilities.registerFrontendToolHandler({\\n ref: 'echo',\\n source: 'manifest:acme.workbench-kit',\\n handler: async (input, runtime) => ({\\n ok: true,\\n input,\\n actor: runtime.actor,\\n handledAt: new Date().toISOString(),\\n }),\\n }),\\n ctx.capabilities.registerContribution('topbar.item', 'acme.workbench-kit.status', {\\n component: () => <span style={{ fontSize: 12, color: 'var(--vscode-input-placeholderForeground)' }}>Local Extension</span>,\\n }),\\n ];\\n\\n return () => disposers.forEach((dispose) => dispose());\\n}\\n\".replaceAll(\"acme.workbench-kit\", extensionId),\n };\n}\n\nfunction localizeGeneratedWorkbenchKitSource(source: string): string {\n const replacements: Array<[string, string]> = [\n ['Workbench Kit', '工作台工具包'],\n ['A starter extension that documents Workbench APIs, reusable blocks, and editor-tab views.', '用于展示工作台 API、可复用区块和编辑器页签的扩展起手式。'],\n ['Sidebar view', '侧边栏视图'],\n ['Registered with ctx.capabilities.registerSidebarView.', '通过 ctx.capabilities.registerSidebarView 注册。'],\n ['Main view', '编辑器页签'],\n ['Open a full Workbench view without creating an editor tab.', '打开完整的工作台页面,并使用独立编辑器页签承载。'],\n ['Editor tab views', '编辑器页签视图'],\n ['Open React components as normal main-area tabs with view:// files.', '将 React 组件作为普通主区域页签打开,并使用 view:// 文件定位。'],\n ['Open API Gallery', '打开 API 示例页签'],\n ['Open Theme Guide', '打开主题指南页签'],\n ['Open Component Preview Tab', '打开组件预览页签'],\n ['Component Preview', '组件预览'],\n ['Open API Reference Tab', '打开 API 参考页签'],\n ['API Reference', 'API 参考'],\n ['Open Extension Cases', '打开扩展案例页签'],\n ['Open UI Components Tab', '打开 UI 组件页签'],\n ['Open Coding Collaboration Template', '打开 Coding 协作模板'],\n ['Coding Collaboration Template', 'Coding 协作模板'],\n ['UI Components', 'UI 组件'],\n ['Run Regression Checks', '运行回归检查'],\n ['Regression Checks', '回归检查'],\n ['Extension API Gallery', '扩展 API 示例'],\n ['>Close<', '>关闭<'],\n ['\\n Close\\n', '\\n 关闭\\n'],\n ['This main view is useful for dashboards, settings pages, and full-page extension surfaces.', '这个编辑器页签适合承载仪表盘、设置页和完整的扩展页面。'],\n ['Component block', '组件区块'],\n ['Create small React blocks with CSS variables so they inherit the Workbench theme.', '使用 CSS 变量创建小型 React 区块,使其自动继承工作台主题。'],\n ['Runtime API', '运行时 API'],\n ['Read tenant, workbench and actor context from ctx.runtime and ctx.auth.', '从 ctx.runtime 和 ctx.auth 读取租户、工作台和当前操作者上下文。'],\n ['Contribution point', '贡献点'],\n ['Register topbar, explorer or custom contributions with ctx.capabilities.registerContribution.', '通过 ctx.capabilities.registerContribution 注册顶部栏、资源管理器或自定义贡献。'],\n ['UI resource', 'UI 资源'],\n ['Expose reusable UI assets from manifest.mcp.uiResources for later platform sharing.', '通过 manifest.mcp.uiResources 暴露可复用 UI 资源,为后续平台共享做准备。'],\n ['Workbench Theme Guide', '工作台主题指南'],\n ['A runnable reference for the offline theme contract. Theme definitions belong to the Workbench configuration, not an extension activation side effect.', '离线主题契约的可运行参考。主题定义属于工作台配置,不应通过扩展激活副作用设置。'],\n [\"['Workbench',\", \"['工作台',\"],\n [\"['Editor',\", \"['编辑器',\"],\n [\"['Sidebar',\", \"['侧边栏',\"],\n ['Accent', '强调色'],\n [\"['Portal',\", \"['门户',\"],\n ['Suggested local file: themes/acme-sales.json. This documents the contract and token inheritance; global custom theme registration is the next runtime capability.', '建议使用本地文件:themes/acme-sales.json。本地 Workbench 会自动加载它,并通过工作台配置的 theme 字段设为默认主题。'],\n ['This React component was opened as a normal editor tab through workspaceEditorService.createViewFile().', '这个 React 组件通过 ctx.views.openEditor() 作为普通编辑器页签打开。'],\n ['Use this pattern for tenant-specific components before promoting them to the shared package.', '租户专属组件可以先采用这种模式,成熟后再提升到共享 UI 包。'],\n ['Props', '属性'],\n ['Interactive UI component example. variant = ', '可提升为共享 UI 区块的交互式组件示例。变体 = '],\n ['variant = ', '变体 = '],\n ['This tab shows the minimum APIs most local extensions need.', '这个页签展示大多数本地扩展所需的最小 API 集合。'],\n ['section = ', '章节 = '],\n ['Sidebar contribution', '侧边栏贡献'],\n ['Register a sidebar view with ctx.capabilities.', '使用 ctx.capabilities 注册侧边栏视图。'],\n ['Deep-linkable editor tab', '可分享的编辑器页签'],\n ['Open a view with a stable routeKey and serializable props.', '使用稳定的 routeKey 和可序列化属性打开视图。'],\n ['Runtime API check', '运行时 API 检查'],\n ['Inspect tenant, workbench and actor context in a live extension.', '在真实扩展中查看租户、工作台和当前操作者上下文。'],\n ['Extension Cases', '扩展案例'],\n ['Runnable examples for the stable Workbench extension contract.', '稳定工作台扩展契约的可运行案例。'],\n ['Open case', '打开案例'],\n ['Interactive component examples that can be promoted into shared UI blocks.', '可提升为共享 UI 区块的交互式组件示例。'],\n ['<strong>Button</strong>', '<strong>按钮</strong>'],\n ['Clicked ', '已点击 '],\n [' times.', ' 次。'],\n ['Click component', '点击组件'],\n ['Toggle', '开关'],\n ['Enabled', '已启用'],\n ['Disabled', '已禁用'],\n ['Plugin context', '插件上下文'],\n ['Runtime context', '运行时上下文'],\n ['View API', '视图 API'],\n ['Link API', '链接 API'],\n ['Capability API', '能力 API'],\n ['A small smoke-test surface for the extension host contract.', '用于快速验证扩展宿主契约的小型检查面板。'],\n ['Run checks', '运行检查'],\n ['PASS', '通过'],\n ['FAIL', '失败'],\n ['NOT RUN', '未运行'],\n ['Local Extension', '本地扩展'],\n ['Acme Sales', 'Acme 销售'],\n ];\n return replacements.reduce((result, [from, to]) => result.replaceAll(from, to), source);\n}\n\nfunction normalizeGeneratedWorkbenchKitSource(source: string): string {\nconst kitEnhancements = `\ntype CodingTemplateItem = { id: string; title: string; description: string; owner: string; status: '进行中' | '已完成' | '待开始'; due: string };\nconst codingTemplateItems: CodingTemplateItem[] = [\n { id: 'task-001', title: '完善成员邀请流程', description: '补齐邀请、角色和通知状态的协作流程。', owner: '林夏', status: '进行中', due: '今天' },\n { id: 'task-002', title: '整理工作台权限矩阵', description: '确认团队管理员和普通成员的功能边界。', owner: '周然', status: '待开始', due: '明天' },\n { id: 'task-003', title: '发布移动端适配检查单', description: '覆盖列表、详情、抽屉和表单的窄屏行为。', owner: '陈默', status: '已完成', due: '周五' },\n];\n\nfunction CodingTemplateView() {\n const [query, setQuery] = useState('');\n const [statusFilter, setStatusFilter] = useState('全部状态');\n const [editorOpen, setEditorOpen] = useState(false);\n const visibleItems = codingTemplateItems.filter((item) => {\n const normalizedQuery = query.trim().toLowerCase();\n const matchesQuery = !normalizedQuery || [item.title, item.description, item.owner].join(' ').toLowerCase().includes(normalizedQuery);\n return matchesQuery && (statusFilter === '全部状态' || item.status === statusFilter);\n });\n\n return (\n <div className=\"coding-kit\" style={{ height: '100%', minHeight: 0, padding: 16, background: 'var(--ck-surface-page)' }}>\n <CodingListDetailWorkspace\n title=\"事项协作\"\n subtitle=\"Workbench Kit 的标准列表-详情模板,适用于团队协作型扩展。\"\n rows={visibleItems}\n getRowInfo={(item) => ({ key: item.id, title: item.title, description: item.description, meta: item.owner + ' · 截止 ' + item.due, status: <span style={{ borderRadius: 4, padding: '3px 6px', color: 'var(--ck-status-brand-text)', background: 'var(--ck-status-brand-bg)', fontSize: 11 }}>{item.status}</span> })}\n toolbar={(\n <div style={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 8 }}>\n <div style={{ width: 'min(100%, 320px)', minWidth: 0 }}><CodingInput value={query} onChange={(event) => setQuery(event.target.value)} placeholder=\"搜索事项、描述或负责人\" containerClassName=\"min-w-0\" /></div>\n <WorkbenchSelect value={statusFilter} onValueChange={setStatusFilter}><WorkbenchSelectTrigger aria-label=\"事项状态\" className=\"text-xs\" style={{ width: 160, height: 32 }}><WorkbenchSelectValue placeholder=\"全部状态\" /></WorkbenchSelectTrigger><WorkbenchSelectContent><WorkbenchSelectItem value=\"全部状态\">全部状态</WorkbenchSelectItem><WorkbenchSelectItem value=\"进行中\">进行中</WorkbenchSelectItem><WorkbenchSelectItem value=\"待开始\">待开始</WorkbenchSelectItem><WorkbenchSelectItem value=\"已完成\">已完成</WorkbenchSelectItem></WorkbenchSelectContent></WorkbenchSelect>\n </div>\n )}\n headerActions={<CodingButton type=\"button\" variant=\"primary\" size=\"sm\" onClick={() => setEditorOpen(true)}>新建事项</CodingButton>}\n detailActions={<CodingButton type=\"button\" size=\"sm\" onClick={() => setEditorOpen(true)}>编辑</CodingButton>}\n renderDetail={({ row }) => <div style={{ display: 'grid', gap: 16 }}><CodingPanel style={{ padding: 16 }}><div style={{ color: 'var(--ck-text-muted)', fontSize: 12 }}>事项说明</div><p style={{ margin: '8px 0 0', color: 'var(--ck-text-primary)', fontSize: 14, lineHeight: 1.7 }}>{row.description}</p></CodingPanel><CodingPanel style={{ display: 'grid', gap: 12, padding: 16 }}><div style={{ display: 'flex', justifyContent: 'space-between', gap: 12 }}><span style={{ color: 'var(--ck-text-muted)', fontSize: 12 }}>负责人</span><strong>{row.owner}</strong></div><div style={{ display: 'flex', justifyContent: 'space-between', gap: 12 }}><span style={{ color: 'var(--ck-text-muted)', fontSize: 12 }}>状态</span><strong>{row.status}</strong></div><div style={{ display: 'flex', justifyContent: 'space-between', gap: 12 }}><span style={{ color: 'var(--ck-text-muted)', fontSize: 12 }}>截止时间</span><strong>{row.due}</strong></div></CodingPanel></div>}\n editor={<div style={{ display: 'grid', minWidth: 0, gap: 16 }}><label style={{ display: 'grid', minWidth: 0, gap: 6, fontSize: 12 }}>事项标题<CodingInput defaultValue=\"新的协作事项\" style={{ minWidth: 0, maxWidth: '100%' }} /></label><label style={{ display: 'grid', minWidth: 0, gap: 6, fontSize: 12 }}>事项描述<textarea defaultValue=\"填写目标、范围和协作信息\" style={{ minHeight: 96, width: '100%', maxWidth: '100%', resize: 'vertical', border: '1px solid var(--ck-border-default)', borderRadius: 4, padding: 10, background: 'var(--ck-surface-overlay)', font: 'inherit', fontSize: 13 }} /></label></div>}\n editorTitle=\"新建协作事项\"\n editorDescription=\"桌面端从右侧打开,移动端从底部打开。\"\n editorOpen={editorOpen}\n onEditorOpenChange={setEditorOpen}\n editorFooter={<div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8, width: '100%' }}><CodingButton type=\"button\" size=\"sm\" onClick={() => setEditorOpen(false)}>取消</CodingButton><CodingButton type=\"button\" variant=\"primary\" size=\"sm\" onClick={() => setEditorOpen(false)}>保存</CodingButton></div>}\n />\n </div>\n );\n}\n\nfunction openEditorViewById(viewId: string, title: string) {\n kitContext?.views.openEditor({ viewId, title, props: { title }, key: viewId });\n}\n\nfunction OverlayGuideView({ onClose }: { onClose?: () => void }) {\n const [dialogOpen, setDialogOpen] = useState(false);\n const [drawerOpen, setDrawerOpen] = useState(false);\n return (\n <div style={mainStyle}>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 }}><h1 style={{ margin: 0, fontSize: 22 }}>弹窗与侧边抽屉规范</h1><button type=\"button\" style={{ ...buttonStyle, padding: '0 12px' }} onClick={onClose}>关闭</button></div>\n <p style={{ marginTop: 8, maxWidth: 760, ...mutedStyle }}>主项目和扩展都应遵循同一套 Overlay 交互契约。下面两个实例可直接操作验证。</p>\n <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))', gap: 12, marginTop: 20 }}><section style={cardStyle}><h2 style={{ margin: 0, fontSize: 15 }}>弹窗 Dialog</h2><p style={{ margin: '8px 0 0', fontSize: 12, ...mutedStyle }}>适用于确认、创建、编辑和权限变更等聚焦任务。</p><button type=\"button\" style={{ ...buttonStyle, marginTop: 14 }} onClick={() => setDialogOpen(true)}>打开弹窗</button></section><section style={cardStyle}><h2 style={{ margin: 0, fontSize: 15 }}>侧边抽屉 Drawer</h2><p style={{ margin: '8px 0 0', fontSize: 12, ...mutedStyle }}>适用于详情、筛选、分享和配置等上下文任务。</p><button type=\"button\" style={{ ...buttonStyle, marginTop: 14 }} onClick={() => setDrawerOpen(true)}>打开抽屉</button></section></div>\n <section style={{ ...cardStyle, marginTop: 12 }}><h2 style={{ margin: 0, fontSize: 15 }}>共同规则</h2><ul style={{ margin: '10px 0 0', paddingLeft: 20, fontSize: 12, lineHeight: 1.8 }}><li>必须有标题;有解释内容时同时提供描述。</li><li>支持 Esc、遮罩点击、焦点恢复和内容区滚动。</li><li>需要分享或恢复的内容统一使用编辑器页签。</li></ul></section>\n <WorkbenchDialog open={dialogOpen} onOpenChange={setDialogOpen}>\n <WorkbenchDialogContent>\n <WorkbenchDialogHeader><WorkbenchDialogTitle>示例弹窗</WorkbenchDialogTitle><WorkbenchDialogDescription>用于确认、创建和编辑等需要聚焦完成的任务。</WorkbenchDialogDescription></WorkbenchDialogHeader>\n <div className=\"text-sm leading-6\"><p>弹窗默认限制宽度和高度,超出内容只在内容区域滚动。</p><p className=\"mt-3 text-xs text-muted-foreground\">支持 Esc、遮罩点击和明确的关闭按钮。</p></div>\n <WorkbenchDialogFooter><button type=\"button\" className=\"rounded-md border border-border bg-secondary px-3 py-2 text-xs font-medium\" onClick={() => setDialogOpen(false)}>取消</button><button type=\"button\" className=\"rounded-md bg-primary px-3 py-2 text-xs font-medium text-primary-foreground\" onClick={() => setDialogOpen(false)}>完成示例</button></WorkbenchDialogFooter>\n </WorkbenchDialogContent>\n </WorkbenchDialog>\n <WorkbenchDrawer open={drawerOpen} onOpenChange={setDrawerOpen}>\n <WorkbenchDrawerContent side=\"right\" mobileSide=\"bottom\" className=\"flex flex-col gap-0 overflow-hidden p-0\">\n <WorkbenchDrawerHeader className=\"shrink-0 border-b border-border px-5 py-4 pr-14\"><WorkbenchDrawerTitle>示例侧边抽屉</WorkbenchDrawerTitle><WorkbenchDrawerDescription>用于详情、筛选、分享和配置,同时保留当前主区域上下文。</WorkbenchDrawerDescription></WorkbenchDrawerHeader>\n <div className=\"min-h-0 flex-1 overflow-y-auto p-5 text-sm leading-6\"><p>桌面端从右侧打开,移动端自动切换为底部抽屉。</p><div className=\"mt-4 grid gap-2\">{Array.from({ length: 8 }, (_, index) => <div key={index} className=\"rounded-md border border-border p-2.5\">可滚动内容 {index + 1}</div>)}</div></div>\n <WorkbenchDrawerFooter className=\"shrink-0 border-t border-border px-5 py-3\"><button type=\"button\" className=\"rounded-md bg-primary px-3 py-2 text-xs font-medium text-primary-foreground\" onClick={() => setDrawerOpen(false)}>关闭抽屉</button></WorkbenchDrawerFooter>\n </WorkbenchDrawerContent>\n </WorkbenchDrawer>\n </div>\n );\n}\n\nfunction ResponsiveWorkspaceGuide({ onClose }: { onClose?: () => void }) {\n const [detailOpen, setDetailOpen] = useState(false);\n const members = ['林夏', '周然', '陈默'];\n return (\n <div style={mainStyle}>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 }}>\n <h1 style={{ margin: 0, fontSize: 22 }}>多栏工作区与移动端折叠规范</h1>\n <button type=\"button\" style={{ ...buttonStyle, padding: '0 12px' }} onClick={onClose}>关闭</button>\n </div>\n <p style={{ marginTop: 8, maxWidth: 760, ...mutedStyle }}>桌面端保留导航、列表、详情的并行关系;移动端使用导航抽屉、列表和全屏详情。</p>\n {!detailOpen ? (\n <section style={{ ...cardStyle, marginTop: 20 }}>\n <strong>移动端列表</strong>\n <div style={{ display: 'grid', gap: 8, marginTop: 10 }}>{members.map((member) => <button key={member} type=\"button\" style={{ ...buttonStyle, textAlign: 'left' }} onClick={() => setDetailOpen(true)}>{member} · 研发部</button>)}</div>\n </section>\n ) : (\n <section style={{ ...cardStyle, marginTop: 20 }}>\n <button type=\"button\" style={{ ...buttonStyle, padding: '0 10px' }} onClick={() => setDetailOpen(false)}>返回成员列表</button>\n <h2 style={{ margin: '16px 0 0', fontSize: 16 }}>成员详情</h2>\n <p style={{ marginTop: 8, ...mutedStyle }}>移动端详情使用全屏承载,返回后保留列表状态。</p>\n </section>\n )}\n <section style={{ ...cardStyle, marginTop: 12 }}><strong>禁止做法</strong><p style={{ margin: '8px 0 0', ...mutedStyle }}>不要把桌面多栏简单压成一张很长的纵向页面,也不要隐藏详情导致关键操作丢失。</p></section>\n </div>\n );\n}\n\nconst themeExample = {\n id: 'acme.sales',\n label: 'Acme Sales',\n type: 'dark',\n extends: 'vercel',\n colors: {\n 'workbench.background': '#101820',\n 'editor.background': '#101820',\n 'editor.foreground': '#f4f7fa',\n 'sideBar.background': '#17232d',\n 'activityBar.background': '#0d141a',\n 'button.background': '#2f9e8f',\n 'input.background': '#1d2b35',\n 'panel.border': '#2b414d',\n },\n portalColors: {\n primary: '#2f9e8f',\n 'primary-hover': '#48b6a5',\n card: '#17232d',\n },\n monaco: {\n base: 'vs-dark',\n colors: {\n 'editor.background': '#101820',\n 'editor.foreground': '#f4f7fa',\n },\n rules: [],\n },\n};\n\nfunction ThemeGuideView({ onClose }: { onClose?: () => void }) {\n return (\n <div style={mainStyle}>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 }}>\n <h1 style={{ margin: 0, fontSize: 22 }}>Workbench Theme Guide</h1>\n <button type=\"button\" style={{ ...buttonStyle, padding: '0 12px' }} onClick={onClose}>Close</button>\n </div>\n <p style={{ marginTop: 8, maxWidth: 760, ...mutedStyle }}>\n A runnable reference for the offline theme contract. Theme definitions belong to the Workbench configuration, not an extension activation side effect.\n </p>\n <div style={{ display: 'grid', gap: 12, gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', marginTop: 20 }}>\n {[\n ['Workbench', 'var(--vscode-workbench-background)'],\n ['Editor', 'var(--vscode-editor-background)'],\n ['Sidebar', 'var(--vscode-sideBar-background)'],\n ['Accent', 'var(--vscode-button-background)'],\n ['Portal', 'var(--portal-primary)'],\n ].map(([label, color]) => (\n <section key={label} style={{ ...cardStyle, display: 'flex', alignItems: 'center', gap: 10 }}>\n <span style={{ width: 28, height: 28, borderRadius: 6, background: color, border: '1px solid var(--vscode-panel-border)' }} />\n <div><strong>{label}</strong><div style={{ fontSize: 11, ...mutedStyle }}>{color}</div></div>\n </section>\n ))}\n </div>\n <pre style={{ ...cardStyle, marginTop: 20, whiteSpace: 'pre-wrap', fontSize: 12, lineHeight: 1.6 }}>\n {JSON.stringify(themeExample, null, 2)}\n </pre>\n <p style={{ marginTop: 12, ...mutedStyle }}>\n Suggested local file: themes/acme-sales.json. The offline Workbench loads it automatically; set devWorkbench.theme to acme.sales to make it the default.\n </p>\n </div>\n );\n}\n\nfunction CasesView({ onClose }: { onClose?: () => void }) {\n return (\n <div style={mainStyle}>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>\n <h1 style={{ margin: 0, fontSize: 22 }}>Extension Cases</h1>\n <button type=\"button\" style={{ ...buttonStyle, padding: '0 12px' }} onClick={onClose}>Close</button>\n </div>\n <p style={{ marginTop: 8, ...mutedStyle }}>Runnable examples for the stable Workbench extension contract.</p>\n <div style={{ display: 'grid', gap: 12, marginTop: 20, maxWidth: 720 }}>\n <BlockCard title=\"Sidebar contribution\">Register a sidebar view with ctx.capabilities.</BlockCard>\n <BlockCard title=\"Deep-linkable editor tab\">Open a view with a stable routeKey and serializable props.</BlockCard>\n <BlockCard title=\"Runtime API check\">Inspect tenant, workbench and actor context in a live extension.</BlockCard>\n </div>\n </div>\n );\n}\n\nfunction ComponentsTab(props: { title?: string; variant?: string }) {\n const [count, setCount] = useState(0);\n return (\n <div style={mainStyle}>\n <h1 style={{ margin: 0, fontSize: 20 }}>{props.title || 'UI Components'}</h1>\n <p style={{ marginTop: 8, ...mutedStyle }}>Interactive UI component example. variant = {props.variant || '-'}</p>\n <button type=\"button\" style={{ ...buttonStyle, marginTop: 16 }} onClick={() => setCount((value) => value + 1)}>Clicked {count} times</button>\n </div>\n );\n}\n\nfunction RegressionTab() {\n const [ran, setRan] = useState(false);\n const checks = [\n ['Plugin context', Boolean(kitContext?.plugin.id)],\n ['Runtime context', Boolean(kitContext?.runtime.workbenchId)],\n ['View API', typeof kitContext?.views.openEditor === 'function'],\n ['Link API', typeof kitContext?.links.create === 'function'],\n ] as const;\n return (\n <div style={mainStyle}>\n <h1 style={{ margin: 0, fontSize: 20 }}>Regression Checks</h1>\n <button type=\"button\" style={{ ...buttonStyle, marginTop: 16 }} onClick={() => setRan(true)}>Run checks</button>\n <div style={{ display: 'grid', gap: 8, marginTop: 16, maxWidth: 520 }}>\n {checks.map(([label, passed]) => <div key={label} style={{ ...cardStyle, display: 'flex', justifyContent: 'space-between' }}><span>{label}</span><strong>{ran && passed ? 'PASS' : ran ? 'FAIL' : 'NOT RUN'}</strong></div>)}\n </div>\n </div>\n );\n}\n`;\n return localizeGeneratedWorkbenchKitSource(source\n .replace(\"import React from 'react';\", \"import React, { useState } from 'react';\\nimport { WorkbenchDialog, WorkbenchDialogContent, WorkbenchDialogDescription, WorkbenchDialogFooter, WorkbenchDialogHeader, WorkbenchDialogTitle, WorkbenchDrawer, WorkbenchDrawerContent, WorkbenchDrawerDescription, WorkbenchDrawerFooter, WorkbenchDrawerHeader, WorkbenchDrawerTitle } from '@appthen/vibe-workspace/overlay';\\nimport { CodingButton, CodingInput, CodingListDetailWorkspace, CodingPanel } from '@appthen/vibe-workspace/coding-kit';\\nimport { WorkbenchSelect, WorkbenchSelectContent, WorkbenchSelectItem, WorkbenchSelectTrigger, WorkbenchSelectValue } from '@appthen/vibe-workspace/ui';\\nimport '@appthen/vibe-workspace/styles.css';\")\n .replace(\" overflow: 'auto',\\n padding: 16,\", \" overflow: 'auto',\\n fontSize: 13,\\n padding: 16,\")\n .replace(\" overflow: 'auto',\\n padding: 24,\", \" overflow: 'auto',\\n fontSize: 13,\\n padding: 24,\")\n .replace(\"const buttonStyle: React.CSSProperties = {\\n height: 32,\", \"const buttonStyle: React.CSSProperties = {\\n height: 32,\\n padding: '0 10px',\\n fontSize: 12,\\n fontWeight: 500,\\n lineHeight: 1.2,\\n fontFamily: 'inherit',\")\n .replace(\n \"const VIEW_API_REFERENCE = 'editor.acme.workbench-kit.api-reference';\",\n \"const VIEW_API_REFERENCE = 'editor.acme.workbench-kit.api-reference';\\nconst VIEW_CODING_TEMPLATE = 'editor.acme.workbench-kit.coding-template';\\nconst VIEW_THEME_GUIDE = 'main.acme.workbench-kit.theme-guide';\\nconst VIEW_CASES = 'main.acme.workbench-kit.cases';\\nconst VIEW_COMPONENTS = 'editor.acme.workbench-kit.components';\\nconst VIEW_REGRESSION = 'editor.acme.workbench-kit.regression';\\nconst VIEW_OVERLAY_GUIDE = 'main.acme.workbench-kit.overlay-guide';\",\n )\n .replace(\n \"const VIEW_OVERLAY_GUIDE = 'main.acme.workbench-kit.overlay-guide';\",\n \"const VIEW_OVERLAY_GUIDE = 'main.acme.workbench-kit.overlay-guide';\\nconst VIEW_RESPONSIVE_WORKSPACE = 'main.acme.workbench-kit.responsive-workspace';\",\n )\n .replaceAll('openMainViewById', 'openEditorViewById')\n .replaceAll('ctx.views.openMain(...)', 'ctx.views.openEditor(...)')\n .replaceAll('main.acme.workbench-kit.', 'editor.acme.workbench-kit.')\n .replace('let openMainView: () => void = () => undefined;', 'let openApiGalleryTab: () => void = () => undefined;')\n .replace('onClick={openMainView}', 'onClick={openApiGalleryTab}')\n .replace('onClick={() => openMainViewById(VIEW_THEME_GUIDE)}', \"onClick={() => openEditorViewById(VIEW_THEME_GUIDE, '工作台主题指南')}\")\n .replace('onClick={() => openMainViewById(VIEW_CASES)}', \"onClick={() => openEditorViewById(VIEW_CASES, '扩展案例')}\")\n .replace('onClick={() => openMainViewById(VIEW_OVERLAY_GUIDE)}', \"onClick={() => openEditorViewById(VIEW_OVERLAY_GUIDE, '弹窗与侧边抽屉规范')}\")\n .replace(\n \"let openEditorTab: OpenEditorTab = () => undefined;\",\n \"let openEditorTab: OpenEditorTab = () => undefined;\\nlet kitContext: PluginContext | null = null;\",\n )\n .replace('\\nfunction MainView', `${kitEnhancements}\\nfunction MainView`)\n .replace(\n ` </button>\\n </div>\\n </div>\\n );\\n}\\n\\nfunction openEditorViewById`,\n ` </button>\\n <button type=\"button\" style={buttonStyle} onClick={() => openMainViewById(VIEW_THEME_GUIDE)}>\\n Open Theme Guide\\n </button>\\n <button type=\"button\" style={buttonStyle} onClick={() => openMainViewById(VIEW_CASES)}>\\n Open Extension Cases\\n </button>\\n <button type=\"button\" style={buttonStyle} onClick={() => openEditorTab(VIEW_COMPONENTS, 'UI Components', { variant: 'interactive' })}>\\n Open UI Components Tab\\n </button>\\n <button type=\"button\" style={buttonStyle} onClick={() => openEditorTab(VIEW_REGRESSION, 'Regression Checks')}>\\n Run Regression Checks\\n </button>\\n </div>\\n </div>\\n );\\n}\\n\\nfunction openMainViewById`,\n )\n .replace(\n ` Open UI Components Tab\\n </button>`,\n ` Open UI Components Tab\\n </button>\\n <button type=\"button\" style={buttonStyle} onClick={() => openEditorTab(VIEW_CODING_TEMPLATE, 'Coding Collaboration Template')}>\\n Open Coding Collaboration Template\\n </button>`,\n )\n .replace(\n ` Open API Reference Tab\\n </button>`,\n ` Open API Reference Tab\\n </button>\\n <button type=\"button\" style={buttonStyle} onClick={() => openEditorViewById(VIEW_THEME_GUIDE, 'Workbench Theme Guide')}>\\n Open Theme Guide\\n </button>\\n <button type=\"button\" style={buttonStyle} onClick={() => openEditorViewById(VIEW_CASES, 'Extension Cases')}>\\n Open Extension Cases\\n </button>\\n <button type=\"button\" style={buttonStyle} onClick={() => openEditorViewById(VIEW_OVERLAY_GUIDE, '弹窗与侧边抽屉规范')}>\\n 打开弹窗与抽屉规范\\n </button>\\n <button type=\"button\" style={buttonStyle} onClick={() => openEditorViewById(VIEW_RESPONSIVE_WORKSPACE, '多栏工作区与移动端折叠规范')}>\\n 打开多栏工作区规范\\n </button>`,\n )\n .replace(\n ` Open Extension Cases\\n </button>`,\n ` Open Extension Cases\\n </button>\\n <button type=\"button\" style={buttonStyle} onClick={() => openMainViewById(VIEW_OVERLAY_GUIDE)}>\\n 打开弹窗与抽屉规范\\n </button>`,\n )\n .replace(\n ` 打开弹窗与抽屉规范\n </button>`,\n ` 打开弹窗与抽屉规范\n </button>\n <button type=\"button\" style={buttonStyle} onClick={() => openMainViewById(VIEW_RESPONSIVE_WORKSPACE)}>\n 打开多栏工作区规范\n </button>`,\n )\n .replace(\n 'export function activate(ctx: PluginContext) {',\n 'export function activate(ctx: PluginContext) {\\n kitContext = ctx;',\n )\n .replace(\n \" ctx.capabilities.registerFrontendToolHandler({\",\n \" ctx.capabilities.registerEditorView({ id: VIEW_THEME_GUIDE, routeKey: 'theme-guide', title: 'Workbench Theme Guide', component: ThemeGuideView }),\\n ctx.capabilities.registerEditorView({ id: VIEW_CASES, routeKey: 'cases', title: 'Extension Cases', component: CasesView }),\\n ctx.capabilities.registerEditorView({ id: VIEW_OVERLAY_GUIDE, routeKey: 'overlay-guide', title: '弹窗与侧边抽屉规范', component: OverlayGuideView }),\\n ctx.capabilities.registerEditorView({ id: VIEW_RESPONSIVE_WORKSPACE, routeKey: 'responsive-workspace', title: '多栏工作区与移动端折叠规范', component: ResponsiveWorkspaceGuide }),\\n ctx.capabilities.registerEditorView({ id: VIEW_COMPONENTS, routeKey: 'components', title: 'UI Components', component: ComponentsTab }),\\n ctx.capabilities.registerEditorView({ id: VIEW_CODING_TEMPLATE, routeKey: 'coding-template', title: 'Coding Collaboration Template', component: CodingTemplateView }),\\n ctx.capabilities.registerEditorView({ id: VIEW_REGRESSION, routeKey: 'regression', title: 'Regression Checks', component: RegressionTab }),\\n ctx.capabilities.registerFrontendToolHandler({\",\n )\n .replaceAll('ctx.capabilities.registerMainView({', 'ctx.capabilities.registerEditorView({')\n .replaceAll('ctx.capabilities.registerMainView(...)', 'ctx.capabilities.registerEditorView(...)')\n .replaceAll(' showInTabs: true,\\n closable: true,\\n', '')\n .replaceAll('openMainViewById', 'openEditorViewById')\n .replaceAll(\"openEditorViewById(VIEW_THEME_GUIDE)\", \"openEditorViewById(VIEW_THEME_GUIDE, '工作台主题指南')\")\n .replaceAll(\"openEditorViewById(VIEW_CASES)\", \"openEditorViewById(VIEW_CASES, '扩展案例')\")\n .replaceAll(\"openEditorViewById(VIEW_OVERLAY_GUIDE)\", \"openEditorViewById(VIEW_OVERLAY_GUIDE, '弹窗与侧边抽屉规范')\")\n .replace(\n \" id: VIEW_API_GALLERY,\\n title: 'Extension API Gallery',\",\n \" id: VIEW_API_GALLERY,\\n routeKey: 'api-gallery',\\n title: 'Extension API Gallery',\",\n )\n .replace(\n \" id: VIEW_COMPONENT_PREVIEW,\\n title: 'Component Preview',\",\n \" id: VIEW_COMPONENT_PREVIEW,\\n routeKey: 'component-preview',\\n title: 'Component Preview',\",\n )\n .replace(\n \" id: VIEW_API_REFERENCE,\\n title: 'API Reference',\",\n \" id: VIEW_API_REFERENCE,\\n routeKey: 'api-reference',\\n title: 'API Reference',\",\n )\n .replace(\n 'ctx.capabilities.registerSidebarView(...)',\n 'import { WorkbenchDialog, WorkbenchDrawer } from \\'@appthen/vibe-workspace/overlay\\';\\n\\nctx.views.openEditor(...)\\nctx.links.create(...)\\n\\nctx.capabilities.registerSidebarView(...)',\n )\n .replace(\n / const workspaceEditorService = ctx\\.services\\?\\.workspaceEditorService;\\n\\n openMainView[\\s\\S]*? \\};\\n\\n const disposers = \\[/,\n ` openApiGalleryTab = () => {\\n ctx.views.openEditor({ viewId: VIEW_API_GALLERY, title: '扩展 API 示例', props: { title: '扩展 API 示例' }, key: VIEW_API_GALLERY });\\n };\\n\\n openEditorTab = (viewId, title, props = {}) => {\\n ctx.views.openEditor({ viewId, title, props: { ...props, title }, key: title });\\n };\\n\\n const disposers = [`,\n )\n .replace('workspaceEditorService.createViewFile()', 'ctx.views.openEditor()'));\n}\n\nfunction createSidebarBasicExtension(extensionId: string): {\n manifest: ExtensionPackageManifest;\n source: string;\n} {\n return {\n manifest: {\n id: extensionId,\n name: 'Sidebar Basic',\n version: '0.1.0',\n icon: EXAMPLE_EXTENSION_ICONS.sidebar,\n main: './src/index.tsx',\n sourceType: 'umd',\n runtime: {\n sidebarViewId: `sidebar.${extensionId}`,\n autoActivate: true,\n },\n mcp: {\n enabled: true,\n uiResources: [],\n frontendTools: [],\n },\n },\n source: `import React from 'react';\\nimport type { PluginContext } from '@appthen/vibe-workspace/plugins/base';\\n\\nfunction SidebarBasic() {\\n return (\\n <div style={{ padding: 16, fontFamily: 'system-ui, sans-serif' }}>\\n <h2 style={{ margin: 0, fontSize: 16 }}>Sidebar Basic</h2>\\n <p style={{ color: '#6b7280', lineHeight: 1.6 }}>\\n This extension contributes a Workbench sidebar view from a local folder.\\n </p>\\n </div>\\n );\\n}\\n\\nexport function activate(ctx: PluginContext) {\\n return ctx.capabilities.registerSidebarView({\\n id: 'sidebar.${extensionId}',\\n title: 'Sidebar Basic',\\n component: SidebarBasic,\\n });\\n}\\n`,\n };\n}\n\nfunction createRemoteHtmlSandboxExtension(extensionId: string): {\n manifest: ExtensionPackageManifest;\n source: string;\n} {\n return {\n manifest: {\n id: extensionId,\n name: 'Remote HTML Sandbox',\n version: '0.1.0',\n icon: EXAMPLE_EXTENSION_ICONS.sandbox,\n main: './src/index.tsx',\n sourceType: 'umd',\n runtime: {\n sidebarViewId: `sidebar.${extensionId}`,\n autoActivate: true,\n },\n mcp: {\n enabled: true,\n uiResources: [],\n frontendTools: [],\n },\n },\n source: `import React, { useEffect, useMemo, useState } from 'react';\nimport type { PluginContext } from '@appthen/vibe-workspace/plugins/base';\n\nconst sandboxDocument = [\n '<!doctype html><html><body style=\"font:14px system-ui;padding:16px\">',\n '<strong>Sandboxed remote HTML</strong>',\n '<p id=\"status\">Waiting for host message...</p>',\n '<script>window.parent.postMessage({ type: \"sandbox-ready\" }, \"*\"); window.addEventListener(\"message\", function (event) { var status = document.getElementById(\"status\"); if (status) status.textContent = \"Received: \" + JSON.stringify(event.data); });</script>',\n '</body></html>',\n].join('');\n\nfunction SandboxSidebar() {\n const [message, setMessage] = useState('');\n const frameId = useMemo(() => 'sandbox-frame-' + Math.random().toString(36).slice(2), []);\n\n useEffect(() => {\n const onMessage = (event: MessageEvent) => {\n if (event.data?.type === 'sandbox-ready') setMessage('The iframe sent a message to the host.');\n };\n window.addEventListener('message', onMessage);\n return () => window.removeEventListener('message', onMessage);\n }, []);\n\n return (\n <div style={{ height: '100%', padding: 16, color: 'var(--vscode-editor-foreground)', fontFamily: 'system-ui, sans-serif' }}>\n <h2 style={{ margin: 0, fontSize: 16 }}>Remote HTML Sandbox</h2>\n <p style={{ color: 'var(--vscode-input-placeholderForeground)', lineHeight: 1.5 }}>\n This iframe runs scripts but has no same-origin access.\n </p>\n <iframe\n id={frameId}\n title=\"Remote HTML Sandbox\"\n srcDoc={sandboxDocument}\n sandbox=\"allow-scripts\"\n csp=\"default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'\"\n referrerPolicy=\"no-referrer\"\n style={{ width: '100%', minHeight: 160, border: '1px solid var(--vscode-panel-border)' }}\n />\n <div style={{ marginTop: 8, fontSize: 12, color: 'var(--vscode-input-placeholderForeground)' }}>{message || 'Loading iframe...'}</div>\n </div>\n );\n}\n\nexport function activate(ctx: PluginContext) {\n return ctx.capabilities.registerSidebarView({\n id: 'sidebar.${extensionId}',\n title: 'Remote HTML Sandbox',\n component: SandboxSidebar,\n });\n}\n`,\n };\n}\n\nfunction createFrontendToolBasicExtension(extensionId: string): {\n manifest: ExtensionPackageManifest;\n source: string;\n} {\n return {\n manifest: {\n id: extensionId,\n name: 'Frontend Tool Basic',\n version: '0.1.0',\n icon: EXAMPLE_EXTENSION_ICONS.tool,\n main: './src/index.tsx',\n sourceType: 'umd',\n runtime: {\n sidebarViewId: `sidebar.${extensionId}`,\n autoActivate: true,\n },\n mcp: {\n enabled: true,\n uiResources: [],\n frontendTools: [\n {\n name: 'demo.echo',\n description: 'Echo an input payload from the local extension.',\n inputSchema: {\n type: 'object',\n properties: {\n message: { type: 'string' },\n },\n },\n handlerRef: 'echo',\n },\n ],\n },\n },\n source: `import React from 'react';\\nimport type { PluginContext } from '@appthen/vibe-workspace/plugins/base';\\n\\nfunction FrontendToolBasic() {\\n return (\\n <div style={{ padding: 16, fontFamily: 'system-ui, sans-serif' }}>\\n <h2 style={{ margin: 0, fontSize: 16 }}>Frontend Tool Basic</h2>\\n <p style={{ color: '#6b7280', lineHeight: 1.6 }}>\\n This extension declares demo.echo in manifest and binds it to a local handler.\\n </p>\\n </div>\\n );\\n}\\n\\nexport function activate(ctx: PluginContext) {\\n const disposeSidebar = ctx.capabilities.registerSidebarView({\\n id: 'sidebar.${extensionId}',\\n title: 'Frontend Tool Basic',\\n component: FrontendToolBasic,\\n });\\n\\n const disposeHandler = ctx.capabilities.registerFrontendToolHandler({\\n ref: 'echo',\\n source: 'manifest:${extensionId}',\\n handler: async (input) => ({\\n ok: true,\\n input,\\n handledAt: new Date().toISOString(),\\n }),\\n });\\n\\n return () => {\\n disposeHandler();\\n disposeSidebar();\\n };\\n}\\n`,\n };\n}\n\nfunction createMultiViewBasicExtension(extensionId: string): {\n manifest: ExtensionPackageManifest;\n source: string;\n} {\n return {\n manifest: {\n id: extensionId,\n name: 'Multi View Basic',\n version: '0.1.0',\n icon: EXAMPLE_EXTENSION_ICONS.multi,\n main: './src/index.tsx',\n sourceType: 'umd',\n runtime: {\n sidebarViewId: `sidebar.${extensionId}`,\n autoActivate: true,\n },\n mcp: {\n enabled: true,\n uiResources: [],\n frontendTools: [],\n },\n },\n source: `import React from 'react';\\nimport type { PluginContext } from '@appthen/vibe-workspace/plugins/base';\\n\\nfunction Sidebar() {\\n return <div style={{ padding: 16 }}>Open the main view from the command palette or extension API.</div>;\\n}\\n\\nfunction MainView() {\\n return (\\n <div style={{ padding: 24, fontFamily: 'system-ui, sans-serif' }}>\\n <h1 style={{ marginTop: 0 }}>Multi View Basic</h1>\\n <p>This extension contributes both a sidebar and a main view.</p>\\n </div>\\n );\\n}\\n\\nexport function activate(ctx: PluginContext) {\\n const disposeSidebar = ctx.capabilities.registerSidebarView({\\n id: 'sidebar.${extensionId}',\\n title: 'Multi View Basic',\\n component: Sidebar,\\n });\\n const disposeMain = ctx.capabilities.registerMainView({\\n id: 'main.${extensionId}',\\n title: 'Multi View Basic',\\n component: MainView,\\n showInTabs: true,\\n closable: true,\\n });\\n\\n return () => {\\n disposeMain();\\n disposeSidebar();\\n };\\n}\\n`,\n };\n}\n\nfunction normalizeEditorOnlyExtensionSource(source: string) {\n return source\n .replaceAll('registerMainView', 'registerEditorView')\n .replaceAll(\"'main.${extensionId}'\", \"'editor.${extensionId}'\")\n .replaceAll(',\\n showInTabs: true,\\n closable: true', '')\n .replaceAll('main view', 'editor tab');\n}\n\nexport function createExtensionWorkspace(\n root: string,\n extensionId = 'acme.example',\n template: ExtensionWorkspaceTemplate = 'basic',\n) {\n const workspaceRoot = path.resolve(root);\n const sampleExtensionIds = template === 'full'\n ? [\n 'acme.workbench-kit',\n 'acme.sidebar-basic',\n 'acme.remote-html-sandbox',\n 'acme.frontend-tool-basic',\n 'acme.multi-view-basic',\n ]\n : [extensionId];\n const config = normalizeWorkspaceConfig({\n devWorkbench: {\n enabledExtensionIds: sampleExtensionIds,\n },\n });\n\n writeJsonFile(path.join(workspaceRoot, EXTENSION_WORKSPACE_CONFIG), config);\n writeFileSync(path.join(workspaceRoot, 'README.md'), GENERATED_WORKSPACE_README, 'utf8');\n writeFileSync(path.join(workspaceRoot, 'AGENTS.md'), GENERATED_WORKSPACE_AGENTS, 'utf8');\n writeJsonFile(path.join(workspaceRoot, 'themes', 'acme-sales.json'), WORKBENCH_THEME_EXAMPLE);\n writeJsonFile(path.join(workspaceRoot, 'package.json'), {\n name: 'appthen-extension-workspace',\n private: true,\n type: 'module',\n scripts: {\n dev: 'appthen-extension dev',\n doctor: 'appthen-extension doctor',\n test: 'appthen-extension test',\n validate: 'appthen-extension validate',\n build: 'appthen-extension build',\n pack: 'appthen-extension pack',\n publish: 'appthen-extension publish',\n },\n dependencies: {\n '@appthen/vibe-workspace': '^0.1.0',\n '@vitejs/plugin-react': '^5.0.0',\n vite: '^6.2.0',\n typescript: '~5.8.2',\n react: '^18.2.0',\n 'react-dom': '^18.2.0',\n },\n });\n\n const samples = template === 'full'\n ? [\n ['acme.workbench-kit', createWorkbenchKitExampleExtension('acme.workbench-kit')],\n ['acme.sidebar-basic', createSidebarBasicExtension('acme.sidebar-basic')],\n ['acme.remote-html-sandbox', createRemoteHtmlSandboxExtension('acme.remote-html-sandbox')],\n ['acme.frontend-tool-basic', createFrontendToolBasicExtension('acme.frontend-tool-basic')],\n ['acme.multi-view-basic', createMultiViewBasicExtension('acme.multi-view-basic')],\n ] as const\n : [[extensionId, createWorkbenchKitExampleExtension(extensionId)]] as const;\n\n samples.forEach(([id, sample]) => {\n writeExtensionFiles(\n workspaceRoot,\n config.extensionsDir,\n id,\n sample.manifest,\n id === 'acme.workbench-kit' || id === extensionId\n ? normalizeGeneratedWorkbenchKitSource(sample.source)\n : id === 'acme.multi-view-basic'\n ? normalizeEditorOnlyExtensionSource(sample.source)\n : sample.source,\n );\n });\n}\n","import { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport path from 'node:path';\nimport {\n discoverExtensionWorkspace,\n loadWorkspaceThemeCatalog,\n loadExtensionWorkspaceConfig,\n resolvePackageDirFromPackageRoot,\n writeExtensionTailwindEntry,\n} from './workspace';\n\nexport interface ExtensionDevWorkbenchFilesResult {\n devRoot: string;\n count: number;\n port: string;\n}\n\nexport interface ExtensionDevWorkbenchFilesOptions {\n packageRoot?: string;\n}\n\nfunction toRelativeImport(fromDir: string, targetPath: string) {\n const relativePath = path.relative(fromDir, targetPath).split(path.sep).join('/');\n return relativePath.startsWith('.') ? relativePath : `./${relativePath}`;\n}\n\nexport function writeExtensionDevWorkbenchFiles(\n workspaceRoot: string,\n port = '5177',\n options: ExtensionDevWorkbenchFilesOptions = {},\n): ExtensionDevWorkbenchFilesResult {\n const config = {\n ...loadExtensionWorkspaceConfig(workspaceRoot),\n themeCatalog: loadWorkspaceThemeCatalog(workspaceRoot),\n };\n const entries = discoverExtensionWorkspace(workspaceRoot);\n const devRoot = path.join(workspaceRoot, '.appthen', 'dev-workbench');\n const packageRoot = options.packageRoot || path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');\n const tailwindEntry = writeExtensionTailwindEntry(workspaceRoot, packageRoot);\n mkdirSync(devRoot, { recursive: true });\n\n const imports = entries.map((entry, index) => {\n const sourcePath = path.join(entry.dir, entry.manifest.main || './src/index.tsx');\n return `import * as extension${index} from '${toRelativeImport(path.join(devRoot, 'src'), sourcePath)}';`;\n });\n const modules = entries.map((entry, index) =>\n ` { manifest: ${JSON.stringify(entry.manifest)}, module: extension${index} }`,\n );\n\n writeFileSync(\n path.join(devRoot, 'index.html'),\n '<!doctype html><html><head><meta charset=\"utf-8\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, viewport-fit=cover, interactive-widget=resizes-content\" /><title>AppThen Extension Dev</title></head><body><div id=\"root\"></div><script type=\"module\" src=\"/src/main.tsx\"></script></body></html>\\n',\n 'utf8',\n );\n mkdirSync(path.join(devRoot, 'src'), { recursive: true });\n writeFileSync(\n path.join(devRoot, 'src', 'main.tsx'),\n `${imports.join('\\n')}\\nimport ${JSON.stringify(toRelativeImport(path.join(devRoot, 'src'), tailwindEntry))};\\nimport React from 'react';\\nimport { createRoot } from 'react-dom/client';\\nimport { ExtensionDevWorkbench } from '@appthen/vibe-workspace/extension-dev-workbench';\\nimport '@appthen/vibe-workspace/styles.css';\\n\\ncreateRoot(document.getElementById('root')!).render(\\n <ExtensionDevWorkbench\\n workspace={${JSON.stringify(config)}}\\n extensions={[\\n${modules.join(',\\n')}\\n ]}\\n />,\\n);\\n`,\n 'utf8',\n );\n writeFileSync(\n path.join(devRoot, 'vite.config.ts'),\n createViteConfigSource(workspaceRoot, packageRoot),\n 'utf8',\n );\n\n if (!existsSync(path.join(workspaceRoot, 'node_modules'))) {\n writeFileSync(\n path.join(devRoot, 'README.md'),\n 'Run npm install or pnpm install in the extension workspace root before starting dev.\\n',\n 'utf8',\n );\n }\n\n return { devRoot, count: entries.length, port };\n}\n\nfunction createViteConfigSource(workspaceRoot: string, packageRoot?: string) {\n // css.postcss 传文件路径时,发布包里未必存在该文件(files 白名单/消费者\n // 安装场景),且 postcss 插件从配置文件位置解析也会因 pnpm 隔离失败。\n // 与 workspace.ts 的 extension build 路径保持一致:本包内带有\n // @tailwindcss/postcss(dependencies),直接内联其绝对路径 import。\n let postcssSnippet: string;\n let postcssImport = '';\n const tailwindPostcssPkgDir = packageRoot\n ? resolvePackageDirFromPackageRoot(packageRoot, '@tailwindcss/postcss')\n : undefined;\n const tailwindPostcssEntry = tailwindPostcssPkgDir\n ? path.join(tailwindPostcssPkgDir, 'dist', 'index.mjs')\n : undefined;\n if (tailwindPostcssEntry && existsSync(tailwindPostcssEntry)) {\n postcssImport = `import tailwindPostcss from ${JSON.stringify(tailwindPostcssEntry.replace(/\\\\/g, '/'))};\\n`;\n postcssSnippet = ' css: {\\n postcss: {\\n plugins: [tailwindPostcss()],\\n },\\n },';\n } else {\n postcssSnippet = ` css: {\\n postcss: ${JSON.stringify(path.join(packageRoot || workspaceRoot, 'postcss.config.js'))},\\n },`;\n }\n\n const packageAliases = packageRoot\n ? [\n {\n find: '@appthen/vibe-workspace/extension-dev-workbench',\n replacement: path.join(packageRoot, 'dist', 'extension-dev-workbench', 'index.js'),\n },\n {\n find: '@appthen/vibe-workspace/plugins/base',\n replacement: path.join(packageRoot, 'dist', 'plugins', 'base', 'index.js'),\n },\n {\n find: '@appthen/vibe-workspace/overlay',\n replacement: path.join(packageRoot, 'dist', 'overlay', 'index.js'),\n },\n {\n find: '@appthen/vibe-workspace/coding-kit',\n replacement: path.join(packageRoot, 'dist', 'coding-kit', 'index.js'),\n },\n {\n find: '@appthen/vibe-workspace/ui',\n replacement: path.join(packageRoot, 'dist', 'ui', 'index.js'),\n },\n {\n find: '@appthen/vibe-workspace/components',\n replacement: path.join(packageRoot, 'dist', 'components', 'index.js'),\n },\n {\n find: '@appthen/vibe-workspace/canvas-core',\n replacement: path.join(packageRoot, 'dist', 'canvas-core', 'index.js'),\n },\n {\n find: '@appthen/vibe-workspace/styles.css',\n replacement: path.join(packageRoot, 'dist', 'vibe-workspace.css'),\n },\n {\n find: '@appthen/vibe-workspace',\n replacement: path.join(packageRoot, 'dist', 'index.js'),\n },\n ]\n : [];\n const aliasEntries = packageAliases\n .map((entry) =>\n ` { find: ${JSON.stringify(entry.find)}, replacement: ${JSON.stringify(entry.replacement)} }`,\n )\n .join(',\\n');\n\n return `${postcssImport}import { defineConfig } from 'vite';\\nimport react from '@vitejs/plugin-react';\\n\\nexport default defineConfig({\\n${postcssSnippet}\\n plugins: [react()],\\n server: {\\n fs: {\\n allow: [${JSON.stringify(workspaceRoot)}${packageRoot ? `, ${JSON.stringify(packageRoot)}` : ''}],\\n },\\n },\\n resolve: {\\n alias: [\\n${aliasEntries}\\n ],\\n dedupe: ['react', 'react-dom'],\\n },\\n});\\n`;\n}\n"],"names":[],"mappings":"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"}
@@ -4,7 +4,7 @@ import { createServer } from "node:http";
4
4
  import { existsSync, statSync, readFileSync, watch } from "node:fs";
5
5
  import path from "node:path";
6
6
  import { fileURLToPath } from "node:url";
7
- import { c as createExtensionWorkspace, b as buildExtension, p as packExtension, e as validateExtensionWorkspace, E as EXTENSION_PACKAGE_EXTENSION, w as writeExtensionDevWorkbenchFiles, d as discoverExtensionWorkspace, f as findExtensionWorkspaceRoot } from "../devWorkbench-DC7468GN.js";
7
+ import { c as createExtensionWorkspace, b as buildExtension, p as packExtension, e as validateExtensionWorkspace, E as EXTENSION_PACKAGE_EXTENSION, w as writeExtensionDevWorkbenchFiles, d as discoverExtensionWorkspace, f as findExtensionWorkspaceRoot } from "../devWorkbench-Ifd_a8Pb.js";
8
8
  function printUsage() {
9
9
  console.log(`appthen-extension
10
10
 
@@ -1,4 +1,4 @@
1
- import { E, a, b, c, d, f, l, p, v, e, w } from "../devWorkbench-DC7468GN.js";
1
+ import { E, a, b, c, d, f, l, p, v, e, w } from "../devWorkbench-Ifd_a8Pb.js";
2
2
  export {
3
3
  E as EXTENSION_PACKAGE_EXTENSION,
4
4
  a as EXTENSION_WORKSPACE_CONFIG,
@@ -3,6 +3,16 @@ import { ITheme } from '../services/themeService';
3
3
  export declare const EXTENSION_WORKSPACE_CONFIG = "appthen-extension-workspace.json";
4
4
  export declare const EXTENSION_PACKAGE_EXTENSION = ".appthen-extension.json";
5
5
  export declare const EXTENSION_BUNDLE_ENTRY = "entry.js";
6
+ /**
7
+ * 从指定包根解析依赖的真实入口(兼容 pnpm 虚拟 store:依赖并不位于
8
+ * <packageRoot>/node_modules,而在 .pnpm 的虚拟层,必须走 Node 解析)。
9
+ */
10
+ export declare function resolveFromPackageRoot(packageRoot: string, spec: string): string | undefined;
11
+ /**
12
+ * 解析依赖的包目录(不支持 exports "./package.json" 的包也能解析:
13
+ * 先 resolve 主入口,再向上回溯到含 package.json 的目录)。
14
+ */
15
+ export declare function resolvePackageDirFromPackageRoot(packageRoot: string, spec: string): string | undefined;
6
16
  export declare function writeExtensionTailwindEntry(workspaceRoot: string, packageRoot: string): string;
7
17
  export declare function loadWorkspaceThemeCatalog(root: string): ITheme[];
8
18
  export declare function findExtensionWorkspaceRoot(startDir?: string): string | null;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@appthen/vibe-workspace",
3
3
  "private": false,
4
- "version": "0.1.6",
4
+ "version": "0.1.7",
5
5
  "type": "module",
6
6
  "description": "A configurable IDE-style workbench component library",
7
7
  "main": "./dist/index.js",
@@ -67,6 +67,8 @@
67
67
  },
68
68
  "files": [
69
69
  "dist",
70
+ "postcss.config.js",
71
+ "tailwind.config.js",
70
72
  "README.md",
71
73
  "PLUGIN_DEV.md",
72
74
  "docs/UI-CONTRACT.md",
@@ -94,6 +96,7 @@
94
96
  "@ai-sdk/openai": "^2.0.88",
95
97
  "@microsoft/fetch-event-source": "^2.0.1",
96
98
  "@monaco-editor/loader": "^1.4.0",
99
+ "@tailwindcss/postcss": "^4.2.1",
97
100
  "docx-preview": "^0.4.0",
98
101
  "@radix-ui/react-checkbox": "^1.3.3",
99
102
  "@radix-ui/react-dialog": "^1.1.15",
@@ -141,11 +144,12 @@
141
144
  "remark-react": "^10.0.0",
142
145
  "socket.io-client": "^4.7.1",
143
146
  "tailwind-merge": "^3.5.0",
147
+ "tailwindcss": "^4.2.1",
148
+ "tailwindcss-animate": "^1.0.7",
144
149
  "turndown": "^7.2.2",
145
150
  "zod": "^4.2.1"
146
151
  },
147
152
  "devDependencies": {
148
- "@tailwindcss/postcss": "^4.2.1",
149
153
  "@testing-library/dom": "^10.4.1",
150
154
  "@testing-library/react": "^16.3.2",
151
155
  "@types/node": "^22.14.0",
@@ -156,8 +160,6 @@
156
160
  "cross-env": "^7.0.3",
157
161
  "jsdom": "^28.1.0",
158
162
  "postcss": "^8.5.8",
159
- "tailwindcss": "^4.2.1",
160
- "tailwindcss-animate": "^1.0.7",
161
163
  "typescript": "~5.8.2",
162
164
  "vite": "6.4.1",
163
165
  "vite-plugin-dts": "^4.5.4",
@@ -0,0 +1,6 @@
1
+ export default {
2
+ plugins: {
3
+ '@tailwindcss/postcss': {},
4
+ autoprefixer: {},
5
+ },
6
+ }
@@ -0,0 +1,143 @@
1
+ import animate from "tailwindcss-animate";
2
+ import defaultTheme from "tailwindcss/defaultTheme";
3
+
4
+ /** @type {import('tailwindcss').Config} */
5
+ export default {
6
+ darkMode: ["class"],
7
+ content: [
8
+ './pages/**/*.{ts,tsx}',
9
+ './components/**/*.{ts,tsx}',
10
+ './app/**/*.{ts,tsx}',
11
+ './src/**/*.{ts,tsx}',
12
+ ],
13
+ prefix: "",
14
+ theme: {
15
+ ...defaultTheme,
16
+ container: {
17
+ center: true,
18
+ padding: "2rem",
19
+ screens: {
20
+ "2xl": "1400px",
21
+ },
22
+ },
23
+ extend: {
24
+ borderColor: {
25
+ DEFAULT: "var(--border)",
26
+ vscode: "var(--vscode-panel-border)",
27
+ "vscode-border": "var(--vscode-panel-border)",
28
+ },
29
+ colors: {
30
+ vscode: {
31
+ bg: "var(--vscode-editor-background)",
32
+ fg: "var(--vscode-editor-foreground)",
33
+ workbench: "var(--vscode-workbench-background)",
34
+ sidebar: "var(--vscode-sideBar-background)",
35
+ sidebarFg: "var(--vscode-sideBar-foreground)",
36
+ activity: "var(--vscode-activityBar-background)",
37
+ activityFg: "var(--vscode-activityBar-foreground)",
38
+ activityBorder: "var(--vscode-activityBar-activeBorder)",
39
+ itemHover: "var(--vscode-list-hoverBackground)",
40
+ accent: "var(--vscode-focusBorder)",
41
+ accentLight: "var(--accent-light)",
42
+ text: "var(--vscode-editor-foreground)",
43
+ textDark: "var(--vscode-input-placeholderForeground)",
44
+ border: "var(--vscode-panel-border)",
45
+ borderLight: "var(--border-light)",
46
+ status: "var(--vscode-statusBar-background)",
47
+ statusFg: "var(--vscode-statusBar-foreground)",
48
+ input: "var(--vscode-input-background)",
49
+ inputFg: "var(--vscode-input-foreground)",
50
+ listActive: "var(--vscode-list-activeSelectionBackground)",
51
+ listActiveFg: "var(--vscode-list-activeSelectionForeground)",
52
+ widgetShadow: "var(--vscode-widget-shadow)",
53
+ panel: "var(--vscode-panel-background)",
54
+ },
55
+ drawer: {
56
+ handle: "var(--drawer-handle-bg)",
57
+ btn: "var(--drawer-btn-bg)",
58
+ btnHover: "var(--drawer-btn-hover-bg)",
59
+ btnIcon: "var(--drawer-btn-icon)",
60
+ },
61
+ border: "var(--border)",
62
+ input: "var(--input)",
63
+ ring: "var(--ring)",
64
+ background: "var(--background)",
65
+ foreground: "var(--foreground)",
66
+ primary: {
67
+ DEFAULT: "var(--primary)",
68
+ foreground: "var(--primary-foreground)",
69
+ },
70
+ secondary: {
71
+ DEFAULT: "var(--secondary)",
72
+ foreground: "var(--secondary-foreground)",
73
+ },
74
+ destructive: {
75
+ DEFAULT: "var(--destructive)",
76
+ foreground: "var(--destructive-foreground)",
77
+ },
78
+ muted: {
79
+ DEFAULT: "var(--muted)",
80
+ foreground: "var(--muted-foreground)",
81
+ },
82
+ accent: {
83
+ DEFAULT: "var(--accent)",
84
+ foreground: "var(--accent-foreground)",
85
+ },
86
+ popover: {
87
+ DEFAULT: "var(--popover)",
88
+ foreground: "var(--popover-foreground)",
89
+ },
90
+ card: {
91
+ DEFAULT: "var(--card)",
92
+ foreground: "var(--card-foreground)",
93
+ },
94
+ portal: {
95
+ bg: "var(--portal-bg)",
96
+ card: "var(--portal-card)",
97
+ fill: "var(--portal-fill)",
98
+ border: "var(--portal-border)",
99
+ "border-hover": "var(--portal-border-hover)",
100
+ sidebar: "var(--portal-sidebar)",
101
+ "sidebar-border": "var(--portal-sidebar-border)",
102
+ title: "var(--portal-title)",
103
+ body: "var(--portal-body)",
104
+ sub: "var(--portal-sub)",
105
+ disabled: "var(--portal-disabled)",
106
+ primary: {
107
+ DEFAULT: "var(--portal-primary)",
108
+ light: "var(--portal-primary-light)",
109
+ hover: "var(--portal-primary-hover)",
110
+ },
111
+ success: "var(--portal-success)",
112
+ warning: "var(--portal-warning)",
113
+ danger: "var(--portal-danger)",
114
+ shadow: "var(--portal-shadow)",
115
+ },
116
+ },
117
+ borderRadius: {
118
+ lg: "var(--radius)",
119
+ md: "calc(var(--radius) - 2px)",
120
+ sm: "calc(var(--radius) - 4px)",
121
+ },
122
+ ringOffsetColor: {
123
+ DEFAULT: "var(--background)",
124
+ background: "var(--background)",
125
+ },
126
+ keyframes: {
127
+ "accordion-down": {
128
+ from: { height: "0" },
129
+ to: { height: "var(--radix-accordion-content-height)" },
130
+ },
131
+ "accordion-up": {
132
+ from: { height: "var(--radix-accordion-content-height)" },
133
+ to: { height: "0" },
134
+ },
135
+ },
136
+ animation: {
137
+ "accordion-down": "accordion-down 0.2s ease-out",
138
+ "accordion-up": "accordion-up 0.2s ease-out",
139
+ },
140
+ },
141
+ },
142
+ plugins: [animate],
143
+ }
@@ -1 +0,0 @@
1
- {"version":3,"file":"devWorkbench-DC7468GN.js","sources":["../src/extension-dev/workspace.ts","../src/extension-dev/devWorkbench.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { spawnSync } from 'node:child_process';\nimport { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync, cpSync, rmSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport path from 'node:path';\nimport {\n CURRENT_EXTENSION_API_VERSION,\n CURRENT_EXTENSION_MANIFEST_VERSION,\n validateManifest,\n} from '@/core/ExtensionManifestSchema';\nimport type {\n ExtensionBuildResult,\n ExtensionDevWorkspaceConfig,\n ExtensionPackageArtifact,\n ExtensionPackageFile,\n ExtensionPackageManifest,\n ExtensionValidationResult,\n ExtensionWorkspaceEntry,\n ExtensionWorkspaceTemplate,\n} from './types';\nimport type { ITheme } from '@/services/themeService';\n\nexport const EXTENSION_WORKSPACE_CONFIG = 'appthen-extension-workspace.json';\nexport const EXTENSION_PACKAGE_EXTENSION = '.appthen-extension.json';\nexport const EXTENSION_BUNDLE_ENTRY = 'entry.js';\n\nexport function writeExtensionTailwindEntry(workspaceRoot: string, packageRoot: string): string {\n const generatedDir = path.join(workspaceRoot, '.appthen', 'generated');\n mkdirSync(generatedDir, { recursive: true });\n const cssPath = path.join(generatedDir, 'extensions.css');\n const config = loadExtensionWorkspaceConfig(workspaceRoot);\n const extensionsDir = path.resolve(workspaceRoot, config.extensionsDir);\n const resolvedPackageRoot = path.resolve(packageRoot);\n const tailwindConfig = path.join(resolvedPackageRoot, 'tailwind.config.js');\n // 裸包名 \"tailwindcss\" 会从扩展工作区向上解析,可能命中宿主仓库并存的\n // v3(JS 入口)导致 postcss 报错;显式指向本包的 v4 index.css。\n const tailwindEntryCss = path.join(resolvedPackageRoot, 'node_modules', 'tailwindcss', 'index.css');\n const tailwindImport = existsSync(tailwindEntryCss)\n ? tailwindEntryCss.replace(/\\\\/g, '/')\n : 'tailwindcss';\n writeFileSync(\n cssPath,\n `@import \"${tailwindImport}\";\\n@config ${JSON.stringify(tailwindConfig)};\\n@source ${JSON.stringify(extensionsDir)};\\n`,\n 'utf8',\n );\n return cssPath;\n}\n\nconst DEFAULT_WORKSPACE_CONFIG: Required<ExtensionDevWorkspaceConfig> = {\n extensionsDir: 'extensions',\n themeCatalog: [],\n devWorkbench: {\n tenantId: 'local-tenant',\n workbenchId: 'local-extension-dev',\n name: 'Local Extension Dev',\n theme: 'acme.sales',\n enabledExtensionIds: [],\n },\n actor: {\n subjectId: 'local-subject',\n subjectClassId: 'developer',\n userId: 'local-user',\n role: 'admin',\n },\n};\n\nconst WORKBENCH_THEME_EXAMPLE = {\n id: 'acme.sales',\n label: 'Acme 销售',\n type: 'dark',\n extends: 'vercel',\n colors: {\n 'workbench.background': '#101820',\n 'editor.background': '#101820',\n 'editor.foreground': '#f4f7fa',\n 'sideBar.background': '#17232d',\n 'activityBar.background': '#0d141a',\n 'button.background': '#2f9e8f',\n 'input.background': '#1d2b35',\n 'panel.border': '#2b414d',\n },\n portalColors: {\n primary: '#2f9e8f',\n 'primary-hover': '#48b6a5',\n card: '#17232d',\n },\n monaco: {\n base: 'vs-dark',\n colors: {\n 'editor.background': '#101820',\n 'editor.foreground': '#f4f7fa',\n },\n rules: [],\n },\n};\n\nconst GENERATED_WORKSPACE_README = `# AppThen Extension Workspace\n\nThis workspace is the offline-first development environment for AppThen Workbench extensions.\n\n## Start\n\n\\`\\`\\`bash\npnpm install\npnpm doctor\npnpm dev\n\\`\\`\\`\n\nThe dev Workbench loads every extension under \\`extensions/*/manifest.json\\`. You can develop multiple extensions in this directory at the same time. Manifest changes regenerate the local Workbench entry; source changes use Vite HMR.\n\nWhen changing the Workbench SDK itself, run \\`pnpm run build:lib -- --watch\\` in the SDK repository and start this workspace with \\`pnpm dev -- --package-root /path/to/vibe-workspace\\`. Do not publish npm for local iteration.\n\n## Verify And Package\n\n\\`\\`\\`bash\npnpm validate\npnpm test\npnpm build\npnpm pack\n\\`\\`\\`\n\n\\`test\\` is a local smoke test. It validates manifests, bundles each extension, creates a package, and checks the runtime entry and integrity metadata. It does not upload or install anything.\n\n## Publish And Install\n\nPublishing uploads the package and updates the tenant extension record. It does not mount the extension into a Workbench by default.\n\n\\`\\`\\`bash\nAPPTHEN_TOKEN=\"...\" pnpm run publish -- \\\\\n --server http://127.0.0.1:1626 \\\\\n --tenant \"tenant-id\" \\\\\n --tag dev\n\nAPPTHEN_TOKEN=\"...\" pnpm run publish -- \\\\\n --server http://127.0.0.1:1626 \\\\\n --tenant \"tenant-id\" \\\\\n --install-tenant \\\\\n --tag dev\n\\`\\`\\`\n\nThe normal runtime flow is: publish -> install to the tenant -> mount in Workbench configuration -> configure availability and permissions. \\`--workbench\\` is an isolated legacy path and should not be used for the default tenant workflow.\n\n## Rules For Extensions\n\n- Use \\`activate(ctx)\\` and return a cleanup function.\n- Use \\`ctx.capabilities.registerSidebarView\\` for the extension panel.\n- Use \\`ctx.capabilities.registerEditorView\\` and \\`ctx.views.openEditor\\` for full pages and sub-pages.\n- Give editor views a stable \\`routeKey\\`; pass serializable props and a stable key.\n- Use \\`ctx.links\\` for shareable links. Do not build URLs by hand.\n- Read tenant and actor context from \\`ctx.runtime\\` and \\`ctx.auth\\`.\n- Do not use host internals such as \\`eventBus\\`, \\`workspaceEditorService\\`, or \\`registerMainView\\` in production extensions.\n- On mobile, turn multi-column layouts into navigation drawer -> list -> full-screen detail.\n\nSee \\`AGENTS.md\\` for the complete Agent handoff rules.\n`;\n\nconst GENERATED_WORKSPACE_AGENTS = `# AppThen Extension Agent Guide\n\nYou are working in an AppThen extension workspace. Keep changes inside this workspace unless the task explicitly asks for a host change.\n\n## Required Workflow\n\n1. Read the target extension's \\`manifest.json\\` and \\`src/index.tsx\\` before editing.\n2. Run \\`pnpm doctor\\` before debugging the host.\n3. Run \\`pnpm dev\\` for offline development. Do not use marketplace data for local iteration.\n4. Run \\`pnpm validate\\`, \\`pnpm test\\`, and \\`pnpm pack\\` before reporting completion.\n5. Only publish after the user provides the target server, tenant ID, and a short-lived token through the environment.\n\n## Stable Extension Contract\n\n- Manifest: \\`manifestVersion: 1\\`, \\`apiVersion: \"1\"\\`, \\`sourceType: \"umd\"\\`.\n- Icon: put a small \\`data:image/svg+xml\\` or HTTPS URL in \\`manifest.icon\\`; relative static asset paths are not part of v1.\n- Lifecycle: export \\`activate(ctx)\\`; return a disposer for every registration and subscription.\n- Sidebar: \\`ctx.capabilities.registerSidebarView\\`.\n- Main content: \\`ctx.capabilities.registerEditorView\\` plus \\`ctx.views.openEditor\\`.\n- Sharing: \\`ctx.links.create\\`, \\`ctx.links.createAbsolute\\`, or \\`ctx.links.open\\`.\n- Runtime: \\`ctx.runtime\\`, \\`ctx.auth\\`, and serializable view props.\n\n## Prohibited By Default\n\n- Do not register or open main views in external extensions.\n- Do not import host internals: \\`extensionRegistry\\`, \\`eventBus\\`, or \\`workspaceEditorService\\`.\n- Do not use the legacy \\`open\\` query parameter or manually concatenate Workbench URLs.\n- Do not put a full application page in a sidebar. Use an editor view.\n- Do not make desktop multi-column layouts vertically stack on mobile. Use a drawer, list, and full-screen detail flow.\n- Treat widths below 768px as mobile. Workbench drawers open from the bottom on mobile; WorkbenchDrawerContent with side=\"right\" already provides this default.\n- Keep mobile panel views mounted when hidden so local state and scroll containers survive returning from a detail view. Do not record scroll position with a scroll listener.\n- Use min-h-0 flex-1 overflow-y-auto for drawer content, explicit gap-2 / gap-3 / gap-4 for form and action groups, and min-width: 0; max-width: 100% for controls.\n- Do not add a dependency without updating \\`package.json\\` and verifying offline installation assumptions.\n\n## Definition Of Done\n\n- The extension has a unique stable ID and valid manifest.\n- The sidebar and editor views work in the offline Workbench.\n- Editor tabs do not duplicate when the same logical resource is opened again.\n- Routes restore the extension and the same serializable resource state.\n- Dialogs and drawers use the shared overlay package.\n- Mobile behavior has been checked at narrow and tablet widths.\n- The extension passes the UI review: no duplicated resource tabs, no overflowing controls, and list/detail return preserves filters and local state.\n- \\`pnpm doctor\\`, \\`pnpm validate\\`, \\`pnpm test\\`, and \\`pnpm pack\\` pass.\n`;\n\nfunction readJsonFile<T>(filePath: string): T {\n return JSON.parse(readFileSync(filePath, 'utf8')) as T;\n}\n\nfunction writeJsonFile(filePath: string, value: unknown) {\n mkdirSync(path.dirname(filePath), { recursive: true });\n writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\\n`, 'utf8');\n}\n\nfunction normalizeWorkspaceConfig(config?: ExtensionDevWorkspaceConfig): Required<ExtensionDevWorkspaceConfig> {\n return {\n extensionsDir: config?.extensionsDir || DEFAULT_WORKSPACE_CONFIG.extensionsDir,\n themeCatalog: config?.themeCatalog || DEFAULT_WORKSPACE_CONFIG.themeCatalog,\n devWorkbench: {\n ...DEFAULT_WORKSPACE_CONFIG.devWorkbench,\n ...(config?.devWorkbench || {}),\n enabledExtensionIds: config?.devWorkbench?.enabledExtensionIds || [],\n },\n actor: {\n ...DEFAULT_WORKSPACE_CONFIG.actor,\n ...(config?.actor || {}),\n },\n };\n}\n\nexport function loadWorkspaceThemeCatalog(root: string): ITheme[] {\n const themesRoot = path.join(root, 'themes');\n if (!existsSync(themesRoot)) return [];\n\n return readdirSync(themesRoot)\n .filter((name) => name.endsWith('.json'))\n .map((name) => {\n try {\n return readJsonFile<ITheme>(path.join(themesRoot, name));\n } catch {\n return null;\n }\n })\n .filter((theme): theme is ITheme => Boolean(theme?.id && theme?.label && theme?.colors));\n}\n\nexport function findExtensionWorkspaceRoot(startDir = process.cwd()): string | null {\n let current = path.resolve(startDir);\n while (true) {\n if (existsSync(path.join(current, EXTENSION_WORKSPACE_CONFIG))) {\n return current;\n }\n const parent = path.dirname(current);\n if (parent === current) return null;\n current = parent;\n }\n}\n\nexport function loadExtensionWorkspaceConfig(root: string): Required<ExtensionDevWorkspaceConfig> {\n const configPath = path.join(root, EXTENSION_WORKSPACE_CONFIG);\n if (!existsSync(configPath)) {\n return normalizeWorkspaceConfig();\n }\n return normalizeWorkspaceConfig(readJsonFile<ExtensionDevWorkspaceConfig>(configPath));\n}\n\nexport function discoverExtensionWorkspace(root = process.cwd()): ExtensionWorkspaceEntry[] {\n const workspaceRoot = findExtensionWorkspaceRoot(root) || path.resolve(root);\n const config = loadExtensionWorkspaceConfig(workspaceRoot);\n const extensionsRoot = path.resolve(workspaceRoot, config.extensionsDir);\n if (!existsSync(extensionsRoot)) {\n return [];\n }\n\n return readdirSync(extensionsRoot)\n .map((name) => path.join(extensionsRoot, name))\n .filter((dir) => statSync(dir).isDirectory())\n .map((dir) => {\n const manifestPath = path.join(dir, 'manifest.json');\n if (!existsSync(manifestPath)) return null;\n const manifest = readJsonFile<ExtensionPackageManifest>(manifestPath);\n return {\n id: manifest.appId || manifest.id,\n dir,\n manifestPath,\n manifest,\n } satisfies ExtensionWorkspaceEntry;\n })\n .filter((entry): entry is ExtensionWorkspaceEntry => Boolean(entry));\n}\n\nexport function validateExtensionPackageManifest(\n manifest: ExtensionPackageManifest,\n): ExtensionValidationResult {\n const base = validateManifest(manifest);\n const errors = [...base.errors];\n const warnings: string[] = [];\n\n if (manifest.appId && manifest.appId !== manifest.id) {\n warnings.push('appId differs from manifest id; runtime appId will use appId.');\n }\n if (manifest.manifestVersion === undefined) {\n warnings.push('manifestVersion is missing; the current manifest contract will be used in compatibility mode.');\n }\n if (manifest.apiVersion === undefined) {\n warnings.push('apiVersion is missing; the current Workbench API will be used in compatibility mode.');\n }\n if (!manifest.sourceType) {\n warnings.push('sourceType is missing; runtime will default to umd when installed.');\n }\n if (!manifest.runtime?.sidebarViewId && !manifest.runtime?.editorProviders?.length && !manifest.mcp?.uiResources?.length) {\n warnings.push('manifest does not declare runtime views, editor providers, or MCP UI resources.');\n }\n\n return {\n valid: base.valid && errors.length === 0,\n errors,\n warnings,\n };\n}\n\nexport function validateExtensionWorkspace(root = process.cwd()): ExtensionValidationResult {\n const entries = discoverExtensionWorkspace(root);\n const errors: string[] = [];\n const warnings: string[] = [];\n const ids = new Set<string>();\n\n if (entries.length === 0) {\n errors.push('No extensions found. Expected extensions/*/manifest.json.');\n }\n\n for (const entry of entries) {\n if (ids.has(entry.id)) {\n errors.push(`Duplicate extension id: ${entry.id}`);\n }\n ids.add(entry.id);\n const result = validateExtensionPackageManifest(entry.manifest);\n errors.push(...result.errors.map((message) => `${entry.id}: ${message}`));\n warnings.push(...result.warnings.map((message) => `${entry.id}: ${message}`));\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\nfunction listFilesRecursive(root: string): string[] {\n if (!existsSync(root)) return [];\n return readdirSync(root).flatMap((name) => {\n const absolutePath = path.join(root, name);\n const relativePath = path.relative(root, absolutePath);\n if (statSync(absolutePath).isDirectory()) {\n return listFilesRecursive(absolutePath).map((child) => path.join(relativePath, child));\n }\n return [relativePath];\n });\n}\n\nexport interface BuildExtensionOptions {\n bundle?: boolean;\n packageRoot?: string;\n}\n\nfunction toUmdGlobalName(appId: string) {\n return appId\n .split(/[.-]/)\n .filter(Boolean)\n .map((part, index) => {\n const normalized = part.replace(/[^a-zA-Z0-9_$]/g, '');\n if (!normalized) return '';\n return index === 0\n ? normalized.replace(/^[^a-zA-Z_$]+/, '') || 'AppthenExtension'\n : normalized.charAt(0).toUpperCase() + normalized.slice(1);\n })\n .join('') || 'AppthenExtension';\n}\n\nfunction resolveViteCommand(workspaceRoot: string, packageRoot?: string) {\n const binName = process.platform === 'win32' ? 'vite.cmd' : 'vite';\n const candidates = [\n path.join(workspaceRoot, 'node_modules', '.bin', binName),\n packageRoot ? path.join(packageRoot, 'node_modules', '.bin', binName) : undefined,\n ].filter((candidate): candidate is string => Boolean(candidate));\n return candidates.find((candidate) => existsSync(candidate)) || 'vite';\n}\n\nfunction createExtensionViteConfigSource(input: {\n appId: string;\n entryPath: string;\n outDir: string;\n globalName: string;\n packageRoot?: string;\n}) {\n const packageAliases = input.packageRoot\n ? [\n ['@appthen/vibe-workspace/overlay', path.join(input.packageRoot, 'dist', 'overlay', 'index.js')],\n ['@appthen/vibe-workspace/coding-kit', path.join(input.packageRoot, 'dist', 'coding-kit', 'index.js')],\n ['@appthen/vibe-workspace/canvas-core', path.join(input.packageRoot, 'dist', 'canvas-core', 'index.js')],\n ['@appthen/vibe-workspace/ui', path.join(input.packageRoot, 'dist', 'ui', 'index.js')],\n ['@appthen/vibe-workspace/components', path.join(input.packageRoot, 'dist', 'components', 'index.js')],\n ['@appthen/vibe-workspace/plugins/base', path.join(input.packageRoot, 'dist', 'plugins', 'base', 'index.js')],\n ['@appthen/vibe-workspace/styles.css', path.join(input.packageRoot, 'dist', 'vibe-workspace.css')],\n ['@appthen/vibe-workspace', path.join(input.packageRoot, 'dist', 'index.js')],\n ]\n : [];\n const aliasEntries = packageAliases\n .map(([find, replacement]) => ` { find: ${JSON.stringify(find)}, replacement: ${JSON.stringify(replacement)} }`)\n .join(',\\n');\n\n // css.postcss 传文件路径会被 vite 当作搜索目录,插件解析不到(pnpm 隔离下\n // 尤其如此)。直接内联 @tailwindcss/postcss 插件的绝对路径 import。\n const tailwindPostcssEntry = input.packageRoot\n ? path.join(input.packageRoot, 'node_modules', '@tailwindcss', 'postcss', 'dist', 'index.mjs')\n : '';\n const postcssImport = existsSync(tailwindPostcssEntry)\n ? `import tailwindPostcss from ${JSON.stringify(tailwindPostcssEntry.replace(/\\\\/g, '/'))};\\n`\n : '';\n\n return `${postcssImport}import { defineConfig } from 'vite';\\n\\nexport default defineConfig({\\n css: {\\n postcss: ${postcssImport ? '{\\n plugins: [tailwindPostcss()],\\n }' : JSON.stringify(path.join(input.packageRoot || path.dirname(input.entryPath), 'postcss.config.js'))},\\n },\\n esbuild: {\\n jsx: 'automatic',\\n },\\n build: {\\n emptyOutDir: false,\\n sourcemap: true,\\n minify: false,\\n cssCodeSplit: false,\\n outDir: ${JSON.stringify(input.outDir)},\\n lib: {\\n entry: ${JSON.stringify(input.entryPath)},\\n name: ${JSON.stringify(input.globalName)},\\n formats: ['iife'],\\n fileName: () => ${JSON.stringify(EXTENSION_BUNDLE_ENTRY)},\\n },\\n rollupOptions: {\\n external: ['react', 'react-dom', 'react/jsx-runtime', 'react/jsx-dev-runtime', 'lucide-react'],\\n output: {\\n globals: {\\n react: 'React',\\n 'react-dom': 'ReactDOM',\\n 'react/jsx-runtime': 'ReactJsxRuntime',\\n 'react/jsx-dev-runtime': 'ReactJsxRuntime',\\n 'lucide-react': 'LucideReact',\\n },\\n },\\n },\\n },\\n resolve: {\\n alias: [\\n${aliasEntries}\\n ],\\n dedupe: ['react', 'react-dom'],\\n },\\n});\\n`;\n}\n\nfunction createExtensionBundleEntry(\n workspaceRoot: string,\n entry: ExtensionWorkspaceEntry,\n sourceEntry: string,\n packageRoot: string,\n) {\n const generatedDir = path.join(workspaceRoot, '.appthen', 'generated');\n mkdirSync(generatedDir, { recursive: true });\n const wrapperPath = path.join(generatedDir, `${entry.id.replace(/[^a-zA-Z0-9_.-]/g, '_')}.tsx`);\n const tailwindEntry = writeExtensionTailwindEntry(workspaceRoot, packageRoot);\n writeFileSync(\n wrapperPath,\n `import ${JSON.stringify(tailwindEntry)};\\nimport ${JSON.stringify(sourceEntry)};\\nexport * from ${JSON.stringify(sourceEntry)};\\n`,\n 'utf8',\n );\n return wrapperPath;\n}\n\nfunction bundleExtension(entry: ExtensionWorkspaceEntry, workspaceRoot: string, buildRoot: string, packageRoot?: string) {\n const sourceEntry = path.resolve(entry.dir, entry.manifest.main || './src/index.tsx');\n if (!existsSync(sourceEntry)) {\n throw new Error(`Extension entry does not exist: ${sourceEntry}`);\n }\n\n const resolvedPackageRoot = packageRoot || path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');\n const bundleEntry = createExtensionBundleEntry(workspaceRoot, entry, sourceEntry, resolvedPackageRoot);\n const globalName = toUmdGlobalName(entry.id);\n const configDir = path.join(workspaceRoot, '.appthen', 'build', '.vite');\n mkdirSync(configDir, { recursive: true });\n const configPath = path.join(configDir, `${entry.id.replace(/[^a-zA-Z0-9_.-]/g, '_')}.config.mjs`);\n writeFileSync(\n configPath,\n createExtensionViteConfigSource({\n appId: entry.id,\n entryPath: bundleEntry,\n outDir: buildRoot,\n globalName,\n packageRoot: resolvedPackageRoot,\n }),\n 'utf8',\n );\n\n const command = resolveViteCommand(workspaceRoot, resolvedPackageRoot);\n const result = spawnSync(command, ['build', '--config', configPath], {\n cwd: workspaceRoot,\n stdio: 'pipe',\n shell: process.platform === 'win32',\n encoding: 'utf8',\n });\n if (result.status !== 0) {\n throw new Error(`Failed to build ${entry.id}:\\n${result.stdout || ''}${result.stderr || ''}`.trim());\n }\n\n return {\n globalName,\n entryFile: EXTENSION_BUNDLE_ENTRY,\n cssFiles: listFilesRecursive(buildRoot).filter((file) => file.endsWith('.css')).sort(),\n };\n}\n\nexport function buildExtension(\n entry: ExtensionWorkspaceEntry,\n workspaceRoot: string,\n options: BuildExtensionOptions = {},\n): ExtensionBuildResult {\n const buildRoot = path.join(workspaceRoot, '.appthen', 'build', entry.id);\n rmSync(buildRoot, { recursive: true, force: true });\n mkdirSync(buildRoot, { recursive: true });\n\n let runtime: Pick<ExtensionBuildResult, 'entryFile' | 'cssFiles' | 'globalName'> = {};\n const manifest: ExtensionPackageManifest = {\n ...entry.manifest,\n appId: entry.manifest.appId || entry.id,\n id: entry.manifest.id || entry.id,\n manifestVersion: entry.manifest.manifestVersion ?? CURRENT_EXTENSION_MANIFEST_VERSION,\n apiVersion: entry.manifest.apiVersion ?? CURRENT_EXTENSION_API_VERSION,\n sourceType: 'umd',\n };\n\n if (options.bundle) {\n runtime = bundleExtension(entry, workspaceRoot, buildRoot, options.packageRoot);\n manifest.main = `./${runtime.entryFile}`;\n // cssFiles 让 serve 能打印样式地址、调试面板能自动发现,缺了它本地调试会丢全部样式\n if (runtime.cssFiles.length > 0) {\n manifest.cssFiles = runtime.cssFiles;\n }\n }\n\n const manifestTarget = path.join(buildRoot, 'manifest.json');\n writeJsonFile(manifestTarget, manifest);\n\n if (!options.bundle) {\n const srcDir = path.join(entry.dir, 'src');\n const distDir = path.join(entry.dir, 'dist');\n const sourceToCopy = existsSync(distDir) ? distDir : srcDir;\n\n if (existsSync(sourceToCopy)) {\n const targetDir = path.join(buildRoot, existsSync(distDir) ? 'dist' : 'src');\n cpSync(sourceToCopy, targetDir, { recursive: true });\n }\n }\n\n return {\n id: entry.id,\n buildDir: buildRoot,\n files: listFilesRecursive(buildRoot).sort(),\n ...runtime,\n };\n}\n\nfunction sha256(buffer: Buffer | string) {\n return createHash('sha256').update(buffer).digest('hex');\n}\n\nfunction sha256Base64(buffer: Buffer | string) {\n return createHash('sha256').update(buffer).digest('base64');\n}\n\nfunction createPackageFiles(buildDir: string): ExtensionPackageFile[] {\n return listFilesRecursive(buildDir)\n .sort()\n .map((relativePath) => {\n const absolutePath = path.join(buildDir, relativePath);\n const content = readFileSync(absolutePath);\n return {\n path: relativePath,\n sha256: sha256(content),\n size: content.byteLength,\n contentBase64: content.toString('base64'),\n };\n });\n}\n\nexport interface PackExtensionOptions extends BuildExtensionOptions {\n useExistingBuild?: boolean;\n}\n\nfunction readBuildManifest(buildDir: string) {\n return readJsonFile<ExtensionPackageManifest>(path.join(buildDir, 'manifest.json'));\n}\n\nexport function packExtension(\n entry: ExtensionWorkspaceEntry,\n workspaceRoot: string,\n outDir?: string,\n options: PackExtensionOptions = {},\n): ExtensionPackageArtifact {\n const existingBuildDir = path.join(workspaceRoot, '.appthen', 'build', entry.id);\n if (options.useExistingBuild && !existsSync(existingBuildDir)) {\n throw new Error(`Build output not found for ${entry.id}. Run appthen-extension build ${entry.id} first.`);\n }\n const build = options.useExistingBuild\n ? {\n id: entry.id,\n buildDir: existingBuildDir,\n files: listFilesRecursive(existingBuildDir).sort(),\n entryFile: EXTENSION_BUNDLE_ENTRY,\n cssFiles: listFilesRecursive(existingBuildDir).filter((file) => file.endsWith('.css')).sort(),\n globalName: toUmdGlobalName(entry.id),\n }\n : buildExtension(entry, workspaceRoot, options);\n const sourceManifest = readBuildManifest(build.buildDir);\n const sourceFiles = createPackageFiles(build.buildDir);\n const manifest: ExtensionPackageManifest = {\n ...sourceManifest,\n integrity: {\n algorithm: 'sha256',\n files: Object.fromEntries(\n sourceFiles\n .filter((file) => file.path !== 'manifest.json')\n .map((file) => [file.path, `sha256-${sha256Base64(Buffer.from(file.contentBase64, 'base64'))}`]),\n ),\n },\n };\n writeJsonFile(path.join(build.buildDir, 'manifest.json'), manifest);\n const files = createPackageFiles(build.buildDir);\n const packageWithoutIntegrity = {\n format: 'appthen-extension-package',\n formatVersion: 1,\n appId: entry.id,\n version: manifest.version,\n manifest,\n runtime: {\n sourceType: 'umd',\n entryFile: build.entryFile || manifest.main?.replace(/^\\.\\//, '') || EXTENSION_BUNDLE_ENTRY,\n cssFiles: build.cssFiles || [],\n globalName: build.globalName || toUmdGlobalName(entry.id),\n },\n files,\n createdAt: new Date().toISOString(),\n } satisfies Omit<ExtensionPackageArtifact, 'integrity'>;\n const digest = sha256(JSON.stringify(packageWithoutIntegrity));\n const artifact: ExtensionPackageArtifact = {\n ...packageWithoutIntegrity,\n integrity: {\n algorithm: 'sha256',\n digest,\n },\n };\n\n const targetDir = outDir ? path.resolve(workspaceRoot, outDir) : path.join(workspaceRoot, '.appthen', 'packages');\n mkdirSync(targetDir, { recursive: true });\n const packagePath = path.join(targetDir, `${entry.id}-${manifest.version}${EXTENSION_PACKAGE_EXTENSION}`);\n writeJsonFile(packagePath, artifact);\n return artifact;\n}\n\nfunction writeExtensionFiles(\n workspaceRoot: string,\n extensionsDir: string,\n extensionId: string,\n manifest: ExtensionPackageManifest,\n source: string,\n) {\n const extensionRoot = path.join(workspaceRoot, extensionsDir, extensionId);\n writeJsonFile(path.join(extensionRoot, 'manifest.json'), {\n ...manifest,\n manifestVersion: manifest.manifestVersion ?? CURRENT_EXTENSION_MANIFEST_VERSION,\n apiVersion: manifest.apiVersion ?? CURRENT_EXTENSION_API_VERSION,\n });\n mkdirSync(path.join(extensionRoot, 'src'), { recursive: true });\n writeFileSync(path.join(extensionRoot, 'src', 'index.tsx'), source, 'utf8');\n}\n\nconst EXAMPLE_EXTENSION_ICONS = {\n workbench: 'data:image/svg+xml,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"%3E%3Crect width=\"32\" height=\"32\" rx=\"8\" fill=\"%232F9E8F\"/%3E%3Cpath d=\"M8 9h16v4H8zm0 6h10v4H8zm0 6h16v4H8z\" fill=\"white\"/%3E%3C/svg%3E',\n sidebar: 'data:image/svg+xml,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"%3E%3Crect width=\"32\" height=\"32\" rx=\"8\" fill=\"%233B82F6\"/%3E%3Cpath d=\"M8 9h6l2 2h8v12H8V9zm4 5h8v2h-8zm0 4h6v2h-6z\" fill=\"white\"/%3E%3C/svg%3E',\n sandbox: 'data:image/svg+xml,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"%3E%3Crect width=\"32\" height=\"32\" rx=\"8\" fill=\"%23F59E0B\"/%3E%3Cpath d=\"M16 7a9 9 0 1 0 0 18 9 9 0 0 0 0-18zm0 0c2 2.2 3 5.2 3 9s-1 6.8-3 9c-2-2.2-3-5.2-3-9s1-6.8 3-9zM7 16h18M9 11h14M9 21h14\" fill=\"none\" stroke=\"white\" stroke-width=\"1.7\" stroke-linecap=\"round\"/%3E%3C/svg%3E',\n tool: 'data:image/svg+xml,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"%3E%3Crect width=\"32\" height=\"32\" rx=\"8\" fill=\"%232F9E8F\"/%3E%3Cpath d=\"M18 6l-8 12h6l-2 8 8-12h-6l2-8z\" fill=\"white\"/%3E%3C/svg%3E',\n multi: 'data:image/svg+xml,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"%3E%3Crect width=\"32\" height=\"32\" rx=\"8\" fill=\"%237C3AED\"/%3E%3Crect x=\"8\" y=\"8\" width=\"7\" height=\"16\" rx=\"1.5\" fill=\"white\"/%3E%3Crect x=\"17\" y=\"8\" width=\"7\" height=\"7\" rx=\"1.5\" fill=\"white\"/%3E%3Crect x=\"17\" y=\"17\" width=\"7\" height=\"7\" rx=\"1.5\" fill=\"white\"/%3E%3C/svg%3E',\n} as const;\n\nfunction createWorkbenchKitExampleExtension(extensionId: string): {\n manifest: ExtensionPackageManifest;\n source: string;\n} {\n return {\n manifest: {\n id: extensionId,\n name: '工作台工具包示例',\n version: '0.1.0',\n icon: EXAMPLE_EXTENSION_ICONS.workbench,\n main: './src/index.tsx',\n sourceType: 'umd',\n runtime: {\n sidebarViewId: `sidebar.${extensionId}`,\n autoActivate: true,\n },\n mcp: {\n enabled: true,\n uiResources: [\n {\n uri: `ui://${extensionId}/starter-card`,\n name: '起手式卡片区块',\n description: '由本地扩展提供的可复用卡片区块。',\n mimeType: 'text/html',\n content: '<section data-block=\"starter-card\">工作台起手式卡片</section>',\n metadata: {\n capabilities: ['展示', '起手式'],\n },\n },\n ],\n frontendTools: [\n {\n name: 'starter.echo',\n description: '回显本地扩展收到的输入数据。',\n inputSchema: {\n type: 'object',\n properties: {\n message: { type: 'string' },\n },\n },\n handlerRef: 'echo',\n },\n ],\n },\n },\n source: \"import React from 'react';\\nimport type { PluginContext } from '@appthen/vibe-workspace/plugins/base';\\n\\nconst VIEW_API_GALLERY = 'main.acme.workbench-kit.api-gallery';\\nconst VIEW_COMPONENT_PREVIEW = 'editor.acme.workbench-kit.component-preview';\\nconst VIEW_API_REFERENCE = 'editor.acme.workbench-kit.api-reference';\\n\\ntype OpenEditorTab = (viewId: string, title: string, props?: Record<string, unknown>) => void;\\n\\nlet openMainView: () => void = () => undefined;\\nlet openEditorTab: OpenEditorTab = () => undefined;\\n\\nconst panelStyle: React.CSSProperties = {\\n height: '100%',\\n overflow: 'auto',\\n padding: 16,\\n color: 'var(--vscode-editor-foreground)',\\n background: 'var(--vscode-sideBar-background)',\\n fontFamily: 'system-ui, sans-serif',\\n};\\n\\nconst mainStyle: React.CSSProperties = {\\n height: '100%',\\n overflow: 'auto',\\n padding: 24,\\n color: 'var(--vscode-editor-foreground)',\\n background: 'var(--vscode-editor-background)',\\n fontFamily: 'system-ui, sans-serif',\\n};\\n\\nconst cardStyle: React.CSSProperties = {\\n border: '1px solid var(--vscode-panel-border)',\\n borderRadius: 8,\\n padding: 12,\\n background: 'var(--vscode-panel-background)',\\n};\\n\\nconst buttonStyle: React.CSSProperties = {\\n height: 32,\\n borderRadius: 6,\\n border: '1px solid var(--vscode-panel-border)',\\n color: 'var(--vscode-editor-foreground)',\\n background: 'var(--vscode-input-background)',\\n};\\n\\nconst mutedStyle: React.CSSProperties = {\\n color: 'var(--vscode-input-placeholderForeground)',\\n lineHeight: 1.6,\\n};\\n\\nfunction BlockCard({ title, children }: { title: string; children: React.ReactNode }) {\\n return (\\n <section style={cardStyle}>\\n <div style={{ fontSize: 13, fontWeight: 700 }}>{title}</div>\\n <div style={{ marginTop: 8, fontSize: 12, ...mutedStyle }}>{children}</div>\\n </section>\\n );\\n}\\n\\nfunction Sidebar() {\\n return (\\n <div style={panelStyle}>\\n <h2 style={{ margin: 0, fontSize: 16 }}>Workbench Kit</h2>\\n <p style={{ marginTop: 8, ...mutedStyle }}>\\n A starter extension that documents Workbench APIs, reusable blocks, and editor-tab views.\\n </p>\\n <div style={{ display: 'grid', gap: 10, marginTop: 16 }}>\\n <BlockCard title=\\\"Sidebar view\\\">Registered with ctx.capabilities.registerSidebarView.</BlockCard>\\n <BlockCard title=\\\"Main view\\\">Open a full Workbench view without creating an editor tab.</BlockCard>\\n <BlockCard title=\\\"Editor tab views\\\">Open React components as normal main-area tabs with view:// files.</BlockCard>\\n <button type=\\\"button\\\" style={buttonStyle} onClick={openMainView}>\\n Open API Gallery\\n </button>\\n <button\\n type=\\\"button\\\"\\n style={buttonStyle}\\n onClick={() => openEditorTab(VIEW_COMPONENT_PREVIEW, 'Component Preview', { variant: 'compact' })}\\n >\\n Open Component Preview Tab\\n </button>\\n <button\\n type=\\\"button\\\"\\n style={buttonStyle}\\n onClick={() => openEditorTab(VIEW_API_REFERENCE, 'API Reference', { section: 'capabilities' })}\\n >\\n Open API Reference Tab\\n </button>\\n </div>\\n </div>\\n );\\n}\\n\\nfunction MainView({ onClose }: { onClose?: () => void }) {\\n return (\\n <div style={mainStyle}>\\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 }}>\\n <h1 style={{ margin: 0, fontSize: 22 }}>Extension API Gallery</h1>\\n <button type=\\\"button\\\" style={{ ...buttonStyle, padding: '0 12px' }} onClick={onClose}>\\n Close\\n </button>\\n </div>\\n <p style={{ marginTop: 8, maxWidth: 720, ...mutedStyle }}>\\n This main view is useful for dashboards, settings pages, and full-page extension surfaces.\\n </p>\\n <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 12, marginTop: 20 }}>\\n <BlockCard title=\\\"Component block\\\">Create small React blocks with CSS variables so they inherit the Workbench theme.</BlockCard>\\n <BlockCard title=\\\"Runtime API\\\">Read tenant, workbench and actor context from ctx.runtime and ctx.auth.</BlockCard>\\n <BlockCard title=\\\"Contribution point\\\">Register topbar, explorer or custom contributions with ctx.capabilities.registerContribution.</BlockCard>\\n <BlockCard title=\\\"UI resource\\\">Expose reusable UI assets from manifest.mcp.uiResources for later platform sharing.</BlockCard>\\n </div>\\n </div>\\n );\\n}\\n\\nfunction ComponentPreviewTab(props: { title?: string; variant?: string }) {\\n return (\\n <div style={mainStyle}>\\n <h1 style={{ margin: 0, fontSize: 20 }}>{props.title || 'Component Preview'}</h1>\\n <p style={{ marginTop: 8, ...mutedStyle }}>\\n This React component was opened as a normal editor tab through workspaceEditorService.createViewFile().\\n </p>\\n <div style={{ display: 'grid', gap: 12, marginTop: 20, maxWidth: 520 }}>\\n <BlockCard title=\\\"Reusable block\\\">Use this pattern for tenant-specific components before promoting them to the shared package.</BlockCard>\\n <BlockCard title=\\\"Props\\\">variant = {props.variant || '-'}</BlockCard>\\n </div>\\n </div>\\n );\\n}\\n\\nfunction ApiReferenceTab(props: { title?: string; section?: string }) {\\n return (\\n <div style={mainStyle}>\\n <h1 style={{ margin: 0, fontSize: 20 }}>{props.title || 'API Reference'}</h1>\\n <p style={{ marginTop: 8, ...mutedStyle }}>\\n This tab shows the minimum APIs most local extensions need.\\n </p>\\n <pre style={{ ...cardStyle, marginTop: 20, whiteSpace: 'pre-wrap', fontSize: 12, lineHeight: 1.6 }}>\\n{`ctx.capabilities.registerSidebarView(...)\\nctx.capabilities.registerMainView(...)\\nctx.capabilities.registerEditorView(...)\\nctx.capabilities.registerFrontendToolHandler(...)\\nctx.capabilities.registerContribution(...)`}\\n </pre>\\n <p style={{ marginTop: 12, ...mutedStyle }}>section = {props.section || '-'}</p>\\n </div>\\n );\\n}\\n\\nexport function activate(ctx: PluginContext) {\\n const workspaceEditorService = ctx.services?.workspaceEditorService;\\n\\n openMainView = () => {\\n ctx.eventBus?.emit('workbench', 'mainView.open', { viewId: VIEW_API_GALLERY });\\n };\\n\\n openEditorTab = (viewId, title, props = {}) => {\\n if (!workspaceEditorService) {\\n console.warn('[workbench-kit] workspaceEditorService is not available.');\\n return;\\n }\\n const file = workspaceEditorService.createViewFile(viewId, title, { ...props, title }, title);\\n ctx.eventBus?.emit('workbench', 'layout.forceOpen', { fileId: file.id });\\n };\\n\\n const disposers = [\\n ctx.capabilities.registerSidebarView({\\n id: 'sidebar.acme.workbench-kit',\\n title: 'Workbench Kit',\\n component: Sidebar,\\n }),\\n ctx.capabilities.registerMainView({\\n id: VIEW_API_GALLERY,\\n title: 'Extension API Gallery',\\n component: MainView,\\n showInTabs: true,\\n closable: true,\\n }),\\n ctx.capabilities.registerEditorView({\\n id: VIEW_COMPONENT_PREVIEW,\\n title: 'Component Preview',\\n component: ComponentPreviewTab,\\n }),\\n ctx.capabilities.registerEditorView({\\n id: VIEW_API_REFERENCE,\\n title: 'API Reference',\\n component: ApiReferenceTab,\\n }),\\n ctx.capabilities.registerFrontendToolHandler({\\n ref: 'echo',\\n source: 'manifest:acme.workbench-kit',\\n handler: async (input, runtime) => ({\\n ok: true,\\n input,\\n actor: runtime.actor,\\n handledAt: new Date().toISOString(),\\n }),\\n }),\\n ctx.capabilities.registerContribution('topbar.item', 'acme.workbench-kit.status', {\\n component: () => <span style={{ fontSize: 12, color: 'var(--vscode-input-placeholderForeground)' }}>Local Extension</span>,\\n }),\\n ];\\n\\n return () => disposers.forEach((dispose) => dispose());\\n}\\n\".replaceAll(\"acme.workbench-kit\", extensionId),\n };\n}\n\nfunction localizeGeneratedWorkbenchKitSource(source: string): string {\n const replacements: Array<[string, string]> = [\n ['Workbench Kit', '工作台工具包'],\n ['A starter extension that documents Workbench APIs, reusable blocks, and editor-tab views.', '用于展示工作台 API、可复用区块和编辑器页签的扩展起手式。'],\n ['Sidebar view', '侧边栏视图'],\n ['Registered with ctx.capabilities.registerSidebarView.', '通过 ctx.capabilities.registerSidebarView 注册。'],\n ['Main view', '编辑器页签'],\n ['Open a full Workbench view without creating an editor tab.', '打开完整的工作台页面,并使用独立编辑器页签承载。'],\n ['Editor tab views', '编辑器页签视图'],\n ['Open React components as normal main-area tabs with view:// files.', '将 React 组件作为普通主区域页签打开,并使用 view:// 文件定位。'],\n ['Open API Gallery', '打开 API 示例页签'],\n ['Open Theme Guide', '打开主题指南页签'],\n ['Open Component Preview Tab', '打开组件预览页签'],\n ['Component Preview', '组件预览'],\n ['Open API Reference Tab', '打开 API 参考页签'],\n ['API Reference', 'API 参考'],\n ['Open Extension Cases', '打开扩展案例页签'],\n ['Open UI Components Tab', '打开 UI 组件页签'],\n ['Open Coding Collaboration Template', '打开 Coding 协作模板'],\n ['Coding Collaboration Template', 'Coding 协作模板'],\n ['UI Components', 'UI 组件'],\n ['Run Regression Checks', '运行回归检查'],\n ['Regression Checks', '回归检查'],\n ['Extension API Gallery', '扩展 API 示例'],\n ['>Close<', '>关闭<'],\n ['\\n Close\\n', '\\n 关闭\\n'],\n ['This main view is useful for dashboards, settings pages, and full-page extension surfaces.', '这个编辑器页签适合承载仪表盘、设置页和完整的扩展页面。'],\n ['Component block', '组件区块'],\n ['Create small React blocks with CSS variables so they inherit the Workbench theme.', '使用 CSS 变量创建小型 React 区块,使其自动继承工作台主题。'],\n ['Runtime API', '运行时 API'],\n ['Read tenant, workbench and actor context from ctx.runtime and ctx.auth.', '从 ctx.runtime 和 ctx.auth 读取租户、工作台和当前操作者上下文。'],\n ['Contribution point', '贡献点'],\n ['Register topbar, explorer or custom contributions with ctx.capabilities.registerContribution.', '通过 ctx.capabilities.registerContribution 注册顶部栏、资源管理器或自定义贡献。'],\n ['UI resource', 'UI 资源'],\n ['Expose reusable UI assets from manifest.mcp.uiResources for later platform sharing.', '通过 manifest.mcp.uiResources 暴露可复用 UI 资源,为后续平台共享做准备。'],\n ['Workbench Theme Guide', '工作台主题指南'],\n ['A runnable reference for the offline theme contract. Theme definitions belong to the Workbench configuration, not an extension activation side effect.', '离线主题契约的可运行参考。主题定义属于工作台配置,不应通过扩展激活副作用设置。'],\n [\"['Workbench',\", \"['工作台',\"],\n [\"['Editor',\", \"['编辑器',\"],\n [\"['Sidebar',\", \"['侧边栏',\"],\n ['Accent', '强调色'],\n [\"['Portal',\", \"['门户',\"],\n ['Suggested local file: themes/acme-sales.json. This documents the contract and token inheritance; global custom theme registration is the next runtime capability.', '建议使用本地文件:themes/acme-sales.json。本地 Workbench 会自动加载它,并通过工作台配置的 theme 字段设为默认主题。'],\n ['This React component was opened as a normal editor tab through workspaceEditorService.createViewFile().', '这个 React 组件通过 ctx.views.openEditor() 作为普通编辑器页签打开。'],\n ['Use this pattern for tenant-specific components before promoting them to the shared package.', '租户专属组件可以先采用这种模式,成熟后再提升到共享 UI 包。'],\n ['Props', '属性'],\n ['Interactive UI component example. variant = ', '可提升为共享 UI 区块的交互式组件示例。变体 = '],\n ['variant = ', '变体 = '],\n ['This tab shows the minimum APIs most local extensions need.', '这个页签展示大多数本地扩展所需的最小 API 集合。'],\n ['section = ', '章节 = '],\n ['Sidebar contribution', '侧边栏贡献'],\n ['Register a sidebar view with ctx.capabilities.', '使用 ctx.capabilities 注册侧边栏视图。'],\n ['Deep-linkable editor tab', '可分享的编辑器页签'],\n ['Open a view with a stable routeKey and serializable props.', '使用稳定的 routeKey 和可序列化属性打开视图。'],\n ['Runtime API check', '运行时 API 检查'],\n ['Inspect tenant, workbench and actor context in a live extension.', '在真实扩展中查看租户、工作台和当前操作者上下文。'],\n ['Extension Cases', '扩展案例'],\n ['Runnable examples for the stable Workbench extension contract.', '稳定工作台扩展契约的可运行案例。'],\n ['Open case', '打开案例'],\n ['Interactive component examples that can be promoted into shared UI blocks.', '可提升为共享 UI 区块的交互式组件示例。'],\n ['<strong>Button</strong>', '<strong>按钮</strong>'],\n ['Clicked ', '已点击 '],\n [' times.', ' 次。'],\n ['Click component', '点击组件'],\n ['Toggle', '开关'],\n ['Enabled', '已启用'],\n ['Disabled', '已禁用'],\n ['Plugin context', '插件上下文'],\n ['Runtime context', '运行时上下文'],\n ['View API', '视图 API'],\n ['Link API', '链接 API'],\n ['Capability API', '能力 API'],\n ['A small smoke-test surface for the extension host contract.', '用于快速验证扩展宿主契约的小型检查面板。'],\n ['Run checks', '运行检查'],\n ['PASS', '通过'],\n ['FAIL', '失败'],\n ['NOT RUN', '未运行'],\n ['Local Extension', '本地扩展'],\n ['Acme Sales', 'Acme 销售'],\n ];\n return replacements.reduce((result, [from, to]) => result.replaceAll(from, to), source);\n}\n\nfunction normalizeGeneratedWorkbenchKitSource(source: string): string {\nconst kitEnhancements = `\ntype CodingTemplateItem = { id: string; title: string; description: string; owner: string; status: '进行中' | '已完成' | '待开始'; due: string };\nconst codingTemplateItems: CodingTemplateItem[] = [\n { id: 'task-001', title: '完善成员邀请流程', description: '补齐邀请、角色和通知状态的协作流程。', owner: '林夏', status: '进行中', due: '今天' },\n { id: 'task-002', title: '整理工作台权限矩阵', description: '确认团队管理员和普通成员的功能边界。', owner: '周然', status: '待开始', due: '明天' },\n { id: 'task-003', title: '发布移动端适配检查单', description: '覆盖列表、详情、抽屉和表单的窄屏行为。', owner: '陈默', status: '已完成', due: '周五' },\n];\n\nfunction CodingTemplateView() {\n const [query, setQuery] = useState('');\n const [statusFilter, setStatusFilter] = useState('全部状态');\n const [editorOpen, setEditorOpen] = useState(false);\n const visibleItems = codingTemplateItems.filter((item) => {\n const normalizedQuery = query.trim().toLowerCase();\n const matchesQuery = !normalizedQuery || [item.title, item.description, item.owner].join(' ').toLowerCase().includes(normalizedQuery);\n return matchesQuery && (statusFilter === '全部状态' || item.status === statusFilter);\n });\n\n return (\n <div className=\"coding-kit\" style={{ height: '100%', minHeight: 0, padding: 16, background: 'var(--ck-surface-page)' }}>\n <CodingListDetailWorkspace\n title=\"事项协作\"\n subtitle=\"Workbench Kit 的标准列表-详情模板,适用于团队协作型扩展。\"\n rows={visibleItems}\n getRowInfo={(item) => ({ key: item.id, title: item.title, description: item.description, meta: item.owner + ' · 截止 ' + item.due, status: <span style={{ borderRadius: 4, padding: '3px 6px', color: 'var(--ck-status-brand-text)', background: 'var(--ck-status-brand-bg)', fontSize: 11 }}>{item.status}</span> })}\n toolbar={(\n <div style={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 8 }}>\n <div style={{ width: 'min(100%, 320px)', minWidth: 0 }}><CodingInput value={query} onChange={(event) => setQuery(event.target.value)} placeholder=\"搜索事项、描述或负责人\" containerClassName=\"min-w-0\" /></div>\n <WorkbenchSelect value={statusFilter} onValueChange={setStatusFilter}><WorkbenchSelectTrigger aria-label=\"事项状态\" className=\"text-xs\" style={{ width: 160, height: 32 }}><WorkbenchSelectValue placeholder=\"全部状态\" /></WorkbenchSelectTrigger><WorkbenchSelectContent><WorkbenchSelectItem value=\"全部状态\">全部状态</WorkbenchSelectItem><WorkbenchSelectItem value=\"进行中\">进行中</WorkbenchSelectItem><WorkbenchSelectItem value=\"待开始\">待开始</WorkbenchSelectItem><WorkbenchSelectItem value=\"已完成\">已完成</WorkbenchSelectItem></WorkbenchSelectContent></WorkbenchSelect>\n </div>\n )}\n headerActions={<CodingButton type=\"button\" variant=\"primary\" size=\"sm\" onClick={() => setEditorOpen(true)}>新建事项</CodingButton>}\n detailActions={<CodingButton type=\"button\" size=\"sm\" onClick={() => setEditorOpen(true)}>编辑</CodingButton>}\n renderDetail={({ row }) => <div style={{ display: 'grid', gap: 16 }}><CodingPanel style={{ padding: 16 }}><div style={{ color: 'var(--ck-text-muted)', fontSize: 12 }}>事项说明</div><p style={{ margin: '8px 0 0', color: 'var(--ck-text-primary)', fontSize: 14, lineHeight: 1.7 }}>{row.description}</p></CodingPanel><CodingPanel style={{ display: 'grid', gap: 12, padding: 16 }}><div style={{ display: 'flex', justifyContent: 'space-between', gap: 12 }}><span style={{ color: 'var(--ck-text-muted)', fontSize: 12 }}>负责人</span><strong>{row.owner}</strong></div><div style={{ display: 'flex', justifyContent: 'space-between', gap: 12 }}><span style={{ color: 'var(--ck-text-muted)', fontSize: 12 }}>状态</span><strong>{row.status}</strong></div><div style={{ display: 'flex', justifyContent: 'space-between', gap: 12 }}><span style={{ color: 'var(--ck-text-muted)', fontSize: 12 }}>截止时间</span><strong>{row.due}</strong></div></CodingPanel></div>}\n editor={<div style={{ display: 'grid', minWidth: 0, gap: 16 }}><label style={{ display: 'grid', minWidth: 0, gap: 6, fontSize: 12 }}>事项标题<CodingInput defaultValue=\"新的协作事项\" style={{ minWidth: 0, maxWidth: '100%' }} /></label><label style={{ display: 'grid', minWidth: 0, gap: 6, fontSize: 12 }}>事项描述<textarea defaultValue=\"填写目标、范围和协作信息\" style={{ minHeight: 96, width: '100%', maxWidth: '100%', resize: 'vertical', border: '1px solid var(--ck-border-default)', borderRadius: 4, padding: 10, background: 'var(--ck-surface-overlay)', font: 'inherit', fontSize: 13 }} /></label></div>}\n editorTitle=\"新建协作事项\"\n editorDescription=\"桌面端从右侧打开,移动端从底部打开。\"\n editorOpen={editorOpen}\n onEditorOpenChange={setEditorOpen}\n editorFooter={<div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8, width: '100%' }}><CodingButton type=\"button\" size=\"sm\" onClick={() => setEditorOpen(false)}>取消</CodingButton><CodingButton type=\"button\" variant=\"primary\" size=\"sm\" onClick={() => setEditorOpen(false)}>保存</CodingButton></div>}\n />\n </div>\n );\n}\n\nfunction openEditorViewById(viewId: string, title: string) {\n kitContext?.views.openEditor({ viewId, title, props: { title }, key: viewId });\n}\n\nfunction OverlayGuideView({ onClose }: { onClose?: () => void }) {\n const [dialogOpen, setDialogOpen] = useState(false);\n const [drawerOpen, setDrawerOpen] = useState(false);\n return (\n <div style={mainStyle}>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 }}><h1 style={{ margin: 0, fontSize: 22 }}>弹窗与侧边抽屉规范</h1><button type=\"button\" style={{ ...buttonStyle, padding: '0 12px' }} onClick={onClose}>关闭</button></div>\n <p style={{ marginTop: 8, maxWidth: 760, ...mutedStyle }}>主项目和扩展都应遵循同一套 Overlay 交互契约。下面两个实例可直接操作验证。</p>\n <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))', gap: 12, marginTop: 20 }}><section style={cardStyle}><h2 style={{ margin: 0, fontSize: 15 }}>弹窗 Dialog</h2><p style={{ margin: '8px 0 0', fontSize: 12, ...mutedStyle }}>适用于确认、创建、编辑和权限变更等聚焦任务。</p><button type=\"button\" style={{ ...buttonStyle, marginTop: 14 }} onClick={() => setDialogOpen(true)}>打开弹窗</button></section><section style={cardStyle}><h2 style={{ margin: 0, fontSize: 15 }}>侧边抽屉 Drawer</h2><p style={{ margin: '8px 0 0', fontSize: 12, ...mutedStyle }}>适用于详情、筛选、分享和配置等上下文任务。</p><button type=\"button\" style={{ ...buttonStyle, marginTop: 14 }} onClick={() => setDrawerOpen(true)}>打开抽屉</button></section></div>\n <section style={{ ...cardStyle, marginTop: 12 }}><h2 style={{ margin: 0, fontSize: 15 }}>共同规则</h2><ul style={{ margin: '10px 0 0', paddingLeft: 20, fontSize: 12, lineHeight: 1.8 }}><li>必须有标题;有解释内容时同时提供描述。</li><li>支持 Esc、遮罩点击、焦点恢复和内容区滚动。</li><li>需要分享或恢复的内容统一使用编辑器页签。</li></ul></section>\n <WorkbenchDialog open={dialogOpen} onOpenChange={setDialogOpen}>\n <WorkbenchDialogContent>\n <WorkbenchDialogHeader><WorkbenchDialogTitle>示例弹窗</WorkbenchDialogTitle><WorkbenchDialogDescription>用于确认、创建和编辑等需要聚焦完成的任务。</WorkbenchDialogDescription></WorkbenchDialogHeader>\n <div className=\"text-sm leading-6\"><p>弹窗默认限制宽度和高度,超出内容只在内容区域滚动。</p><p className=\"mt-3 text-xs text-muted-foreground\">支持 Esc、遮罩点击和明确的关闭按钮。</p></div>\n <WorkbenchDialogFooter><button type=\"button\" className=\"rounded-md border border-border bg-secondary px-3 py-2 text-xs font-medium\" onClick={() => setDialogOpen(false)}>取消</button><button type=\"button\" className=\"rounded-md bg-primary px-3 py-2 text-xs font-medium text-primary-foreground\" onClick={() => setDialogOpen(false)}>完成示例</button></WorkbenchDialogFooter>\n </WorkbenchDialogContent>\n </WorkbenchDialog>\n <WorkbenchDrawer open={drawerOpen} onOpenChange={setDrawerOpen}>\n <WorkbenchDrawerContent side=\"right\" mobileSide=\"bottom\" className=\"flex flex-col gap-0 overflow-hidden p-0\">\n <WorkbenchDrawerHeader className=\"shrink-0 border-b border-border px-5 py-4 pr-14\"><WorkbenchDrawerTitle>示例侧边抽屉</WorkbenchDrawerTitle><WorkbenchDrawerDescription>用于详情、筛选、分享和配置,同时保留当前主区域上下文。</WorkbenchDrawerDescription></WorkbenchDrawerHeader>\n <div className=\"min-h-0 flex-1 overflow-y-auto p-5 text-sm leading-6\"><p>桌面端从右侧打开,移动端自动切换为底部抽屉。</p><div className=\"mt-4 grid gap-2\">{Array.from({ length: 8 }, (_, index) => <div key={index} className=\"rounded-md border border-border p-2.5\">可滚动内容 {index + 1}</div>)}</div></div>\n <WorkbenchDrawerFooter className=\"shrink-0 border-t border-border px-5 py-3\"><button type=\"button\" className=\"rounded-md bg-primary px-3 py-2 text-xs font-medium text-primary-foreground\" onClick={() => setDrawerOpen(false)}>关闭抽屉</button></WorkbenchDrawerFooter>\n </WorkbenchDrawerContent>\n </WorkbenchDrawer>\n </div>\n );\n}\n\nfunction ResponsiveWorkspaceGuide({ onClose }: { onClose?: () => void }) {\n const [detailOpen, setDetailOpen] = useState(false);\n const members = ['林夏', '周然', '陈默'];\n return (\n <div style={mainStyle}>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 }}>\n <h1 style={{ margin: 0, fontSize: 22 }}>多栏工作区与移动端折叠规范</h1>\n <button type=\"button\" style={{ ...buttonStyle, padding: '0 12px' }} onClick={onClose}>关闭</button>\n </div>\n <p style={{ marginTop: 8, maxWidth: 760, ...mutedStyle }}>桌面端保留导航、列表、详情的并行关系;移动端使用导航抽屉、列表和全屏详情。</p>\n {!detailOpen ? (\n <section style={{ ...cardStyle, marginTop: 20 }}>\n <strong>移动端列表</strong>\n <div style={{ display: 'grid', gap: 8, marginTop: 10 }}>{members.map((member) => <button key={member} type=\"button\" style={{ ...buttonStyle, textAlign: 'left' }} onClick={() => setDetailOpen(true)}>{member} · 研发部</button>)}</div>\n </section>\n ) : (\n <section style={{ ...cardStyle, marginTop: 20 }}>\n <button type=\"button\" style={{ ...buttonStyle, padding: '0 10px' }} onClick={() => setDetailOpen(false)}>返回成员列表</button>\n <h2 style={{ margin: '16px 0 0', fontSize: 16 }}>成员详情</h2>\n <p style={{ marginTop: 8, ...mutedStyle }}>移动端详情使用全屏承载,返回后保留列表状态。</p>\n </section>\n )}\n <section style={{ ...cardStyle, marginTop: 12 }}><strong>禁止做法</strong><p style={{ margin: '8px 0 0', ...mutedStyle }}>不要把桌面多栏简单压成一张很长的纵向页面,也不要隐藏详情导致关键操作丢失。</p></section>\n </div>\n );\n}\n\nconst themeExample = {\n id: 'acme.sales',\n label: 'Acme Sales',\n type: 'dark',\n extends: 'vercel',\n colors: {\n 'workbench.background': '#101820',\n 'editor.background': '#101820',\n 'editor.foreground': '#f4f7fa',\n 'sideBar.background': '#17232d',\n 'activityBar.background': '#0d141a',\n 'button.background': '#2f9e8f',\n 'input.background': '#1d2b35',\n 'panel.border': '#2b414d',\n },\n portalColors: {\n primary: '#2f9e8f',\n 'primary-hover': '#48b6a5',\n card: '#17232d',\n },\n monaco: {\n base: 'vs-dark',\n colors: {\n 'editor.background': '#101820',\n 'editor.foreground': '#f4f7fa',\n },\n rules: [],\n },\n};\n\nfunction ThemeGuideView({ onClose }: { onClose?: () => void }) {\n return (\n <div style={mainStyle}>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 }}>\n <h1 style={{ margin: 0, fontSize: 22 }}>Workbench Theme Guide</h1>\n <button type=\"button\" style={{ ...buttonStyle, padding: '0 12px' }} onClick={onClose}>Close</button>\n </div>\n <p style={{ marginTop: 8, maxWidth: 760, ...mutedStyle }}>\n A runnable reference for the offline theme contract. Theme definitions belong to the Workbench configuration, not an extension activation side effect.\n </p>\n <div style={{ display: 'grid', gap: 12, gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', marginTop: 20 }}>\n {[\n ['Workbench', 'var(--vscode-workbench-background)'],\n ['Editor', 'var(--vscode-editor-background)'],\n ['Sidebar', 'var(--vscode-sideBar-background)'],\n ['Accent', 'var(--vscode-button-background)'],\n ['Portal', 'var(--portal-primary)'],\n ].map(([label, color]) => (\n <section key={label} style={{ ...cardStyle, display: 'flex', alignItems: 'center', gap: 10 }}>\n <span style={{ width: 28, height: 28, borderRadius: 6, background: color, border: '1px solid var(--vscode-panel-border)' }} />\n <div><strong>{label}</strong><div style={{ fontSize: 11, ...mutedStyle }}>{color}</div></div>\n </section>\n ))}\n </div>\n <pre style={{ ...cardStyle, marginTop: 20, whiteSpace: 'pre-wrap', fontSize: 12, lineHeight: 1.6 }}>\n {JSON.stringify(themeExample, null, 2)}\n </pre>\n <p style={{ marginTop: 12, ...mutedStyle }}>\n Suggested local file: themes/acme-sales.json. The offline Workbench loads it automatically; set devWorkbench.theme to acme.sales to make it the default.\n </p>\n </div>\n );\n}\n\nfunction CasesView({ onClose }: { onClose?: () => void }) {\n return (\n <div style={mainStyle}>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>\n <h1 style={{ margin: 0, fontSize: 22 }}>Extension Cases</h1>\n <button type=\"button\" style={{ ...buttonStyle, padding: '0 12px' }} onClick={onClose}>Close</button>\n </div>\n <p style={{ marginTop: 8, ...mutedStyle }}>Runnable examples for the stable Workbench extension contract.</p>\n <div style={{ display: 'grid', gap: 12, marginTop: 20, maxWidth: 720 }}>\n <BlockCard title=\"Sidebar contribution\">Register a sidebar view with ctx.capabilities.</BlockCard>\n <BlockCard title=\"Deep-linkable editor tab\">Open a view with a stable routeKey and serializable props.</BlockCard>\n <BlockCard title=\"Runtime API check\">Inspect tenant, workbench and actor context in a live extension.</BlockCard>\n </div>\n </div>\n );\n}\n\nfunction ComponentsTab(props: { title?: string; variant?: string }) {\n const [count, setCount] = useState(0);\n return (\n <div style={mainStyle}>\n <h1 style={{ margin: 0, fontSize: 20 }}>{props.title || 'UI Components'}</h1>\n <p style={{ marginTop: 8, ...mutedStyle }}>Interactive UI component example. variant = {props.variant || '-'}</p>\n <button type=\"button\" style={{ ...buttonStyle, marginTop: 16 }} onClick={() => setCount((value) => value + 1)}>Clicked {count} times</button>\n </div>\n );\n}\n\nfunction RegressionTab() {\n const [ran, setRan] = useState(false);\n const checks = [\n ['Plugin context', Boolean(kitContext?.plugin.id)],\n ['Runtime context', Boolean(kitContext?.runtime.workbenchId)],\n ['View API', typeof kitContext?.views.openEditor === 'function'],\n ['Link API', typeof kitContext?.links.create === 'function'],\n ] as const;\n return (\n <div style={mainStyle}>\n <h1 style={{ margin: 0, fontSize: 20 }}>Regression Checks</h1>\n <button type=\"button\" style={{ ...buttonStyle, marginTop: 16 }} onClick={() => setRan(true)}>Run checks</button>\n <div style={{ display: 'grid', gap: 8, marginTop: 16, maxWidth: 520 }}>\n {checks.map(([label, passed]) => <div key={label} style={{ ...cardStyle, display: 'flex', justifyContent: 'space-between' }}><span>{label}</span><strong>{ran && passed ? 'PASS' : ran ? 'FAIL' : 'NOT RUN'}</strong></div>)}\n </div>\n </div>\n );\n}\n`;\n return localizeGeneratedWorkbenchKitSource(source\n .replace(\"import React from 'react';\", \"import React, { useState } from 'react';\\nimport { WorkbenchDialog, WorkbenchDialogContent, WorkbenchDialogDescription, WorkbenchDialogFooter, WorkbenchDialogHeader, WorkbenchDialogTitle, WorkbenchDrawer, WorkbenchDrawerContent, WorkbenchDrawerDescription, WorkbenchDrawerFooter, WorkbenchDrawerHeader, WorkbenchDrawerTitle } from '@appthen/vibe-workspace/overlay';\\nimport { CodingButton, CodingInput, CodingListDetailWorkspace, CodingPanel } from '@appthen/vibe-workspace/coding-kit';\\nimport { WorkbenchSelect, WorkbenchSelectContent, WorkbenchSelectItem, WorkbenchSelectTrigger, WorkbenchSelectValue } from '@appthen/vibe-workspace/ui';\\nimport '@appthen/vibe-workspace/styles.css';\")\n .replace(\" overflow: 'auto',\\n padding: 16,\", \" overflow: 'auto',\\n fontSize: 13,\\n padding: 16,\")\n .replace(\" overflow: 'auto',\\n padding: 24,\", \" overflow: 'auto',\\n fontSize: 13,\\n padding: 24,\")\n .replace(\"const buttonStyle: React.CSSProperties = {\\n height: 32,\", \"const buttonStyle: React.CSSProperties = {\\n height: 32,\\n padding: '0 10px',\\n fontSize: 12,\\n fontWeight: 500,\\n lineHeight: 1.2,\\n fontFamily: 'inherit',\")\n .replace(\n \"const VIEW_API_REFERENCE = 'editor.acme.workbench-kit.api-reference';\",\n \"const VIEW_API_REFERENCE = 'editor.acme.workbench-kit.api-reference';\\nconst VIEW_CODING_TEMPLATE = 'editor.acme.workbench-kit.coding-template';\\nconst VIEW_THEME_GUIDE = 'main.acme.workbench-kit.theme-guide';\\nconst VIEW_CASES = 'main.acme.workbench-kit.cases';\\nconst VIEW_COMPONENTS = 'editor.acme.workbench-kit.components';\\nconst VIEW_REGRESSION = 'editor.acme.workbench-kit.regression';\\nconst VIEW_OVERLAY_GUIDE = 'main.acme.workbench-kit.overlay-guide';\",\n )\n .replace(\n \"const VIEW_OVERLAY_GUIDE = 'main.acme.workbench-kit.overlay-guide';\",\n \"const VIEW_OVERLAY_GUIDE = 'main.acme.workbench-kit.overlay-guide';\\nconst VIEW_RESPONSIVE_WORKSPACE = 'main.acme.workbench-kit.responsive-workspace';\",\n )\n .replaceAll('openMainViewById', 'openEditorViewById')\n .replaceAll('ctx.views.openMain(...)', 'ctx.views.openEditor(...)')\n .replaceAll('main.acme.workbench-kit.', 'editor.acme.workbench-kit.')\n .replace('let openMainView: () => void = () => undefined;', 'let openApiGalleryTab: () => void = () => undefined;')\n .replace('onClick={openMainView}', 'onClick={openApiGalleryTab}')\n .replace('onClick={() => openMainViewById(VIEW_THEME_GUIDE)}', \"onClick={() => openEditorViewById(VIEW_THEME_GUIDE, '工作台主题指南')}\")\n .replace('onClick={() => openMainViewById(VIEW_CASES)}', \"onClick={() => openEditorViewById(VIEW_CASES, '扩展案例')}\")\n .replace('onClick={() => openMainViewById(VIEW_OVERLAY_GUIDE)}', \"onClick={() => openEditorViewById(VIEW_OVERLAY_GUIDE, '弹窗与侧边抽屉规范')}\")\n .replace(\n \"let openEditorTab: OpenEditorTab = () => undefined;\",\n \"let openEditorTab: OpenEditorTab = () => undefined;\\nlet kitContext: PluginContext | null = null;\",\n )\n .replace('\\nfunction MainView', `${kitEnhancements}\\nfunction MainView`)\n .replace(\n ` </button>\\n </div>\\n </div>\\n );\\n}\\n\\nfunction openEditorViewById`,\n ` </button>\\n <button type=\"button\" style={buttonStyle} onClick={() => openMainViewById(VIEW_THEME_GUIDE)}>\\n Open Theme Guide\\n </button>\\n <button type=\"button\" style={buttonStyle} onClick={() => openMainViewById(VIEW_CASES)}>\\n Open Extension Cases\\n </button>\\n <button type=\"button\" style={buttonStyle} onClick={() => openEditorTab(VIEW_COMPONENTS, 'UI Components', { variant: 'interactive' })}>\\n Open UI Components Tab\\n </button>\\n <button type=\"button\" style={buttonStyle} onClick={() => openEditorTab(VIEW_REGRESSION, 'Regression Checks')}>\\n Run Regression Checks\\n </button>\\n </div>\\n </div>\\n );\\n}\\n\\nfunction openMainViewById`,\n )\n .replace(\n ` Open UI Components Tab\\n </button>`,\n ` Open UI Components Tab\\n </button>\\n <button type=\"button\" style={buttonStyle} onClick={() => openEditorTab(VIEW_CODING_TEMPLATE, 'Coding Collaboration Template')}>\\n Open Coding Collaboration Template\\n </button>`,\n )\n .replace(\n ` Open API Reference Tab\\n </button>`,\n ` Open API Reference Tab\\n </button>\\n <button type=\"button\" style={buttonStyle} onClick={() => openEditorViewById(VIEW_THEME_GUIDE, 'Workbench Theme Guide')}>\\n Open Theme Guide\\n </button>\\n <button type=\"button\" style={buttonStyle} onClick={() => openEditorViewById(VIEW_CASES, 'Extension Cases')}>\\n Open Extension Cases\\n </button>\\n <button type=\"button\" style={buttonStyle} onClick={() => openEditorViewById(VIEW_OVERLAY_GUIDE, '弹窗与侧边抽屉规范')}>\\n 打开弹窗与抽屉规范\\n </button>\\n <button type=\"button\" style={buttonStyle} onClick={() => openEditorViewById(VIEW_RESPONSIVE_WORKSPACE, '多栏工作区与移动端折叠规范')}>\\n 打开多栏工作区规范\\n </button>`,\n )\n .replace(\n ` Open Extension Cases\\n </button>`,\n ` Open Extension Cases\\n </button>\\n <button type=\"button\" style={buttonStyle} onClick={() => openMainViewById(VIEW_OVERLAY_GUIDE)}>\\n 打开弹窗与抽屉规范\\n </button>`,\n )\n .replace(\n ` 打开弹窗与抽屉规范\n </button>`,\n ` 打开弹窗与抽屉规范\n </button>\n <button type=\"button\" style={buttonStyle} onClick={() => openMainViewById(VIEW_RESPONSIVE_WORKSPACE)}>\n 打开多栏工作区规范\n </button>`,\n )\n .replace(\n 'export function activate(ctx: PluginContext) {',\n 'export function activate(ctx: PluginContext) {\\n kitContext = ctx;',\n )\n .replace(\n \" ctx.capabilities.registerFrontendToolHandler({\",\n \" ctx.capabilities.registerEditorView({ id: VIEW_THEME_GUIDE, routeKey: 'theme-guide', title: 'Workbench Theme Guide', component: ThemeGuideView }),\\n ctx.capabilities.registerEditorView({ id: VIEW_CASES, routeKey: 'cases', title: 'Extension Cases', component: CasesView }),\\n ctx.capabilities.registerEditorView({ id: VIEW_OVERLAY_GUIDE, routeKey: 'overlay-guide', title: '弹窗与侧边抽屉规范', component: OverlayGuideView }),\\n ctx.capabilities.registerEditorView({ id: VIEW_RESPONSIVE_WORKSPACE, routeKey: 'responsive-workspace', title: '多栏工作区与移动端折叠规范', component: ResponsiveWorkspaceGuide }),\\n ctx.capabilities.registerEditorView({ id: VIEW_COMPONENTS, routeKey: 'components', title: 'UI Components', component: ComponentsTab }),\\n ctx.capabilities.registerEditorView({ id: VIEW_CODING_TEMPLATE, routeKey: 'coding-template', title: 'Coding Collaboration Template', component: CodingTemplateView }),\\n ctx.capabilities.registerEditorView({ id: VIEW_REGRESSION, routeKey: 'regression', title: 'Regression Checks', component: RegressionTab }),\\n ctx.capabilities.registerFrontendToolHandler({\",\n )\n .replaceAll('ctx.capabilities.registerMainView({', 'ctx.capabilities.registerEditorView({')\n .replaceAll('ctx.capabilities.registerMainView(...)', 'ctx.capabilities.registerEditorView(...)')\n .replaceAll(' showInTabs: true,\\n closable: true,\\n', '')\n .replaceAll('openMainViewById', 'openEditorViewById')\n .replaceAll(\"openEditorViewById(VIEW_THEME_GUIDE)\", \"openEditorViewById(VIEW_THEME_GUIDE, '工作台主题指南')\")\n .replaceAll(\"openEditorViewById(VIEW_CASES)\", \"openEditorViewById(VIEW_CASES, '扩展案例')\")\n .replaceAll(\"openEditorViewById(VIEW_OVERLAY_GUIDE)\", \"openEditorViewById(VIEW_OVERLAY_GUIDE, '弹窗与侧边抽屉规范')\")\n .replace(\n \" id: VIEW_API_GALLERY,\\n title: 'Extension API Gallery',\",\n \" id: VIEW_API_GALLERY,\\n routeKey: 'api-gallery',\\n title: 'Extension API Gallery',\",\n )\n .replace(\n \" id: VIEW_COMPONENT_PREVIEW,\\n title: 'Component Preview',\",\n \" id: VIEW_COMPONENT_PREVIEW,\\n routeKey: 'component-preview',\\n title: 'Component Preview',\",\n )\n .replace(\n \" id: VIEW_API_REFERENCE,\\n title: 'API Reference',\",\n \" id: VIEW_API_REFERENCE,\\n routeKey: 'api-reference',\\n title: 'API Reference',\",\n )\n .replace(\n 'ctx.capabilities.registerSidebarView(...)',\n 'import { WorkbenchDialog, WorkbenchDrawer } from \\'@appthen/vibe-workspace/overlay\\';\\n\\nctx.views.openEditor(...)\\nctx.links.create(...)\\n\\nctx.capabilities.registerSidebarView(...)',\n )\n .replace(\n / const workspaceEditorService = ctx\\.services\\?\\.workspaceEditorService;\\n\\n openMainView[\\s\\S]*? \\};\\n\\n const disposers = \\[/,\n ` openApiGalleryTab = () => {\\n ctx.views.openEditor({ viewId: VIEW_API_GALLERY, title: '扩展 API 示例', props: { title: '扩展 API 示例' }, key: VIEW_API_GALLERY });\\n };\\n\\n openEditorTab = (viewId, title, props = {}) => {\\n ctx.views.openEditor({ viewId, title, props: { ...props, title }, key: title });\\n };\\n\\n const disposers = [`,\n )\n .replace('workspaceEditorService.createViewFile()', 'ctx.views.openEditor()'));\n}\n\nfunction createSidebarBasicExtension(extensionId: string): {\n manifest: ExtensionPackageManifest;\n source: string;\n} {\n return {\n manifest: {\n id: extensionId,\n name: 'Sidebar Basic',\n version: '0.1.0',\n icon: EXAMPLE_EXTENSION_ICONS.sidebar,\n main: './src/index.tsx',\n sourceType: 'umd',\n runtime: {\n sidebarViewId: `sidebar.${extensionId}`,\n autoActivate: true,\n },\n mcp: {\n enabled: true,\n uiResources: [],\n frontendTools: [],\n },\n },\n source: `import React from 'react';\\nimport type { PluginContext } from '@appthen/vibe-workspace/plugins/base';\\n\\nfunction SidebarBasic() {\\n return (\\n <div style={{ padding: 16, fontFamily: 'system-ui, sans-serif' }}>\\n <h2 style={{ margin: 0, fontSize: 16 }}>Sidebar Basic</h2>\\n <p style={{ color: '#6b7280', lineHeight: 1.6 }}>\\n This extension contributes a Workbench sidebar view from a local folder.\\n </p>\\n </div>\\n );\\n}\\n\\nexport function activate(ctx: PluginContext) {\\n return ctx.capabilities.registerSidebarView({\\n id: 'sidebar.${extensionId}',\\n title: 'Sidebar Basic',\\n component: SidebarBasic,\\n });\\n}\\n`,\n };\n}\n\nfunction createRemoteHtmlSandboxExtension(extensionId: string): {\n manifest: ExtensionPackageManifest;\n source: string;\n} {\n return {\n manifest: {\n id: extensionId,\n name: 'Remote HTML Sandbox',\n version: '0.1.0',\n icon: EXAMPLE_EXTENSION_ICONS.sandbox,\n main: './src/index.tsx',\n sourceType: 'umd',\n runtime: {\n sidebarViewId: `sidebar.${extensionId}`,\n autoActivate: true,\n },\n mcp: {\n enabled: true,\n uiResources: [],\n frontendTools: [],\n },\n },\n source: `import React, { useEffect, useMemo, useState } from 'react';\nimport type { PluginContext } from '@appthen/vibe-workspace/plugins/base';\n\nconst sandboxDocument = [\n '<!doctype html><html><body style=\"font:14px system-ui;padding:16px\">',\n '<strong>Sandboxed remote HTML</strong>',\n '<p id=\"status\">Waiting for host message...</p>',\n '<script>window.parent.postMessage({ type: \"sandbox-ready\" }, \"*\"); window.addEventListener(\"message\", function (event) { var status = document.getElementById(\"status\"); if (status) status.textContent = \"Received: \" + JSON.stringify(event.data); });</script>',\n '</body></html>',\n].join('');\n\nfunction SandboxSidebar() {\n const [message, setMessage] = useState('');\n const frameId = useMemo(() => 'sandbox-frame-' + Math.random().toString(36).slice(2), []);\n\n useEffect(() => {\n const onMessage = (event: MessageEvent) => {\n if (event.data?.type === 'sandbox-ready') setMessage('The iframe sent a message to the host.');\n };\n window.addEventListener('message', onMessage);\n return () => window.removeEventListener('message', onMessage);\n }, []);\n\n return (\n <div style={{ height: '100%', padding: 16, color: 'var(--vscode-editor-foreground)', fontFamily: 'system-ui, sans-serif' }}>\n <h2 style={{ margin: 0, fontSize: 16 }}>Remote HTML Sandbox</h2>\n <p style={{ color: 'var(--vscode-input-placeholderForeground)', lineHeight: 1.5 }}>\n This iframe runs scripts but has no same-origin access.\n </p>\n <iframe\n id={frameId}\n title=\"Remote HTML Sandbox\"\n srcDoc={sandboxDocument}\n sandbox=\"allow-scripts\"\n csp=\"default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'\"\n referrerPolicy=\"no-referrer\"\n style={{ width: '100%', minHeight: 160, border: '1px solid var(--vscode-panel-border)' }}\n />\n <div style={{ marginTop: 8, fontSize: 12, color: 'var(--vscode-input-placeholderForeground)' }}>{message || 'Loading iframe...'}</div>\n </div>\n );\n}\n\nexport function activate(ctx: PluginContext) {\n return ctx.capabilities.registerSidebarView({\n id: 'sidebar.${extensionId}',\n title: 'Remote HTML Sandbox',\n component: SandboxSidebar,\n });\n}\n`,\n };\n}\n\nfunction createFrontendToolBasicExtension(extensionId: string): {\n manifest: ExtensionPackageManifest;\n source: string;\n} {\n return {\n manifest: {\n id: extensionId,\n name: 'Frontend Tool Basic',\n version: '0.1.0',\n icon: EXAMPLE_EXTENSION_ICONS.tool,\n main: './src/index.tsx',\n sourceType: 'umd',\n runtime: {\n sidebarViewId: `sidebar.${extensionId}`,\n autoActivate: true,\n },\n mcp: {\n enabled: true,\n uiResources: [],\n frontendTools: [\n {\n name: 'demo.echo',\n description: 'Echo an input payload from the local extension.',\n inputSchema: {\n type: 'object',\n properties: {\n message: { type: 'string' },\n },\n },\n handlerRef: 'echo',\n },\n ],\n },\n },\n source: `import React from 'react';\\nimport type { PluginContext } from '@appthen/vibe-workspace/plugins/base';\\n\\nfunction FrontendToolBasic() {\\n return (\\n <div style={{ padding: 16, fontFamily: 'system-ui, sans-serif' }}>\\n <h2 style={{ margin: 0, fontSize: 16 }}>Frontend Tool Basic</h2>\\n <p style={{ color: '#6b7280', lineHeight: 1.6 }}>\\n This extension declares demo.echo in manifest and binds it to a local handler.\\n </p>\\n </div>\\n );\\n}\\n\\nexport function activate(ctx: PluginContext) {\\n const disposeSidebar = ctx.capabilities.registerSidebarView({\\n id: 'sidebar.${extensionId}',\\n title: 'Frontend Tool Basic',\\n component: FrontendToolBasic,\\n });\\n\\n const disposeHandler = ctx.capabilities.registerFrontendToolHandler({\\n ref: 'echo',\\n source: 'manifest:${extensionId}',\\n handler: async (input) => ({\\n ok: true,\\n input,\\n handledAt: new Date().toISOString(),\\n }),\\n });\\n\\n return () => {\\n disposeHandler();\\n disposeSidebar();\\n };\\n}\\n`,\n };\n}\n\nfunction createMultiViewBasicExtension(extensionId: string): {\n manifest: ExtensionPackageManifest;\n source: string;\n} {\n return {\n manifest: {\n id: extensionId,\n name: 'Multi View Basic',\n version: '0.1.0',\n icon: EXAMPLE_EXTENSION_ICONS.multi,\n main: './src/index.tsx',\n sourceType: 'umd',\n runtime: {\n sidebarViewId: `sidebar.${extensionId}`,\n autoActivate: true,\n },\n mcp: {\n enabled: true,\n uiResources: [],\n frontendTools: [],\n },\n },\n source: `import React from 'react';\\nimport type { PluginContext } from '@appthen/vibe-workspace/plugins/base';\\n\\nfunction Sidebar() {\\n return <div style={{ padding: 16 }}>Open the main view from the command palette or extension API.</div>;\\n}\\n\\nfunction MainView() {\\n return (\\n <div style={{ padding: 24, fontFamily: 'system-ui, sans-serif' }}>\\n <h1 style={{ marginTop: 0 }}>Multi View Basic</h1>\\n <p>This extension contributes both a sidebar and a main view.</p>\\n </div>\\n );\\n}\\n\\nexport function activate(ctx: PluginContext) {\\n const disposeSidebar = ctx.capabilities.registerSidebarView({\\n id: 'sidebar.${extensionId}',\\n title: 'Multi View Basic',\\n component: Sidebar,\\n });\\n const disposeMain = ctx.capabilities.registerMainView({\\n id: 'main.${extensionId}',\\n title: 'Multi View Basic',\\n component: MainView,\\n showInTabs: true,\\n closable: true,\\n });\\n\\n return () => {\\n disposeMain();\\n disposeSidebar();\\n };\\n}\\n`,\n };\n}\n\nfunction normalizeEditorOnlyExtensionSource(source: string) {\n return source\n .replaceAll('registerMainView', 'registerEditorView')\n .replaceAll(\"'main.${extensionId}'\", \"'editor.${extensionId}'\")\n .replaceAll(',\\n showInTabs: true,\\n closable: true', '')\n .replaceAll('main view', 'editor tab');\n}\n\nexport function createExtensionWorkspace(\n root: string,\n extensionId = 'acme.example',\n template: ExtensionWorkspaceTemplate = 'basic',\n) {\n const workspaceRoot = path.resolve(root);\n const sampleExtensionIds = template === 'full'\n ? [\n 'acme.workbench-kit',\n 'acme.sidebar-basic',\n 'acme.remote-html-sandbox',\n 'acme.frontend-tool-basic',\n 'acme.multi-view-basic',\n ]\n : [extensionId];\n const config = normalizeWorkspaceConfig({\n devWorkbench: {\n enabledExtensionIds: sampleExtensionIds,\n },\n });\n\n writeJsonFile(path.join(workspaceRoot, EXTENSION_WORKSPACE_CONFIG), config);\n writeFileSync(path.join(workspaceRoot, 'README.md'), GENERATED_WORKSPACE_README, 'utf8');\n writeFileSync(path.join(workspaceRoot, 'AGENTS.md'), GENERATED_WORKSPACE_AGENTS, 'utf8');\n writeJsonFile(path.join(workspaceRoot, 'themes', 'acme-sales.json'), WORKBENCH_THEME_EXAMPLE);\n writeJsonFile(path.join(workspaceRoot, 'package.json'), {\n name: 'appthen-extension-workspace',\n private: true,\n type: 'module',\n scripts: {\n dev: 'appthen-extension dev',\n doctor: 'appthen-extension doctor',\n test: 'appthen-extension test',\n validate: 'appthen-extension validate',\n build: 'appthen-extension build',\n pack: 'appthen-extension pack',\n publish: 'appthen-extension publish',\n },\n dependencies: {\n '@appthen/vibe-workspace': '^0.1.0',\n '@vitejs/plugin-react': '^5.0.0',\n vite: '^6.2.0',\n typescript: '~5.8.2',\n react: '^18.2.0',\n 'react-dom': '^18.2.0',\n },\n });\n\n const samples = template === 'full'\n ? [\n ['acme.workbench-kit', createWorkbenchKitExampleExtension('acme.workbench-kit')],\n ['acme.sidebar-basic', createSidebarBasicExtension('acme.sidebar-basic')],\n ['acme.remote-html-sandbox', createRemoteHtmlSandboxExtension('acme.remote-html-sandbox')],\n ['acme.frontend-tool-basic', createFrontendToolBasicExtension('acme.frontend-tool-basic')],\n ['acme.multi-view-basic', createMultiViewBasicExtension('acme.multi-view-basic')],\n ] as const\n : [[extensionId, createWorkbenchKitExampleExtension(extensionId)]] as const;\n\n samples.forEach(([id, sample]) => {\n writeExtensionFiles(\n workspaceRoot,\n config.extensionsDir,\n id,\n sample.manifest,\n id === 'acme.workbench-kit' || id === extensionId\n ? normalizeGeneratedWorkbenchKitSource(sample.source)\n : id === 'acme.multi-view-basic'\n ? normalizeEditorOnlyExtensionSource(sample.source)\n : sample.source,\n );\n });\n}\n","import { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport path from 'node:path';\nimport {\n discoverExtensionWorkspace,\n loadWorkspaceThemeCatalog,\n loadExtensionWorkspaceConfig,\n writeExtensionTailwindEntry,\n} from './workspace';\n\nexport interface ExtensionDevWorkbenchFilesResult {\n devRoot: string;\n count: number;\n port: string;\n}\n\nexport interface ExtensionDevWorkbenchFilesOptions {\n packageRoot?: string;\n}\n\nfunction toRelativeImport(fromDir: string, targetPath: string) {\n const relativePath = path.relative(fromDir, targetPath).split(path.sep).join('/');\n return relativePath.startsWith('.') ? relativePath : `./${relativePath}`;\n}\n\nexport function writeExtensionDevWorkbenchFiles(\n workspaceRoot: string,\n port = '5177',\n options: ExtensionDevWorkbenchFilesOptions = {},\n): ExtensionDevWorkbenchFilesResult {\n const config = {\n ...loadExtensionWorkspaceConfig(workspaceRoot),\n themeCatalog: loadWorkspaceThemeCatalog(workspaceRoot),\n };\n const entries = discoverExtensionWorkspace(workspaceRoot);\n const devRoot = path.join(workspaceRoot, '.appthen', 'dev-workbench');\n const packageRoot = options.packageRoot || path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');\n const tailwindEntry = writeExtensionTailwindEntry(workspaceRoot, packageRoot);\n mkdirSync(devRoot, { recursive: true });\n\n const imports = entries.map((entry, index) => {\n const sourcePath = path.join(entry.dir, entry.manifest.main || './src/index.tsx');\n return `import * as extension${index} from '${toRelativeImport(path.join(devRoot, 'src'), sourcePath)}';`;\n });\n const modules = entries.map((entry, index) =>\n ` { manifest: ${JSON.stringify(entry.manifest)}, module: extension${index} }`,\n );\n\n writeFileSync(\n path.join(devRoot, 'index.html'),\n '<!doctype html><html><head><meta charset=\"utf-8\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, viewport-fit=cover, interactive-widget=resizes-content\" /><title>AppThen Extension Dev</title></head><body><div id=\"root\"></div><script type=\"module\" src=\"/src/main.tsx\"></script></body></html>\\n',\n 'utf8',\n );\n mkdirSync(path.join(devRoot, 'src'), { recursive: true });\n writeFileSync(\n path.join(devRoot, 'src', 'main.tsx'),\n `${imports.join('\\n')}\\nimport ${JSON.stringify(toRelativeImport(path.join(devRoot, 'src'), tailwindEntry))};\\nimport React from 'react';\\nimport { createRoot } from 'react-dom/client';\\nimport { ExtensionDevWorkbench } from '@appthen/vibe-workspace/extension-dev-workbench';\\nimport '@appthen/vibe-workspace/styles.css';\\n\\ncreateRoot(document.getElementById('root')!).render(\\n <ExtensionDevWorkbench\\n workspace={${JSON.stringify(config)}}\\n extensions={[\\n${modules.join(',\\n')}\\n ]}\\n />,\\n);\\n`,\n 'utf8',\n );\n writeFileSync(\n path.join(devRoot, 'vite.config.ts'),\n createViteConfigSource(workspaceRoot, packageRoot),\n 'utf8',\n );\n\n if (!existsSync(path.join(workspaceRoot, 'node_modules'))) {\n writeFileSync(\n path.join(devRoot, 'README.md'),\n 'Run npm install or pnpm install in the extension workspace root before starting dev.\\n',\n 'utf8',\n );\n }\n\n return { devRoot, count: entries.length, port };\n}\n\nfunction createViteConfigSource(workspaceRoot: string, packageRoot?: string) {\n const packageAliases = packageRoot\n ? [\n {\n find: '@appthen/vibe-workspace/extension-dev-workbench',\n replacement: path.join(packageRoot, 'dist', 'extension-dev-workbench', 'index.js'),\n },\n {\n find: '@appthen/vibe-workspace/plugins/base',\n replacement: path.join(packageRoot, 'dist', 'plugins', 'base', 'index.js'),\n },\n {\n find: '@appthen/vibe-workspace/overlay',\n replacement: path.join(packageRoot, 'dist', 'overlay', 'index.js'),\n },\n {\n find: '@appthen/vibe-workspace/coding-kit',\n replacement: path.join(packageRoot, 'dist', 'coding-kit', 'index.js'),\n },\n {\n find: '@appthen/vibe-workspace/ui',\n replacement: path.join(packageRoot, 'dist', 'ui', 'index.js'),\n },\n {\n find: '@appthen/vibe-workspace/components',\n replacement: path.join(packageRoot, 'dist', 'components', 'index.js'),\n },\n {\n find: '@appthen/vibe-workspace/canvas-core',\n replacement: path.join(packageRoot, 'dist', 'canvas-core', 'index.js'),\n },\n {\n find: '@appthen/vibe-workspace/styles.css',\n replacement: path.join(packageRoot, 'dist', 'vibe-workspace.css'),\n },\n {\n find: '@appthen/vibe-workspace',\n replacement: path.join(packageRoot, 'dist', 'index.js'),\n },\n ]\n : [];\n const aliasEntries = packageAliases\n .map((entry) =>\n ` { find: ${JSON.stringify(entry.find)}, replacement: ${JSON.stringify(entry.replacement)} }`,\n )\n .join(',\\n');\n\n return `import { defineConfig } from 'vite';\\nimport react from '@vitejs/plugin-react';\\n\\nexport default defineConfig({\\n css: {\\n postcss: ${JSON.stringify(path.join(packageRoot || workspaceRoot, 'postcss.config.js'))},\\n },\\n plugins: [react()],\\n server: {\\n fs: {\\n allow: [${JSON.stringify(workspaceRoot)}${packageRoot ? `, ${JSON.stringify(packageRoot)}` : ''}],\\n },\\n },\\n resolve: {\\n alias: [\\n${aliasEntries}\\n ],\\n dedupe: ['react', 'react-dom'],\\n },\\n});\\n`;\n}\n"],"names":[],"mappings":"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"}