@appthen/vibe-workspace 0.1.0 → 0.1.1

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.
@@ -8,10 +8,12 @@ const EXTENSION_PACKAGE_EXTENSION = ".appthen-extension.json";
8
8
  const EXTENSION_BUNDLE_ENTRY = "entry.js";
9
9
  const DEFAULT_WORKSPACE_CONFIG = {
10
10
  extensionsDir: "extensions",
11
+ themeCatalog: [],
11
12
  devWorkbench: {
12
13
  tenantId: "local-tenant",
13
14
  workbenchId: "local-extension-dev",
14
15
  name: "Local Extension Dev",
16
+ theme: "acme.sales",
15
17
  enabledExtensionIds: []
16
18
  },
17
19
  actor: {
@@ -64,6 +66,8 @@ pnpm dev
64
66
 
65
67
  The 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.
66
68
 
69
+ When 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.
70
+
67
71
  ## Verify And Package
68
72
 
69
73
  \`\`\`bash
@@ -122,6 +126,7 @@ You are working in an AppThen extension workspace. Keep changes inside this work
122
126
  ## Stable Extension Contract
123
127
 
124
128
  - Manifest: \`manifestVersion: 1\`, \`apiVersion: "1"\`, \`sourceType: "umd"\`.
129
+ - Icon: put a small \`data:image/svg+xml\` or HTTPS URL in \`manifest.icon\`; relative static asset paths are not part of v1.
125
130
  - Lifecycle: export \`activate(ctx)\`; return a disposer for every registration and subscription.
126
131
  - Sidebar: \`ctx.capabilities.registerSidebarView\`.
127
132
  - Main content: \`ctx.capabilities.registerEditorView\` plus \`ctx.views.openEditor\`.
@@ -159,6 +164,7 @@ function normalizeWorkspaceConfig(config) {
159
164
  var _a;
160
165
  return {
161
166
  extensionsDir: (config == null ? void 0 : config.extensionsDir) || DEFAULT_WORKSPACE_CONFIG.extensionsDir,
167
+ themeCatalog: (config == null ? void 0 : config.themeCatalog) || DEFAULT_WORKSPACE_CONFIG.themeCatalog,
162
168
  devWorkbench: {
163
169
  ...DEFAULT_WORKSPACE_CONFIG.devWorkbench,
164
170
  ...(config == null ? void 0 : config.devWorkbench) || {},
@@ -170,6 +176,17 @@ function normalizeWorkspaceConfig(config) {
170
176
  }
171
177
  };
172
178
  }
179
+ function loadWorkspaceThemeCatalog(root) {
180
+ const themesRoot = path.join(root, "themes");
181
+ if (!existsSync(themesRoot)) return [];
182
+ return readdirSync(themesRoot).filter((name) => name.endsWith(".json")).map((name) => {
183
+ try {
184
+ return readJsonFile(path.join(themesRoot, name));
185
+ } catch {
186
+ return null;
187
+ }
188
+ }).filter((theme) => Boolean((theme == null ? void 0 : theme.id) && (theme == null ? void 0 : theme.label) && (theme == null ? void 0 : theme.colors)));
189
+ }
173
190
  function findExtensionWorkspaceRoot(startDir = process.cwd()) {
174
191
  let current = path.resolve(startDir);
175
192
  while (true) {
@@ -484,6 +501,7 @@ function createWorkbenchKitExampleExtension(extensionId) {
484
501
  id: extensionId,
485
502
  name: "工作台工具包示例",
486
503
  version: "0.1.0",
504
+ icon: 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"%3E%3Crect width="32" height="32" rx="7" fill="%232f9e8f"/%3E%3Cpath d="M8 9h16v4H8zm0 6h10v4H8zm0 6h16v4H8z" fill="white"/%3E%3C/svg%3E',
487
505
  main: "./src/index.tsx",
488
506
  sourceType: "umd",
489
507
  runtime: {
@@ -766,7 +784,7 @@ function localizeGeneratedWorkbenchKitSource(source) {
766
784
  ["['Sidebar',", "['侧边栏',"],
767
785
  ["Accent", "强调色"],
768
786
  ["['Portal',", "['门户',"],
769
- ["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。本示例用于说明契约和 token 继承;全局自定义主题注册将在后续运行时能力中提供。"],
787
+ ["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 字段设为默认主题。"],
770
788
  ["This React component was opened as a normal editor tab through workspaceEditorService.createViewFile().", "这个 React 组件通过 ctx.views.openEditor() 作为普通编辑器页签打开。"],
771
789
  ["Use this pattern for tenant-specific components before promoting them to the shared package.", "租户专属组件可以先采用这种模式,成熟后再提升到共享 UI 包。"],
772
790
  ["Props", "属性"],
@@ -924,7 +942,7 @@ function ThemeGuideView({ onClose }: { onClose?: () => void }) {
924
942
  {JSON.stringify(themeExample, null, 2)}
925
943
  </pre>
926
944
  <p style={{ marginTop: 12, ...mutedStyle }}>
927
- Suggested local file: themes/acme-sales.json. This documents the contract and token inheritance; global custom theme registration is the next runtime capability.
945
+ Suggested local file: themes/acme-sales.json. The offline Workbench loads it automatically; set devWorkbench.theme to acme.sales to make it the default.
928
946
  </p>
929
947
  </div>
930
948
  );
@@ -1363,7 +1381,10 @@ function toRelativeImport(fromDir, targetPath) {
1363
1381
  return relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
1364
1382
  }
1365
1383
  function writeExtensionDevWorkbenchFiles(workspaceRoot, port = "5177", options = {}) {
1366
- const config = loadExtensionWorkspaceConfig(workspaceRoot);
1384
+ const config = {
1385
+ ...loadExtensionWorkspaceConfig(workspaceRoot),
1386
+ themeCatalog: loadWorkspaceThemeCatalog(workspaceRoot)
1387
+ };
1367
1388
  const entries = discoverExtensionWorkspace(workspaceRoot);
1368
1389
  const devRoot = path.join(workspaceRoot, ".appthen", "dev-workbench");
1369
1390
  mkdirSync(devRoot, { recursive: true });
@@ -1471,4 +1492,4 @@ export {
1471
1492
  validateExtensionPackageManifest as v,
1472
1493
  writeExtensionDevWorkbenchFiles as w
1473
1494
  };
1474
- //# sourceMappingURL=devWorkbench-BmYheR6S.js.map
1495
+ //# sourceMappingURL=devWorkbench-C-rC8sz8.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devWorkbench-C-rC8sz8.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 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\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- 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- \\`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}) {\n return `import { defineConfig } from 'vite';\\n\\nexport default defineConfig({\\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 dedupe: ['react', 'react-dom'],\\n },\\n});\\n`;\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 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: sourceEntry,\n outDir: buildRoot,\n globalName,\n }),\n 'utf8',\n );\n\n const command = resolveViteCommand(workspaceRoot, packageRoot);\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 }\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\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: 'data:image/svg+xml,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\"%3E%3Crect width=\"32\" height=\"32\" rx=\"7\" fill=\"%232f9e8f\"/%3E%3Cpath d=\"M8 9h16v4H8zm0 6h10v4H8zm0 6h16v4H8z\" fill=\"white\"/%3E%3C/svg%3E',\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 ['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 = `\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\" className=\"inset-x-0 bottom-0 top-auto flex h-auto max-h-[90dvh] w-full flex-col gap-0 overflow-hidden rounded-t-lg border-l-0 border-t p-0 sm:inset-x-auto sm:inset-y-0 sm:right-0 sm:top-0 sm:bottom-auto sm:h-full sm:max-h-none sm:w-[min(480px,calc(100vw-16px))] sm:rounded-none sm:border-l sm:border-t-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';\")\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_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 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_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 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 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 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 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 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 path from 'node:path';\nimport {\n discoverExtensionWorkspace,\n loadWorkspaceThemeCatalog,\n loadExtensionWorkspaceConfig,\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 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 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, options.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/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 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":";;;;;AAqBO,MAAM,6BAA6B;AACnC,MAAM,8BAA8B;AACpC,MAAM,yBAAyB;AAEtC,MAAM,2BAAkE;AAAA,EACtE,eAAe;AAAA,EACf,cAAc,CAAA;AAAA,EACd,cAAc;AAAA,IACZ,UAAU;AAAA,IACV,aAAa;AAAA,IACb,MAAM;AAAA,IACN,OAAO;AAAA,IACP,qBAAqB,CAAA;AAAA,EAAC;AAAA,EAExB,OAAO;AAAA,IACL,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,QAAQ;AAAA,IACR,MAAM;AAAA,EAAA;AAEV;AAEA,MAAM,0BAA0B;AAAA,EAC9B,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,MAAM;AAAA,EACN,SAAS;AAAA,EACT,QAAQ;AAAA,IACN,wBAAwB;AAAA,IACxB,qBAAqB;AAAA,IACrB,qBAAqB;AAAA,IACrB,sBAAsB;AAAA,IACtB,0BAA0B;AAAA,IAC1B,qBAAqB;AAAA,IACrB,oBAAoB;AAAA,IACpB,gBAAgB;AAAA,EAAA;AAAA,EAElB,cAAc;AAAA,IACZ,SAAS;AAAA,IACT,iBAAiB;AAAA,IACjB,MAAM;AAAA,EAAA;AAAA,EAER,QAAQ;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,MACN,qBAAqB;AAAA,MACrB,qBAAqB;AAAA,IAAA;AAAA,IAEvB,OAAO,CAAA;AAAA,EAAC;AAEZ;AAEA,MAAM,6BAA6B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4DnC,MAAM,6BAA6B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0CnC,SAAS,aAAgB,UAAqB;AAC5C,SAAO,KAAK,MAAM,aAAa,UAAU,MAAM,CAAC;AAClD;AAEA,SAAS,cAAc,UAAkB,OAAgB;AACvD,YAAU,KAAK,QAAQ,QAAQ,GAAG,EAAE,WAAW,MAAM;AACrD,gBAAc,UAAU,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAAA,GAAM,MAAM;AACvE;AAEA,SAAS,yBAAyB,QAA6E;;AAC7G,SAAO;AAAA,IACL,gBAAe,iCAAQ,kBAAiB,yBAAyB;AAAA,IACjE,eAAc,iCAAQ,iBAAgB,yBAAyB;AAAA,IAC/D,cAAc;AAAA,MACZ,GAAG,yBAAyB;AAAA,MAC5B,IAAI,iCAAQ,iBAAgB,CAAA;AAAA,MAC5B,uBAAqB,sCAAQ,iBAAR,mBAAsB,wBAAuB,CAAA;AAAA,IAAC;AAAA,IAErE,OAAO;AAAA,MACL,GAAG,yBAAyB;AAAA,MAC5B,IAAI,iCAAQ,UAAS,CAAA;AAAA,IAAC;AAAA,EACxB;AAEJ;AAEO,SAAS,0BAA0B,MAAwB;AAChE,QAAM,aAAa,KAAK,KAAK,MAAM,QAAQ;AAC3C,MAAI,CAAC,WAAW,UAAU,UAAU,CAAA;AAEpC,SAAO,YAAY,UAAU,EAC1B,OAAO,CAAC,SAAS,KAAK,SAAS,OAAO,CAAC,EACvC,IAAI,CAAC,SAAS;AACb,QAAI;AACF,aAAO,aAAqB,KAAK,KAAK,YAAY,IAAI,CAAC;AAAA,IACzD,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF,CAAC,EACA,OAAO,CAAC,UAA2B,SAAQ,+BAAO,QAAM,+BAAO,WAAS,+BAAO,OAAM,CAAC;AAC3F;AAEO,SAAS,2BAA2B,WAAW,QAAQ,OAAsB;AAClF,MAAI,UAAU,KAAK,QAAQ,QAAQ;AACnC,SAAO,MAAM;AACX,QAAI,WAAW,KAAK,KAAK,SAAS,0BAA0B,CAAC,GAAG;AAC9D,aAAO;AAAA,IACT;AACA,UAAM,SAAS,KAAK,QAAQ,OAAO;AACnC,QAAI,WAAW,QAAS,QAAO;AAC/B,cAAU;AAAA,EACZ;AACF;AAEO,SAAS,6BAA6B,MAAqD;AAChG,QAAM,aAAa,KAAK,KAAK,MAAM,0BAA0B;AAC7D,MAAI,CAAC,WAAW,UAAU,GAAG;AAC3B,WAAO,yBAAA;AAAA,EACT;AACA,SAAO,yBAAyB,aAA0C,UAAU,CAAC;AACvF;AAEO,SAAS,2BAA2B,OAAO,QAAQ,OAAkC;AAC1F,QAAM,gBAAgB,2BAA2B,IAAI,KAAK,KAAK,QAAQ,IAAI;AAC3E,QAAM,SAAS,6BAA6B,aAAa;AACzD,QAAM,iBAAiB,KAAK,QAAQ,eAAe,OAAO,aAAa;AACvE,MAAI,CAAC,WAAW,cAAc,GAAG;AAC/B,WAAO,CAAA;AAAA,EACT;AAEA,SAAO,YAAY,cAAc,EAC9B,IAAI,CAAC,SAAS,KAAK,KAAK,gBAAgB,IAAI,CAAC,EAC7C,OAAO,CAAC,QAAQ,SAAS,GAAG,EAAE,aAAa,EAC3C,IAAI,CAAC,QAAQ;AACZ,UAAM,eAAe,KAAK,KAAK,KAAK,eAAe;AACnD,QAAI,CAAC,WAAW,YAAY,EAAG,QAAO;AACtC,UAAM,WAAW,aAAuC,YAAY;AACpE,WAAO;AAAA,MACL,IAAI,SAAS,SAAS,SAAS;AAAA,MAC/B;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ,CAAC,EACA,OAAO,CAAC,UAA4C,QAAQ,KAAK,CAAC;AACvE;AAEO,SAAS,iCACd,UAC2B;;AAC3B,QAAM,OAAO,iBAAiB,QAAQ;AACtC,QAAM,SAAS,CAAC,GAAG,KAAK,MAAM;AAC9B,QAAM,WAAqB,CAAA;AAE3B,MAAI,SAAS,SAAS,SAAS,UAAU,SAAS,IAAI;AACpD,aAAS,KAAK,+DAA+D;AAAA,EAC/E;AACA,MAAI,SAAS,oBAAoB,QAAW;AAC1C,aAAS,KAAK,+FAA+F;AAAA,EAC/G;AACA,MAAI,SAAS,eAAe,QAAW;AACrC,aAAS,KAAK,sFAAsF;AAAA,EACtG;AACA,MAAI,CAAC,SAAS,YAAY;AACxB,aAAS,KAAK,oEAAoE;AAAA,EACpF;AACA,MAAI,GAAC,cAAS,YAAT,mBAAkB,kBAAiB,GAAC,oBAAS,YAAT,mBAAkB,oBAAlB,mBAAmC,WAAU,GAAC,oBAAS,QAAT,mBAAc,gBAAd,mBAA2B,SAAQ;AACxH,aAAS,KAAK,iFAAiF;AAAA,EACjG;AAEA,SAAO;AAAA,IACL,OAAO,KAAK,SAAS,OAAO,WAAW;AAAA,IACvC;AAAA,IACA;AAAA,EAAA;AAEJ;AAEO,SAAS,2BAA2B,OAAO,QAAQ,OAAkC;AAC1F,QAAM,UAAU,2BAA2B,IAAI;AAC/C,QAAM,SAAmB,CAAA;AACzB,QAAM,WAAqB,CAAA;AAC3B,QAAM,0BAAU,IAAA;AAEhB,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO,KAAK,2DAA2D;AAAA,EACzE;AAEA,aAAW,SAAS,SAAS;AAC3B,QAAI,IAAI,IAAI,MAAM,EAAE,GAAG;AACrB,aAAO,KAAK,2BAA2B,MAAM,EAAE,EAAE;AAAA,IACnD;AACA,QAAI,IAAI,MAAM,EAAE;AAChB,UAAM,SAAS,iCAAiC,MAAM,QAAQ;AAC9D,WAAO,KAAK,GAAG,OAAO,OAAO,IAAI,CAAC,YAAY,GAAG,MAAM,EAAE,KAAK,OAAO,EAAE,CAAC;AACxE,aAAS,KAAK,GAAG,OAAO,SAAS,IAAI,CAAC,YAAY,GAAG,MAAM,EAAE,KAAK,OAAO,EAAE,CAAC;AAAA,EAC9E;AAEA,SAAO;AAAA,IACL,OAAO,OAAO,WAAW;AAAA,IACzB;AAAA,IACA;AAAA,EAAA;AAEJ;AAEA,SAAS,mBAAmB,MAAwB;AAClD,MAAI,CAAC,WAAW,IAAI,UAAU,CAAA;AAC9B,SAAO,YAAY,IAAI,EAAE,QAAQ,CAAC,SAAS;AACzC,UAAM,eAAe,KAAK,KAAK,MAAM,IAAI;AACzC,UAAM,eAAe,KAAK,SAAS,MAAM,YAAY;AACrD,QAAI,SAAS,YAAY,EAAE,eAAe;AACxC,aAAO,mBAAmB,YAAY,EAAE,IAAI,CAAC,UAAU,KAAK,KAAK,cAAc,KAAK,CAAC;AAAA,IACvF;AACA,WAAO,CAAC,YAAY;AAAA,EACtB,CAAC;AACH;AAOA,SAAS,gBAAgB,OAAe;AACtC,SAAO,MACJ,MAAM,MAAM,EACZ,OAAO,OAAO,EACd,IAAI,CAAC,MAAM,UAAU;AACpB,UAAM,aAAa,KAAK,QAAQ,mBAAmB,EAAE;AACrD,QAAI,CAAC,WAAY,QAAO;AACxB,WAAO,UAAU,IACb,WAAW,QAAQ,iBAAiB,EAAE,KAAK,qBAC3C,WAAW,OAAO,CAAC,EAAE,YAAA,IAAgB,WAAW,MAAM,CAAC;AAAA,EAC7D,CAAC,EACA,KAAK,EAAE,KAAK;AACjB;AAEA,SAAS,mBAAmB,eAAuB,aAAsB;AACvE,QAAM,UAAU,QAAQ,aAAa,UAAU,aAAa;AAC5D,QAAM,aAAa;AAAA,IACjB,KAAK,KAAK,eAAe,gBAAgB,QAAQ,OAAO;AAAA,IACxD,cAAc,KAAK,KAAK,aAAa,gBAAgB,QAAQ,OAAO,IAAI;AAAA,EAAA,EACxE,OAAO,CAAC,cAAmC,QAAQ,SAAS,CAAC;AAC/D,SAAO,WAAW,KAAK,CAAC,cAAc,WAAW,SAAS,CAAC,KAAK;AAClE;AAEA,SAAS,gCAAgC,OAKtC;AACD,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAA0O,KAAK,UAAU,MAAM,MAAM,CAAC;AAAA;AAAA,eAA+B,KAAK,UAAU,MAAM,SAAS,CAAC;AAAA,cAAkB,KAAK,UAAU,MAAM,UAAU,CAAC;AAAA;AAAA,wBAAsD,KAAK,UAAU,sBAAsB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAC3d;AAEA,SAAS,gBAAgB,OAAgC,eAAuB,WAAmB,aAAsB;AACvH,QAAM,cAAc,KAAK,QAAQ,MAAM,KAAK,MAAM,SAAS,QAAQ,iBAAiB;AACpF,MAAI,CAAC,WAAW,WAAW,GAAG;AAC5B,UAAM,IAAI,MAAM,mCAAmC,WAAW,EAAE;AAAA,EAClE;AAEA,QAAM,aAAa,gBAAgB,MAAM,EAAE;AAC3C,QAAM,YAAY,KAAK,KAAK,eAAe,YAAY,SAAS,OAAO;AACvE,YAAU,WAAW,EAAE,WAAW,KAAA,CAAM;AACxC,QAAM,aAAa,KAAK,KAAK,WAAW,GAAG,MAAM,GAAG,QAAQ,oBAAoB,GAAG,CAAC,aAAa;AACjG;AAAA,IACE;AAAA,IACA,gCAAgC;AAAA,MAC9B,OAAO,MAAM;AAAA,MACb,WAAW;AAAA,MACX,QAAQ;AAAA,MACR;AAAA,IAAA,CACD;AAAA,IACD;AAAA,EAAA;AAGF,QAAM,UAAU,mBAAmB,eAAe,WAAW;AAC7D,QAAM,SAAS,UAAU,SAAS,CAAC,SAAS,YAAY,UAAU,GAAG;AAAA,IACnE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,OAAO,QAAQ,aAAa;AAAA,IAC5B,UAAU;AAAA,EAAA,CACX;AACD,MAAI,OAAO,WAAW,GAAG;AACvB,UAAM,IAAI,MAAM,mBAAmB,MAAM,EAAE;AAAA,EAAM,OAAO,UAAU,EAAE,GAAG,OAAO,UAAU,EAAE,GAAG,MAAM;AAAA,EACrG;AAEA,SAAO;AAAA,IACL;AAAA,IACA,WAAW;AAAA,IACX,UAAU,mBAAmB,SAAS,EAAE,OAAO,CAAC,SAAS,KAAK,SAAS,MAAM,CAAC,EAAE,KAAA;AAAA,EAAK;AAEzF;AAEO,SAAS,eACd,OACA,eACA,UAAiC,CAAA,GACX;AACtB,QAAM,YAAY,KAAK,KAAK,eAAe,YAAY,SAAS,MAAM,EAAE;AACxE,SAAO,WAAW,EAAE,WAAW,MAAM,OAAO,MAAM;AAClD,YAAU,WAAW,EAAE,WAAW,KAAA,CAAM;AAExC,MAAI,UAA+E,CAAA;AACnF,QAAM,WAAqC;AAAA,IACzC,GAAG,MAAM;AAAA,IACT,OAAO,MAAM,SAAS,SAAS,MAAM;AAAA,IACrC,IAAI,MAAM,SAAS,MAAM,MAAM;AAAA,IAC/B,iBAAiB,MAAM,SAAS,mBAAmB;AAAA,IACnD,YAAY,MAAM,SAAS,cAAc;AAAA,IACzC,YAAY;AAAA,EAAA;AAGd,MAAI,QAAQ,QAAQ;AAClB,cAAU,gBAAgB,OAAO,eAAe,WAAW,QAAQ,WAAW;AAC9E,aAAS,OAAO,KAAK,QAAQ,SAAS;AAAA,EACxC;AAEA,QAAM,iBAAiB,KAAK,KAAK,WAAW,eAAe;AAC3D,gBAAc,gBAAgB,QAAQ;AAEtC,MAAI,CAAC,QAAQ,QAAQ;AACnB,UAAM,SAAS,KAAK,KAAK,MAAM,KAAK,KAAK;AACzC,UAAM,UAAU,KAAK,KAAK,MAAM,KAAK,MAAM;AAC3C,UAAM,eAAe,WAAW,OAAO,IAAI,UAAU;AAErD,QAAI,WAAW,YAAY,GAAG;AAC5B,YAAM,YAAY,KAAK,KAAK,WAAW,WAAW,OAAO,IAAI,SAAS,KAAK;AAC3E,aAAO,cAAc,WAAW,EAAE,WAAW,MAAM;AAAA,IACrD;AAAA,EACF;AAEA,SAAO;AAAA,IACL,IAAI,MAAM;AAAA,IACV,UAAU;AAAA,IACV,OAAO,mBAAmB,SAAS,EAAE,KAAA;AAAA,IACrC,GAAG;AAAA,EAAA;AAEP;AAEA,SAAS,OAAO,QAAyB;AACvC,SAAO,WAAW,QAAQ,EAAE,OAAO,MAAM,EAAE,OAAO,KAAK;AACzD;AAEA,SAAS,aAAa,QAAyB;AAC7C,SAAO,WAAW,QAAQ,EAAE,OAAO,MAAM,EAAE,OAAO,QAAQ;AAC5D;AAEA,SAAS,mBAAmB,UAA0C;AACpE,SAAO,mBAAmB,QAAQ,EAC/B,OACA,IAAI,CAAC,iBAAiB;AACrB,UAAM,eAAe,KAAK,KAAK,UAAU,YAAY;AACrD,UAAM,UAAU,aAAa,YAAY;AACzC,WAAO;AAAA,MACL,MAAM;AAAA,MACN,QAAQ,OAAO,OAAO;AAAA,MACtB,MAAM,QAAQ;AAAA,MACd,eAAe,QAAQ,SAAS,QAAQ;AAAA,IAAA;AAAA,EAE5C,CAAC;AACL;AAMA,SAAS,kBAAkB,UAAkB;AAC3C,SAAO,aAAuC,KAAK,KAAK,UAAU,eAAe,CAAC;AACpF;AAEO,SAAS,cACd,OACA,eACA,QACA,UAAgC,CAAA,GACN;;AAC1B,QAAM,mBAAmB,KAAK,KAAK,eAAe,YAAY,SAAS,MAAM,EAAE;AAC/E,MAAI,QAAQ,oBAAoB,CAAC,WAAW,gBAAgB,GAAG;AAC7D,UAAM,IAAI,MAAM,8BAA8B,MAAM,EAAE,iCAAiC,MAAM,EAAE,SAAS;AAAA,EAC1G;AACA,QAAM,QAAQ,QAAQ,mBAClB;AAAA,IACE,IAAI,MAAM;AAAA,IACV,UAAU;AAAA,IACV,OAAO,mBAAmB,gBAAgB,EAAE,KAAA;AAAA,IAC5C,WAAW;AAAA,IACX,UAAU,mBAAmB,gBAAgB,EAAE,OAAO,CAAC,SAAS,KAAK,SAAS,MAAM,CAAC,EAAE,KAAA;AAAA,IACvF,YAAY,gBAAgB,MAAM,EAAE;AAAA,EAAA,IAEtC,eAAe,OAAO,eAAe,OAAO;AAChD,QAAM,iBAAiB,kBAAkB,MAAM,QAAQ;AACvD,QAAM,cAAc,mBAAmB,MAAM,QAAQ;AACrD,QAAM,WAAqC;AAAA,IACzC,GAAG;AAAA,IACH,WAAW;AAAA,MACT,WAAW;AAAA,MACX,OAAO,OAAO;AAAA,QACZ,YACG,OAAO,CAAC,SAAS,KAAK,SAAS,eAAe,EAC9C,IAAI,CAAC,SAAS,CAAC,KAAK,MAAM,UAAU,aAAa,OAAO,KAAK,KAAK,eAAe,QAAQ,CAAC,CAAC,EAAE,CAAC;AAAA,MAAA;AAAA,IACnG;AAAA,EACF;AAEF,gBAAc,KAAK,KAAK,MAAM,UAAU,eAAe,GAAG,QAAQ;AAClE,QAAM,QAAQ,mBAAmB,MAAM,QAAQ;AAC/C,QAAM,0BAA0B;AAAA,IAC9B,QAAQ;AAAA,IACR,eAAe;AAAA,IACf,OAAO,MAAM;AAAA,IACb,SAAS,SAAS;AAAA,IAClB;AAAA,IACA,SAAS;AAAA,MACP,YAAY;AAAA,MACZ,WAAW,MAAM,eAAa,cAAS,SAAT,mBAAe,QAAQ,SAAS,QAAO;AAAA,MACrE,UAAU,MAAM,YAAY,CAAA;AAAA,MAC5B,YAAY,MAAM,cAAc,gBAAgB,MAAM,EAAE;AAAA,IAAA;AAAA,IAE1D;AAAA,IACA,YAAW,oBAAI,KAAA,GAAO,YAAA;AAAA,EAAY;AAEpC,QAAM,SAAS,OAAO,KAAK,UAAU,uBAAuB,CAAC;AAC7D,QAAM,WAAqC;AAAA,IACzC,GAAG;AAAA,IACH,WAAW;AAAA,MACT,WAAW;AAAA,MACX;AAAA,IAAA;AAAA,EACF;AAGF,QAAM,YAAY,SAAS,KAAK,QAAQ,eAAe,MAAM,IAAI,KAAK,KAAK,eAAe,YAAY,UAAU;AAChH,YAAU,WAAW,EAAE,WAAW,KAAA,CAAM;AACxC,QAAM,cAAc,KAAK,KAAK,WAAW,GAAG,MAAM,EAAE,IAAI,SAAS,OAAO,GAAG,2BAA2B,EAAE;AACxG,gBAAc,aAAa,QAAQ;AACnC,SAAO;AACT;AAEA,SAAS,oBACP,eACA,eACA,aACA,UACA,QACA;AACA,QAAM,gBAAgB,KAAK,KAAK,eAAe,eAAe,WAAW;AACzE,gBAAc,KAAK,KAAK,eAAe,eAAe,GAAG;AAAA,IACvD,GAAG;AAAA,IACH,iBAAiB,SAAS,mBAAmB;AAAA,IAC7C,YAAY,SAAS,cAAc;AAAA,EAAA,CACpC;AACD,YAAU,KAAK,KAAK,eAAe,KAAK,GAAG,EAAE,WAAW,MAAM;AAC9D,gBAAc,KAAK,KAAK,eAAe,OAAO,WAAW,GAAG,QAAQ,MAAM;AAC5E;AAEA,SAAS,mCAAmC,aAG1C;AACA,SAAO;AAAA,IACL,UAAU;AAAA,MACR,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,SAAS;AAAA,MACT,MAAM;AAAA,MACN,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,SAAS;AAAA,QACP,eAAe,WAAW,WAAW;AAAA,QACrC,cAAc;AAAA,MAAA;AAAA,MAEhB,KAAK;AAAA,QACH,SAAS;AAAA,QACT,aAAa;AAAA,UACX;AAAA,YACE,KAAK,QAAQ,WAAW;AAAA,YACxB,MAAM;AAAA,YACN,aAAa;AAAA,YACb,UAAU;AAAA,YACV,SAAS;AAAA,YACT,UAAU;AAAA,cACR,cAAc,CAAC,MAAM,KAAK;AAAA,YAAA;AAAA,UAC5B;AAAA,QACF;AAAA,QAEF,eAAe;AAAA,UACb;AAAA,YACE,MAAM;AAAA,YACN,aAAa;AAAA,YACb,aAAa;AAAA,cACX,MAAM;AAAA,cACN,YAAY;AAAA,gBACV,SAAS,EAAE,MAAM,SAAA;AAAA,cAAS;AAAA,YAC5B;AAAA,YAEF,YAAY;AAAA,UAAA;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAAA,IAEF,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAA0xP,WAAW,sBAAsB,WAAW;AAAA,EAAA;AAEl1P;AAEA,SAAS,oCAAoC,QAAwB;AACnE,QAAM,eAAwC;AAAA,IAC5C,CAAC,iBAAiB,QAAQ;AAAA,IAC1B,CAAC,6FAA6F,gCAAgC;AAAA,IAC9H,CAAC,gBAAgB,OAAO;AAAA,IACxB,CAAC,yDAAyD,6CAA6C;AAAA,IACvG,CAAC,aAAa,OAAO;AAAA,IACrB,CAAC,8DAA8D,0BAA0B;AAAA,IACzF,CAAC,oBAAoB,SAAS;AAAA,IAC9B,CAAC,sEAAsE,yCAAyC;AAAA,IAChH,CAAC,oBAAoB,aAAa;AAAA,IAClC,CAAC,oBAAoB,UAAU;AAAA,IAC/B,CAAC,8BAA8B,UAAU;AAAA,IACzC,CAAC,qBAAqB,MAAM;AAAA,IAC5B,CAAC,0BAA0B,aAAa;AAAA,IACxC,CAAC,iBAAiB,QAAQ;AAAA,IAC1B,CAAC,wBAAwB,UAAU;AAAA,IACnC,CAAC,0BAA0B,YAAY;AAAA,IACvC,CAAC,iBAAiB,OAAO;AAAA,IACzB,CAAC,yBAAyB,QAAQ;AAAA,IAClC,CAAC,qBAAqB,MAAM;AAAA,IAC5B,CAAC,yBAAyB,WAAW;AAAA,IACrC,CAAC,WAAW,MAAM;AAAA,IAClB,CAAC,uBAAuB,kBAAkB;AAAA,IAC1C,CAAC,8FAA8F,6BAA6B;AAAA,IAC5H,CAAC,mBAAmB,MAAM;AAAA,IAC1B,CAAC,qFAAqF,qCAAqC;AAAA,IAC3H,CAAC,eAAe,SAAS;AAAA,IACzB,CAAC,2EAA2E,6CAA6C;AAAA,IACzH,CAAC,sBAAsB,KAAK;AAAA,IAC5B,CAAC,iGAAiG,6DAA6D;AAAA,IAC/J,CAAC,eAAe,OAAO;AAAA,IACvB,CAAC,uFAAuF,qDAAqD;AAAA,IAC7I,CAAC,yBAAyB,SAAS;AAAA,IACnC,CAAC,0JAA0J,yCAAyC;AAAA,IACpM,CAAC,iBAAiB,SAAS;AAAA,IAC3B,CAAC,cAAc,SAAS;AAAA,IACxB,CAAC,eAAe,SAAS;AAAA,IACzB,CAAC,UAAU,KAAK;AAAA,IAChB,CAAC,cAAc,QAAQ;AAAA,IACvB,CAAC,qKAAqK,+EAA+E;AAAA,IACrP,CAAC,2GAA2G,mDAAmD;AAAA,IAC/J,CAAC,gGAAgG,iCAAiC;AAAA,IAClI,CAAC,SAAS,IAAI;AAAA,IACd,CAAC,gDAAgD,4BAA4B;AAAA,IAC7E,CAAC,cAAc,OAAO;AAAA,IACtB,CAAC,+DAA+D,4BAA4B;AAAA,IAC5F,CAAC,cAAc,OAAO;AAAA,IACtB,CAAC,wBAAwB,OAAO;AAAA,IAChC,CAAC,kDAAkD,8BAA8B;AAAA,IACjF,CAAC,4BAA4B,WAAW;AAAA,IACxC,CAAC,8DAA8D,6BAA6B;AAAA,IAC5F,CAAC,qBAAqB,YAAY;AAAA,IAClC,CAAC,oEAAoE,0BAA0B;AAAA,IAC/F,CAAC,mBAAmB,MAAM;AAAA,IAC1B,CAAC,kEAAkE,kBAAkB;AAAA,IACrF,CAAC,aAAa,MAAM;AAAA,IACpB,CAAC,8EAA8E,uBAAuB;AAAA,IACtG,CAAC,2BAA2B,qBAAqB;AAAA,IACjD,CAAC,YAAY,MAAM;AAAA,IACnB,CAAC,WAAW,KAAK;AAAA,IACjB,CAAC,mBAAmB,MAAM;AAAA,IAC1B,CAAC,UAAU,IAAI;AAAA,IACf,CAAC,WAAW,KAAK;AAAA,IACjB,CAAC,YAAY,KAAK;AAAA,IAClB,CAAC,kBAAkB,OAAO;AAAA,IAC1B,CAAC,mBAAmB,QAAQ;AAAA,IAC5B,CAAC,YAAY,QAAQ;AAAA,IACrB,CAAC,YAAY,QAAQ;AAAA,IACrB,CAAC,kBAAkB,QAAQ;AAAA,IAC3B,CAAC,+DAA+D,sBAAsB;AAAA,IACtF,CAAC,cAAc,MAAM;AAAA,IACrB,CAAC,QAAQ,IAAI;AAAA,IACb,CAAC,QAAQ,IAAI;AAAA,IACb,CAAC,WAAW,KAAK;AAAA,IACjB,CAAC,mBAAmB,MAAM;AAAA,IAC1B,CAAC,cAAc,SAAS;AAAA,EAAA;AAE1B,SAAO,aAAa,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,OAAO,WAAW,MAAM,EAAE,GAAG,MAAM;AACxF;AAEA,SAAS,qCAAqC,QAAwB;AACtE,QAAM,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0KtB,SAAO,oCAAoC,OACxC,QAAQ,8BAA8B,+WAA+W,EACrZ,QAAQ,uCAAuC,sDAAsD,EACrG,QAAQ,uCAAuC,sDAAsD,EACrG,QAAQ,6DAA6D,oKAAoK,EACzO;AAAA,IACC;AAAA,IACA;AAAA,EAAA,EAED;AAAA,IACC;AAAA,IACA;AAAA,EAAA,EAED,WAAW,oBAAoB,oBAAoB,EACnD,WAAW,2BAA2B,2BAA2B,EACjE,WAAW,4BAA4B,4BAA4B,EACnE,QAAQ,mDAAmD,sDAAsD,EACjH,QAAQ,0BAA0B,6BAA6B,EAC/D,QAAQ,sDAAsD,iEAAiE,EAC/H,QAAQ,gDAAgD,wDAAwD,EAChH,QAAQ,wDAAwD,qEAAqE,EACrI;AAAA,IACC;AAAA,IACA;AAAA,EAAA,EAED,QAAQ,uBAAuB,GAAG,eAAe;AAAA,kBAAqB,EACtE;AAAA,IACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA,EAED;AAAA,IACC;AAAA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA,EAED;AAAA,IACC;AAAA;AAAA,IAEA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA,EAMD;AAAA,IACC;AAAA,IACA;AAAA,EAAA,EAED;AAAA,IACC;AAAA,IACA;AAAA,EAAA,EAED,WAAW,uCAAuC,uCAAuC,EACzF,WAAW,0CAA0C,0CAA0C,EAC/F,WAAW,oDAAoD,EAAE,EACjE,WAAW,oBAAoB,oBAAoB,EACnD,WAAW,wCAAwC,iDAAiD,EACpG,WAAW,kCAAkC,wCAAwC,EACrF,WAAW,0CAA0C,qDAAqD,EAC1G;AAAA,IACC;AAAA,IACA;AAAA,EAAA,EAED;AAAA,IACC;AAAA,IACA;AAAA,EAAA,EAED;AAAA,IACC;AAAA,IACA;AAAA,EAAA,EAED;AAAA,IACC;AAAA,IACA;AAAA,EAAA,EAED;AAAA,IACC;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA,EAED,QAAQ,2CAA2C,wBAAwB,CAAC;AACjF;AAEA,SAAS,4BAA4B,aAGnC;AACA,SAAO;AAAA,IACL,UAAU;AAAA,MACR,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,SAAS;AAAA,MACT,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,SAAS;AAAA,QACP,eAAe,WAAW,WAAW;AAAA,QACrC,cAAc;AAAA,MAAA;AAAA,MAEhB,KAAK;AAAA,QACH,SAAS;AAAA,QACT,aAAa,CAAA;AAAA,QACb,eAAe,CAAA;AAAA,MAAC;AAAA,IAClB;AAAA,IAEF,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA8jB,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA;AAErlB;AAEA,SAAS,iCAAiC,aAGxC;AACA,SAAO;AAAA,IACL,UAAU;AAAA,MACR,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,SAAS;AAAA,MACT,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,SAAS;AAAA,QACP,eAAe,WAAW,WAAW;AAAA,QACrC,cAAc;AAAA,MAAA;AAAA,MAEhB,KAAK;AAAA,QACH,SAAS;AAAA,QACT,aAAa,CAAA;AAAA,QACb,eAAe,CAAA;AAAA,MAAC;AAAA,IAClB;AAAA,IAEF,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBA6CO,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA;AAO9B;AAEA,SAAS,iCAAiC,aAGxC;AACA,SAAO;AAAA,IACL,UAAU;AAAA,MACR,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,SAAS;AAAA,MACT,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,SAAS;AAAA,QACP,eAAe,WAAW,WAAW;AAAA,QACrC,cAAc;AAAA,MAAA;AAAA,MAEhB,KAAK;AAAA,QACH,SAAS;AAAA,QACT,aAAa,CAAA;AAAA,QACb,eAAe;AAAA,UACb;AAAA,YACE,MAAM;AAAA,YACN,aAAa;AAAA,YACb,aAAa;AAAA,cACX,MAAM;AAAA,cACN,YAAY;AAAA,gBACV,SAAS,EAAE,MAAM,SAAA;AAAA,cAAS;AAAA,YAC5B;AAAA,YAEF,YAAY;AAAA,UAAA;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAAA,IAEF,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA+lB,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAAuM,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA;AAEx0B;AAEA,SAAS,8BAA8B,aAGrC;AACA,SAAO;AAAA,IACL,UAAU;AAAA,MACR,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,SAAS;AAAA,MACT,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,SAAS;AAAA,QACP,eAAe,WAAW,WAAW;AAAA,QACrC,cAAc;AAAA,MAAA;AAAA,MAEhB,KAAK;AAAA,QACH,SAAS;AAAA,QACT,aAAa,CAAA;AAAA,QACb,eAAe,CAAA;AAAA,MAAC;AAAA,IAClB;AAAA,IAEF,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA2nB,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA,gBAAgJ,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA;AAE7yB;AAEA,SAAS,mCAAmC,QAAgB;AAC1D,SAAO,OACJ,WAAW,oBAAoB,oBAAoB,EACnD,WAAW,yBAAyB,yBAAyB,EAC7D,WAAW,gDAAgD,EAAE,EAC7D,WAAW,aAAa,YAAY;AACzC;AAEO,SAAS,yBACd,MACA,cAAc,gBACd,WAAuC,SACvC;AACA,QAAM,gBAAgB,KAAK,QAAQ,IAAI;AACvC,QAAM,qBAAqB,aAAa,SACpC;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IAEF,CAAC,WAAW;AAChB,QAAM,SAAS,yBAAyB;AAAA,IACtC,cAAc;AAAA,MACZ,qBAAqB;AAAA,IAAA;AAAA,EACvB,CACD;AAED,gBAAc,KAAK,KAAK,eAAe,0BAA0B,GAAG,MAAM;AAC1E,gBAAc,KAAK,KAAK,eAAe,WAAW,GAAG,4BAA4B,MAAM;AACvF,gBAAc,KAAK,KAAK,eAAe,WAAW,GAAG,4BAA4B,MAAM;AACvF,gBAAc,KAAK,KAAK,eAAe,UAAU,iBAAiB,GAAG,uBAAuB;AAC5F,gBAAc,KAAK,KAAK,eAAe,cAAc,GAAG;AAAA,IACtD,SAAS;AAAA,IACT,MAAM;AAAA,IACN,SAAS;AAAA,MACP,KAAK;AAAA,MACL,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,UAAU;AAAA,MACV,OAAO;AAAA,MACP,MAAM;AAAA,MACN,SAAS;AAAA,IAAA;AAAA,IAEX,cAAc;AAAA,MACZ,2BAA2B;AAAA,MAC3B,wBAAwB;AAAA,MACxB,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,OAAO;AAAA,MACP,aAAa;AAAA,IAAA;AAAA,EACf,CACD;AAED,QAAM,UAAU,aAAa,SACzB;AAAA,IACE,CAAC,sBAAsB,mCAAmC,oBAAoB,CAAC;AAAA,IAC/E,CAAC,sBAAsB,4BAA4B,oBAAoB,CAAC;AAAA,IACxE,CAAC,4BAA4B,iCAAiC,0BAA0B,CAAC;AAAA,IACzF,CAAC,4BAA4B,iCAAiC,0BAA0B,CAAC;AAAA,IACzF,CAAC,yBAAyB,8BAA8B,uBAAuB,CAAC;AAAA,EAAA,IAElF,CAAC,CAAC,aAAa,mCAAmC,WAAW,CAAC,CAAC;AAEnE,UAAQ,QAAQ,CAAC,CAAC,IAAI,MAAM,MAAM;AAChC;AAAA,MACE;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA,OAAO;AAAA,MACL,OAAO,wBAAwB,OAAO,cACpC,qCAAqC,OAAO,MAAM,IAClD,OAAO,0BACL,mCAAmC,OAAO,MAAM,IAChD,OAAO;AAAA,IAAA;AAAA,EAEjB,CAAC;AACH;AClpCA,SAAS,iBAAiB,SAAiB,YAAoB;AAC7D,QAAM,eAAe,KAAK,SAAS,SAAS,UAAU,EAAE,MAAM,KAAK,GAAG,EAAE,KAAK,GAAG;AAChF,SAAO,aAAa,WAAW,GAAG,IAAI,eAAe,KAAK,YAAY;AACxE;AAEO,SAAS,gCACd,eACA,OAAO,QACP,UAA6C,CAAA,GACX;AAClC,QAAM,SAAS;AAAA,IACb,GAAG,6BAA6B,aAAa;AAAA,IAC7C,cAAc,0BAA0B,aAAa;AAAA,EAAA;AAEvD,QAAM,UAAU,2BAA2B,aAAa;AACxD,QAAM,UAAU,KAAK,KAAK,eAAe,YAAY,eAAe;AACpE,YAAU,SAAS,EAAE,WAAW,KAAA,CAAM;AAEtC,QAAM,UAAU,QAAQ,IAAI,CAAC,OAAO,UAAU;AAC5C,UAAM,aAAa,KAAK,KAAK,MAAM,KAAK,MAAM,SAAS,QAAQ,iBAAiB;AAChF,WAAO,wBAAwB,KAAK,UAAU,iBAAiB,KAAK,KAAK,SAAS,KAAK,GAAG,UAAU,CAAC;AAAA,EACvG,CAAC;AACD,QAAM,UAAU,QAAQ;AAAA,IAAI,CAAC,OAAO,UAClC,iBAAiB,KAAK,UAAU,MAAM,QAAQ,CAAC,sBAAsB,KAAK;AAAA,EAAA;AAG5E;AAAA,IACE,KAAK,KAAK,SAAS,YAAY;AAAA,IAC/B;AAAA,IACA;AAAA,EAAA;AAEF,YAAU,KAAK,KAAK,SAAS,KAAK,GAAG,EAAE,WAAW,MAAM;AACxD;AAAA,IACE,KAAK,KAAK,SAAS,OAAO,UAAU;AAAA,IACpC,GAAG,QAAQ,KAAK,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAA0T,KAAK,UAAU,MAAM,CAAC;AAAA;AAAA,EAAyB,QAAQ,KAAK,KAAK,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,IACjZ;AAAA,EAAA;AAEF;AAAA,IACE,KAAK,KAAK,SAAS,gBAAgB;AAAA,IACnC,uBAAuB,eAAe,QAAQ,WAAW;AAAA,IACzD;AAAA,EAAA;AAGF,MAAI,CAAC,WAAW,KAAK,KAAK,eAAe,cAAc,CAAC,GAAG;AACzD;AAAA,MACE,KAAK,KAAK,SAAS,WAAW;AAAA,MAC9B;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ;AAEA,SAAO,EAAE,SAAS,OAAO,QAAQ,QAAQ,KAAA;AAC3C;AAEA,SAAS,uBAAuB,eAAuB,aAAsB;AAC3E,QAAM,iBAAiB,cACnB;AAAA,IACE;AAAA,MACE,MAAM;AAAA,MACN,aAAa,KAAK,KAAK,aAAa,QAAQ,2BAA2B,UAAU;AAAA,IAAA;AAAA,IAEnF;AAAA,MACE,MAAM;AAAA,MACN,aAAa,KAAK,KAAK,aAAa,QAAQ,WAAW,QAAQ,UAAU;AAAA,IAAA;AAAA,IAE3E;AAAA,MACE,MAAM;AAAA,MACN,aAAa,KAAK,KAAK,aAAa,QAAQ,WAAW,UAAU;AAAA,IAAA;AAAA,IAEnE;AAAA,MACE,MAAM;AAAA,MACN,aAAa,KAAK,KAAK,aAAa,QAAQ,oBAAoB;AAAA,IAAA;AAAA,IAElE;AAAA,MACE,MAAM;AAAA,MACN,aAAa,KAAK,KAAK,aAAa,QAAQ,UAAU;AAAA,IAAA;AAAA,EACxD,IAEF,CAAA;AACJ,QAAM,eAAe,eAClB;AAAA,IAAI,CAAC,UACJ,iBAAiB,KAAK,UAAU,MAAM,IAAI,CAAC,kBAAkB,KAAK,UAAU,MAAM,WAAW,CAAC;AAAA,EAAA,EAE/F,KAAK,KAAK;AAEb,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAAkL,KAAK,UAAU,aAAa,CAAC,GAAG,cAAc,KAAK,KAAK,UAAU,WAAW,CAAC,KAAK,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA,EAAiD,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAC7U;"}
@@ -3,13 +3,13 @@ import { spawnSync } from "node:child_process";
3
3
  import { existsSync, readFileSync, watch } from "node:fs";
4
4
  import path from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
- 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-BmYheR6S.js";
6
+ 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-C-rC8sz8.js";
7
7
  function printUsage() {
8
8
  console.log(`appthen-extension
9
9
 
10
10
  Usage:
11
11
  appthen-extension init [dir] [--id app.id] [--template basic|full]
12
- appthen-extension dev [--port 5177] [--no-watch]
12
+ appthen-extension dev [--port 5177] [--no-watch] [--package-root <vibe-workspace-dir>]
13
13
  appthen-extension doctor [--json]
14
14
  appthen-extension test [extensionId]
15
15
  appthen-extension validate
@@ -162,7 +162,7 @@ function commandTest({ cwd, args }) {
162
162
  return;
163
163
  }
164
164
  const { workspaceRoot, entries } = selectEntries(cwd, extensionId);
165
- const packageRoot = resolvePackageRoot();
165
+ const packageRoot = resolvePackageRoot(readFlag(args, "--package-root"));
166
166
  for (const entry of entries) {
167
167
  const build = buildExtension(entry, workspaceRoot, { bundle: true, packageRoot });
168
168
  const artifact = packExtension(entry, workspaceRoot, void 0, {
@@ -184,7 +184,7 @@ function commandTest({ cwd, args }) {
184
184
  function commandBuild({ cwd, args }) {
185
185
  const extensionId = args[0] && !args[0].startsWith("--") ? args[0] : void 0;
186
186
  const { workspaceRoot, entries } = selectEntries(cwd, extensionId);
187
- const packageRoot = resolvePackageRoot();
187
+ const packageRoot = resolvePackageRoot(readFlag(args, "--package-root"));
188
188
  for (const entry of entries) {
189
189
  const result = buildExtension(entry, workspaceRoot, {
190
190
  bundle: true,
@@ -197,7 +197,7 @@ function commandPack({ cwd, args }) {
197
197
  const extensionId = args[0] && !args[0].startsWith("--") ? args[0] : void 0;
198
198
  const outDir = readFlag(args, "--out");
199
199
  const { workspaceRoot, entries } = selectEntries(cwd, extensionId);
200
- const packageRoot = resolvePackageRoot();
200
+ const packageRoot = resolvePackageRoot(readFlag(args, "--package-root"));
201
201
  for (const entry of entries) {
202
202
  const artifact = packExtension(entry, workspaceRoot, outDir, {
203
203
  bundle: true,
@@ -211,7 +211,7 @@ function commandPack({ cwd, args }) {
211
211
  function commandDev({ cwd, args }) {
212
212
  const workspaceRoot = getWorkspaceRoot(cwd);
213
213
  const port = readFlag(args, "--port") || "5177";
214
- const packageRoot = resolvePackageRoot();
214
+ const packageRoot = resolvePackageRoot(readFlag(args, "--package-root"));
215
215
  const { devRoot, count } = writeExtensionDevWorkbenchFiles(workspaceRoot, port, {
216
216
  packageRoot
217
217
  });
@@ -225,7 +225,7 @@ function commandDev({ cwd, args }) {
225
225
  if (!hasFlag(args, "--no-watch")) {
226
226
  closeWatcher = watchExtensionManifests(workspaceRoot, port, packageRoot);
227
227
  }
228
- const command = resolveViteCommand(workspaceRoot);
228
+ const command = resolveViteCommand(workspaceRoot, packageRoot);
229
229
  const result = spawnSync(command, ["--host", "0.0.0.0", "--port", port], {
230
230
  cwd: devRoot,
231
231
  stdio: "inherit",
@@ -234,15 +234,19 @@ function commandDev({ cwd, args }) {
234
234
  closeWatcher == null ? void 0 : closeWatcher();
235
235
  process.exitCode = result.status ?? 1;
236
236
  }
237
- function resolveViteCommand(workspaceRoot) {
237
+ function resolveViteCommand(workspaceRoot, packageRoot) {
238
238
  const binName = process.platform === "win32" ? "vite.cmd" : "vite";
239
239
  const candidates = [
240
240
  path.join(workspaceRoot, "node_modules", ".bin", binName),
241
- path.join(resolvePackageRoot(), "node_modules", ".bin", binName)
241
+ path.join(packageRoot || resolvePackageRoot(), "node_modules", ".bin", binName)
242
242
  ];
243
243
  return candidates.find((candidate) => existsSync(candidate)) || "vite";
244
244
  }
245
- function resolvePackageRoot() {
245
+ function resolvePackageRoot(explicitRoot) {
246
+ if (explicitRoot) return path.resolve(explicitRoot);
247
+ if (process.env.APPTHEN_VIBE_WORKSPACE_ROOT) {
248
+ return path.resolve(process.env.APPTHEN_VIBE_WORKSPACE_ROOT);
249
+ }
246
250
  return path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
247
251
  }
248
252
  function watchExtensionManifests(workspaceRoot, port, packageRoot) {
@@ -322,7 +326,7 @@ async function commandPublish({ cwd, args }) {
322
326
  console.warn("Publishing with --workbench is an isolated install path; prefer --install-tenant or a separate install command.");
323
327
  }
324
328
  const { workspaceRoot, entries } = selectEntries(cwd, extensionId);
325
- const packageRoot = resolvePackageRoot();
329
+ const packageRoot = resolvePackageRoot(readFlag(args, "--package-root"));
326
330
  for (const entry of entries) {
327
331
  const artifact = packExtension(entry, workspaceRoot, void 0, {
328
332
  bundle: !hasFlag(args, "--skip-build"),
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/extension-cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { spawnSync } from 'node:child_process';\nimport { watch } from 'node:fs';\nimport { existsSync, readFileSync } from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { writeExtensionDevWorkbenchFiles } from '@/extension-dev/devWorkbench';\nimport type { ExtensionWorkspaceTemplate } from '@/extension-dev/types';\nimport {\n EXTENSION_PACKAGE_EXTENSION,\n buildExtension,\n createExtensionWorkspace,\n discoverExtensionWorkspace,\n findExtensionWorkspaceRoot,\n packExtension,\n validateExtensionWorkspace,\n} from '@/extension-dev/workspace';\n\ninterface CliOptions {\n cwd: string;\n args: string[];\n}\n\nfunction printUsage() {\n console.log(`appthen-extension\n\nUsage:\n appthen-extension init [dir] [--id app.id] [--template basic|full]\n appthen-extension dev [--port 5177] [--no-watch]\n appthen-extension doctor [--json]\n appthen-extension test [extensionId]\n appthen-extension validate\n appthen-extension build [extensionId]\n appthen-extension pack [extensionId] [--out .appthen/packages]\n appthen-extension publish [extensionId] --server <url> --tenant <tenantId> [--install-tenant] [--workbench <workbenchId>] [--tag dev] [--token <token>] [--skip-build]\n Publishes only by default. --install-tenant enables it for the tenant; --workbench is an isolated legacy path.\n appthen-extension install <package-file> --server <url> --tenant <tenantId> [--workbench <workbenchId>] [--token <token>]\n Installs to the tenant by default; --workbench limits the install to one workbench.\n`);\n}\n\nfunction readFlag(args: string[], name: string) {\n const index = args.indexOf(name);\n if (index === -1) return undefined;\n return args[index + 1];\n}\n\nfunction hasFlag(args: string[], name: string) {\n return args.includes(name);\n}\n\nfunction getWorkspaceRoot(cwd: string) {\n const root = findExtensionWorkspaceRoot(cwd);\n if (!root) {\n throw new Error('No appthen extension workspace found. Run appthen-extension init first.');\n }\n return root;\n}\n\nfunction selectEntries(cwd: string, extensionId?: string) {\n const workspaceRoot = getWorkspaceRoot(cwd);\n const entries = discoverExtensionWorkspace(workspaceRoot);\n const selected = extensionId\n ? entries.filter((entry) => entry.id === extensionId)\n : entries;\n if (selected.length === 0) {\n throw new Error(extensionId ? `Extension not found: ${extensionId}` : 'No extensions found.');\n }\n return { workspaceRoot, entries: selected };\n}\n\nfunction commandInit({ cwd, args }: CliOptions) {\n const targetDir = path.resolve(cwd, args[0] && !args[0].startsWith('--') ? args[0] : '.');\n const extensionId = readFlag(args, '--id') || 'acme.workbench-kit';\n const template = (readFlag(args, '--template') || 'basic') as ExtensionWorkspaceTemplate;\n if (template !== 'basic' && template !== 'full') {\n throw new Error(`Unknown template: ${template}`);\n }\n createExtensionWorkspace(targetDir, extensionId, template);\n console.log(`Created extension workspace at ${targetDir}`);\n console.log(template === 'full'\n ? 'Created full example extension workspace'\n : `Created example extension ${extensionId}`);\n}\n\nfunction commandValidate({ cwd }: CliOptions) {\n const result = validateExtensionWorkspace(cwd);\n result.warnings.forEach((warning) => console.warn(`Warning: ${warning}`));\n result.errors.forEach((error) => console.error(`Error: ${error}`));\n if (!result.valid) {\n process.exitCode = 1;\n return;\n }\n console.log('Extension workspace is valid.');\n}\n\nfunction collectDoctorReport(cwd: string) {\n const workspaceRoot = findExtensionWorkspaceRoot(cwd);\n if (!workspaceRoot) {\n return {\n valid: false,\n root: null,\n checks: [{ name: 'workspace', status: 'error', message: 'No appthen extension workspace found. Run appthen-extension init first.' }],\n };\n }\n\n const checks: Array<{ name: string; status: 'ok' | 'warning' | 'error'; message: string }> = [];\n const packagePath = path.join(workspaceRoot, 'package.json');\n const configPath = path.join(workspaceRoot, 'appthen-extension-workspace.json');\n const agentsPath = path.join(workspaceRoot, 'AGENTS.md');\n const readmePath = path.join(workspaceRoot, 'README.md');\n const packageJson = existsSync(packagePath)\n ? JSON.parse(readFileSync(packagePath, 'utf8')) as { scripts?: Record<string, string>; dependencies?: Record<string, string> }\n : null;\n\n checks.push({\n name: 'workspace',\n status: 'ok',\n message: workspaceRoot,\n });\n checks.push({\n name: 'config',\n status: existsSync(configPath) ? 'ok' : 'error',\n message: existsSync(configPath) ? 'appthen-extension-workspace.json found' : 'Missing appthen-extension-workspace.json',\n });\n checks.push({\n name: 'package',\n status: packageJson ? 'ok' : 'error',\n message: packageJson ? 'package.json found' : 'Missing package.json; run appthen-extension init',\n });\n checks.push({\n name: 'agent-guide',\n status: existsSync(agentsPath) ? 'ok' : 'warning',\n message: existsSync(agentsPath) ? 'AGENTS.md found' : 'AGENTS.md is missing; regenerate the workspace or add the Agent handoff guide',\n });\n checks.push({\n name: 'readme',\n status: existsSync(readmePath) ? 'ok' : 'warning',\n message: existsSync(readmePath) ? 'README.md found' : 'README.md is missing; regenerate the workspace or add the developer guide',\n });\n\n const entries = discoverExtensionWorkspace(workspaceRoot);\n const validation = validateExtensionWorkspace(workspaceRoot);\n checks.push({\n name: 'extensions',\n status: validation.valid ? 'ok' : 'error',\n message: validation.valid\n ? `${entries.length} extension(s) discovered`\n : validation.errors.join('; '),\n });\n\n const viteBin = path.join(workspaceRoot, 'node_modules', '.bin', process.platform === 'win32' ? 'vite.cmd' : 'vite');\n checks.push({\n name: 'dependencies',\n status: existsSync(viteBin) ? 'ok' : 'error',\n message: existsSync(viteBin)\n ? 'local Vite dependency is installed'\n : 'local dependencies are missing; run pnpm install before dev/build/test',\n });\n const cliBin = path.join(workspaceRoot, 'node_modules', '.bin', process.platform === 'win32' ? 'appthen-extension.cmd' : 'appthen-extension');\n checks.push({\n name: 'cli',\n status: existsSync(cliBin) ? 'ok' : 'error',\n message: existsSync(cliBin)\n ? 'appthen-extension binary is installed'\n : 'appthen-extension binary is missing; reinstall the workspace dependencies',\n });\n\n const requiredScripts = ['dev', 'validate', 'build', 'pack', 'publish'];\n const missingScripts = requiredScripts.filter((script) => !packageJson?.scripts?.[script]);\n checks.push({\n name: 'scripts',\n status: missingScripts.length === 0 ? 'ok' : 'warning',\n message: missingScripts.length === 0\n ? 'standard extension scripts are present'\n : `missing scripts: ${missingScripts.join(', ')}`,\n });\n\n return {\n valid: checks.every((check) => check.status !== 'error'),\n root: workspaceRoot,\n checks,\n };\n}\n\nfunction commandDoctor({ cwd, args }: CliOptions) {\n const report = collectDoctorReport(cwd);\n if (hasFlag(args, '--json')) {\n console.log(JSON.stringify(report, null, 2));\n } else {\n console.log(`Extension workspace: ${report.root || 'not found'}`);\n report.checks.forEach((check) => {\n console.log(`[${check.status.toUpperCase()}] ${check.name}: ${check.message}`);\n });\n }\n if (!report.valid) process.exitCode = 1;\n}\n\nfunction commandTest({ cwd, args }: CliOptions) {\n const extensionId = args[0] && !args[0].startsWith('--') ? args[0] : undefined;\n const report = collectDoctorReport(cwd);\n if (!report.valid) {\n report.checks\n .filter((check) => check.status === 'error')\n .forEach((check) => console.error(`Error: ${check.name}: ${check.message}`));\n process.exitCode = 1;\n return;\n }\n\n const { workspaceRoot, entries } = selectEntries(cwd, extensionId);\n const packageRoot = resolvePackageRoot();\n for (const entry of entries) {\n const build = buildExtension(entry, workspaceRoot, { bundle: true, packageRoot });\n const artifact = packExtension(entry, workspaceRoot, undefined, {\n bundle: false,\n useExistingBuild: true,\n packageRoot,\n });\n const entryPath = path.join(build.buildDir, artifact.runtime.entryFile);\n if (!existsSync(entryPath)) {\n throw new Error(`Smoke test failed for ${entry.id}: missing runtime entry ${artifact.runtime.entryFile}`);\n }\n if (!artifact.integrity.digest || artifact.files.length === 0) {\n throw new Error(`Smoke test failed for ${entry.id}: package integrity or files are missing`);\n }\n console.log(`Smoke tested ${entry.id}@${artifact.version}: build, pack, entry and integrity OK`);\n }\n console.log('Extension workspace smoke test passed.');\n}\n\nfunction commandBuild({ cwd, args }: CliOptions) {\n const extensionId = args[0] && !args[0].startsWith('--') ? args[0] : undefined;\n const { workspaceRoot, entries } = selectEntries(cwd, extensionId);\n const packageRoot = resolvePackageRoot();\n for (const entry of entries) {\n const result = buildExtension(entry, workspaceRoot, {\n bundle: true,\n packageRoot,\n });\n console.log(`Built ${result.id} -> ${path.relative(workspaceRoot, result.buildDir)}`);\n }\n}\n\nfunction commandPack({ cwd, args }: CliOptions) {\n const extensionId = args[0] && !args[0].startsWith('--') ? args[0] : undefined;\n const outDir = readFlag(args, '--out');\n const { workspaceRoot, entries } = selectEntries(cwd, extensionId);\n const packageRoot = resolvePackageRoot();\n for (const entry of entries) {\n const artifact = packExtension(entry, workspaceRoot, outDir, {\n bundle: true,\n packageRoot,\n });\n const targetDir = outDir ? path.resolve(workspaceRoot, outDir) : path.join(workspaceRoot, '.appthen', 'packages');\n const packagePath = path.join(targetDir, `${artifact.appId}-${artifact.version}${EXTENSION_PACKAGE_EXTENSION}`);\n console.log(`Packed ${artifact.appId}@${artifact.version} -> ${path.relative(workspaceRoot, packagePath)}`);\n }\n}\n\nfunction commandDev({ cwd, args }: CliOptions) {\n const workspaceRoot = getWorkspaceRoot(cwd);\n const port = readFlag(args, '--port') || '5177';\n const packageRoot = resolvePackageRoot();\n const { devRoot, count } = writeExtensionDevWorkbenchFiles(workspaceRoot, port, {\n packageRoot,\n });\n if (count === 0) {\n throw new Error('No local extensions found. Expected extensions/*/manifest.json.');\n }\n console.log(`Starting offline extension workbench with ${count} extension(s).`);\n console.log(`Dev app: ${devRoot}`);\n console.log(`Loaded extensions: ${discoverExtensionWorkspace(workspaceRoot).map((entry) => entry.id).join(', ')}`);\n\n let closeWatcher: (() => void) | undefined;\n if (!hasFlag(args, '--no-watch')) {\n closeWatcher = watchExtensionManifests(workspaceRoot, port, packageRoot);\n }\n\n const command = resolveViteCommand(workspaceRoot);\n const result = spawnSync(command, ['--host', '0.0.0.0', '--port', port], {\n cwd: devRoot,\n stdio: 'inherit',\n shell: process.platform === 'win32',\n });\n closeWatcher?.();\n process.exitCode = result.status ?? 1;\n}\n\nfunction resolveViteCommand(workspaceRoot: string) {\n const binName = process.platform === 'win32' ? 'vite.cmd' : 'vite';\n const candidates = [\n path.join(workspaceRoot, 'node_modules', '.bin', binName),\n path.join(resolvePackageRoot(), 'node_modules', '.bin', binName),\n ];\n return candidates.find((candidate) => existsSync(candidate)) || 'vite';\n}\n\nfunction resolvePackageRoot() {\n return path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');\n}\n\nfunction watchExtensionManifests(workspaceRoot: string, port: string, packageRoot?: string) {\n const extensionsRoot = path.join(workspaceRoot, 'extensions');\n if (!existsSync(extensionsRoot)) {\n return () => undefined;\n }\n\n let timer: NodeJS.Timeout | undefined;\n const watcher = watch(extensionsRoot, { recursive: true }, (_event, filename) => {\n if (filename && !String(filename).endsWith('manifest.json')) {\n return;\n }\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n try {\n const result = validateExtensionWorkspace(workspaceRoot);\n result.warnings.forEach((warning) => console.warn(`Warning: ${warning}`));\n if (!result.valid) {\n result.errors.forEach((error) => console.error(`Error: ${error}`));\n return;\n }\n writeExtensionDevWorkbenchFiles(workspaceRoot, port, { packageRoot });\n console.log(`Regenerated dev workbench entry for ${discoverExtensionWorkspace(workspaceRoot).length} extension(s).`);\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error));\n }\n }, 100);\n });\n\n return () => {\n if (timer) clearTimeout(timer);\n watcher.close();\n };\n}\n\nasync function commandInstall({ args }: CliOptions) {\n const packageFile = args[0];\n if (!packageFile || packageFile.startsWith('--')) {\n throw new Error('install requires a package file.');\n }\n const server = readFlag(args, '--server');\n const tenantId = readFlag(args, '--tenant');\n const workbenchId = readFlag(args, '--workbench');\n const token = readFlag(args, '--token') || process.env.APPTHEN_TOKEN;\n if (!server) throw new Error('install requires --server.');\n if (!tenantId) throw new Error('install requires --tenant.');\n if (workbenchId) {\n console.warn('Installing with --workbench is an isolated path; omit it for the default tenant-level install.');\n }\n\n const artifact = JSON.parse(readFileSync(path.resolve(packageFile), 'utf8'));\n const response = await fetch(`${server.replace(/\\/$/, '')}/marketplace/extensions/install-package`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n ...(token ? { authorization: `Bearer ${token}` } : {}),\n },\n body: JSON.stringify({\n tenantId,\n workbenchId,\n package: artifact,\n }),\n });\n\n if (!response.ok) {\n throw new Error(`Install failed: ${response.status} ${await response.text()}`);\n }\n console.log(await response.text());\n}\n\nasync function commandPublish({ cwd, args }: CliOptions) {\n const extensionId = args[0] && !args[0].startsWith('--') ? args[0] : undefined;\n const server = readFlag(args, '--server') || process.env.APPTHEN_SERVER || process.env.APPTHEN_API_BASE_URL;\n const tenantId = readFlag(args, '--tenant') || process.env.APPTHEN_TENANT_ID;\n const workbenchId = readFlag(args, '--workbench') || process.env.APPTHEN_WORKBENCH_ID;\n const installTenant = hasFlag(args, '--install-tenant') || Boolean(workbenchId);\n const token = readFlag(args, '--token') || process.env.APPTHEN_TOKEN;\n const tag = readFlag(args, '--tag') || 'dev';\n if (!server) throw new Error('publish requires --server or APPTHEN_SERVER.');\n if (!tenantId) throw new Error('publish requires --tenant or APPTHEN_TENANT_ID.');\n if (workbenchId) {\n console.warn('Publishing with --workbench is an isolated install path; prefer --install-tenant or a separate install command.');\n }\n\n const { workspaceRoot, entries } = selectEntries(cwd, extensionId);\n const packageRoot = resolvePackageRoot();\n for (const entry of entries) {\n const artifact = packExtension(entry, workspaceRoot, undefined, {\n bundle: !hasFlag(args, '--skip-build'),\n useExistingBuild: hasFlag(args, '--skip-build'),\n packageRoot,\n });\n const url = `${server.replace(/\\/$/, '')}/marketplace/tenants/${encodeURIComponent(tenantId)}/extensions/publish`;\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n ...(token ? { authorization: `Bearer ${token}` } : {}),\n },\n body: JSON.stringify({\n tenantId,\n tag,\n artifact,\n }),\n });\n\n if (!response.ok) {\n throw new Error(`Publish failed for ${artifact.appId}: ${response.status} ${await response.text()}`);\n }\n const published = await response.json();\n let installed;\n if (installTenant) {\n const installResponse = await fetch(\n `${server.replace(/\\/$/, '')}/marketplace/extensions/${encodeURIComponent(artifact.appId)}/install`,\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n ...(token ? { authorization: `Bearer ${token}` } : {}),\n },\n body: JSON.stringify({\n tenantId,\n ...(workbenchId ? { workbenchId } : {}),\n version: artifact.version,\n metadata: {\n source: 'appthen-extension-publish',\n tag,\n installScope: workbenchId ? 'workbench' : 'tenant',\n experimentalSourceAccepted: true,\n },\n }),\n },\n );\n if (!installResponse.ok) {\n throw new Error(`Install failed for ${artifact.appId}: ${installResponse.status} ${await installResponse.text()}`);\n }\n installed = await installResponse.json();\n }\n console.log(JSON.stringify({ published, ...(installed ? { installed } : {}) }, null, 2));\n }\n}\n\nasync function main() {\n const [, , command, ...args] = process.argv;\n const options = { cwd: process.cwd(), args };\n try {\n if (!command || command === '--help' || hasFlag(args, '--help') || command === 'help') {\n printUsage();\n return;\n }\n if (command === 'init') return commandInit(options);\n if (command === 'doctor') return commandDoctor(options);\n if (command === 'test') return commandTest(options);\n if (command === 'validate') return commandValidate(options);\n if (command === 'build') return commandBuild(options);\n if (command === 'pack') return commandPack(options);\n if (command === 'dev') return commandDev(options);\n if (command === 'install') return await commandInstall(options);\n if (command === 'publish') return await commandPublish(options);\n throw new Error(`Unknown command: ${command}`);\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error));\n process.exitCode = 1;\n }\n}\n\nvoid main();\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/extension-cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { spawnSync } from 'node:child_process';\nimport { watch } from 'node:fs';\nimport { existsSync, readFileSync } from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { writeExtensionDevWorkbenchFiles } from '@/extension-dev/devWorkbench';\nimport type { ExtensionWorkspaceTemplate } from '@/extension-dev/types';\nimport {\n EXTENSION_PACKAGE_EXTENSION,\n buildExtension,\n createExtensionWorkspace,\n discoverExtensionWorkspace,\n findExtensionWorkspaceRoot,\n packExtension,\n validateExtensionWorkspace,\n} from '@/extension-dev/workspace';\n\ninterface CliOptions {\n cwd: string;\n args: string[];\n}\n\nfunction printUsage() {\n console.log(`appthen-extension\n\nUsage:\n appthen-extension init [dir] [--id app.id] [--template basic|full]\n appthen-extension dev [--port 5177] [--no-watch] [--package-root <vibe-workspace-dir>]\n appthen-extension doctor [--json]\n appthen-extension test [extensionId]\n appthen-extension validate\n appthen-extension build [extensionId]\n appthen-extension pack [extensionId] [--out .appthen/packages]\n appthen-extension publish [extensionId] --server <url> --tenant <tenantId> [--install-tenant] [--workbench <workbenchId>] [--tag dev] [--token <token>] [--skip-build]\n Publishes only by default. --install-tenant enables it for the tenant; --workbench is an isolated legacy path.\n appthen-extension install <package-file> --server <url> --tenant <tenantId> [--workbench <workbenchId>] [--token <token>]\n Installs to the tenant by default; --workbench limits the install to one workbench.\n`);\n}\n\nfunction readFlag(args: string[], name: string) {\n const index = args.indexOf(name);\n if (index === -1) return undefined;\n return args[index + 1];\n}\n\nfunction hasFlag(args: string[], name: string) {\n return args.includes(name);\n}\n\nfunction getWorkspaceRoot(cwd: string) {\n const root = findExtensionWorkspaceRoot(cwd);\n if (!root) {\n throw new Error('No appthen extension workspace found. Run appthen-extension init first.');\n }\n return root;\n}\n\nfunction selectEntries(cwd: string, extensionId?: string) {\n const workspaceRoot = getWorkspaceRoot(cwd);\n const entries = discoverExtensionWorkspace(workspaceRoot);\n const selected = extensionId\n ? entries.filter((entry) => entry.id === extensionId)\n : entries;\n if (selected.length === 0) {\n throw new Error(extensionId ? `Extension not found: ${extensionId}` : 'No extensions found.');\n }\n return { workspaceRoot, entries: selected };\n}\n\nfunction commandInit({ cwd, args }: CliOptions) {\n const targetDir = path.resolve(cwd, args[0] && !args[0].startsWith('--') ? args[0] : '.');\n const extensionId = readFlag(args, '--id') || 'acme.workbench-kit';\n const template = (readFlag(args, '--template') || 'basic') as ExtensionWorkspaceTemplate;\n if (template !== 'basic' && template !== 'full') {\n throw new Error(`Unknown template: ${template}`);\n }\n createExtensionWorkspace(targetDir, extensionId, template);\n console.log(`Created extension workspace at ${targetDir}`);\n console.log(template === 'full'\n ? 'Created full example extension workspace'\n : `Created example extension ${extensionId}`);\n}\n\nfunction commandValidate({ cwd }: CliOptions) {\n const result = validateExtensionWorkspace(cwd);\n result.warnings.forEach((warning) => console.warn(`Warning: ${warning}`));\n result.errors.forEach((error) => console.error(`Error: ${error}`));\n if (!result.valid) {\n process.exitCode = 1;\n return;\n }\n console.log('Extension workspace is valid.');\n}\n\nfunction collectDoctorReport(cwd: string) {\n const workspaceRoot = findExtensionWorkspaceRoot(cwd);\n if (!workspaceRoot) {\n return {\n valid: false,\n root: null,\n checks: [{ name: 'workspace', status: 'error', message: 'No appthen extension workspace found. Run appthen-extension init first.' }],\n };\n }\n\n const checks: Array<{ name: string; status: 'ok' | 'warning' | 'error'; message: string }> = [];\n const packagePath = path.join(workspaceRoot, 'package.json');\n const configPath = path.join(workspaceRoot, 'appthen-extension-workspace.json');\n const agentsPath = path.join(workspaceRoot, 'AGENTS.md');\n const readmePath = path.join(workspaceRoot, 'README.md');\n const packageJson = existsSync(packagePath)\n ? JSON.parse(readFileSync(packagePath, 'utf8')) as { scripts?: Record<string, string>; dependencies?: Record<string, string> }\n : null;\n\n checks.push({\n name: 'workspace',\n status: 'ok',\n message: workspaceRoot,\n });\n checks.push({\n name: 'config',\n status: existsSync(configPath) ? 'ok' : 'error',\n message: existsSync(configPath) ? 'appthen-extension-workspace.json found' : 'Missing appthen-extension-workspace.json',\n });\n checks.push({\n name: 'package',\n status: packageJson ? 'ok' : 'error',\n message: packageJson ? 'package.json found' : 'Missing package.json; run appthen-extension init',\n });\n checks.push({\n name: 'agent-guide',\n status: existsSync(agentsPath) ? 'ok' : 'warning',\n message: existsSync(agentsPath) ? 'AGENTS.md found' : 'AGENTS.md is missing; regenerate the workspace or add the Agent handoff guide',\n });\n checks.push({\n name: 'readme',\n status: existsSync(readmePath) ? 'ok' : 'warning',\n message: existsSync(readmePath) ? 'README.md found' : 'README.md is missing; regenerate the workspace or add the developer guide',\n });\n\n const entries = discoverExtensionWorkspace(workspaceRoot);\n const validation = validateExtensionWorkspace(workspaceRoot);\n checks.push({\n name: 'extensions',\n status: validation.valid ? 'ok' : 'error',\n message: validation.valid\n ? `${entries.length} extension(s) discovered`\n : validation.errors.join('; '),\n });\n\n const viteBin = path.join(workspaceRoot, 'node_modules', '.bin', process.platform === 'win32' ? 'vite.cmd' : 'vite');\n checks.push({\n name: 'dependencies',\n status: existsSync(viteBin) ? 'ok' : 'error',\n message: existsSync(viteBin)\n ? 'local Vite dependency is installed'\n : 'local dependencies are missing; run pnpm install before dev/build/test',\n });\n const cliBin = path.join(workspaceRoot, 'node_modules', '.bin', process.platform === 'win32' ? 'appthen-extension.cmd' : 'appthen-extension');\n checks.push({\n name: 'cli',\n status: existsSync(cliBin) ? 'ok' : 'error',\n message: existsSync(cliBin)\n ? 'appthen-extension binary is installed'\n : 'appthen-extension binary is missing; reinstall the workspace dependencies',\n });\n\n const requiredScripts = ['dev', 'validate', 'build', 'pack', 'publish'];\n const missingScripts = requiredScripts.filter((script) => !packageJson?.scripts?.[script]);\n checks.push({\n name: 'scripts',\n status: missingScripts.length === 0 ? 'ok' : 'warning',\n message: missingScripts.length === 0\n ? 'standard extension scripts are present'\n : `missing scripts: ${missingScripts.join(', ')}`,\n });\n\n return {\n valid: checks.every((check) => check.status !== 'error'),\n root: workspaceRoot,\n checks,\n };\n}\n\nfunction commandDoctor({ cwd, args }: CliOptions) {\n const report = collectDoctorReport(cwd);\n if (hasFlag(args, '--json')) {\n console.log(JSON.stringify(report, null, 2));\n } else {\n console.log(`Extension workspace: ${report.root || 'not found'}`);\n report.checks.forEach((check) => {\n console.log(`[${check.status.toUpperCase()}] ${check.name}: ${check.message}`);\n });\n }\n if (!report.valid) process.exitCode = 1;\n}\n\nfunction commandTest({ cwd, args }: CliOptions) {\n const extensionId = args[0] && !args[0].startsWith('--') ? args[0] : undefined;\n const report = collectDoctorReport(cwd);\n if (!report.valid) {\n report.checks\n .filter((check) => check.status === 'error')\n .forEach((check) => console.error(`Error: ${check.name}: ${check.message}`));\n process.exitCode = 1;\n return;\n }\n\n const { workspaceRoot, entries } = selectEntries(cwd, extensionId);\n const packageRoot = resolvePackageRoot(readFlag(args, '--package-root'));\n for (const entry of entries) {\n const build = buildExtension(entry, workspaceRoot, { bundle: true, packageRoot });\n const artifact = packExtension(entry, workspaceRoot, undefined, {\n bundle: false,\n useExistingBuild: true,\n packageRoot,\n });\n const entryPath = path.join(build.buildDir, artifact.runtime.entryFile);\n if (!existsSync(entryPath)) {\n throw new Error(`Smoke test failed for ${entry.id}: missing runtime entry ${artifact.runtime.entryFile}`);\n }\n if (!artifact.integrity.digest || artifact.files.length === 0) {\n throw new Error(`Smoke test failed for ${entry.id}: package integrity or files are missing`);\n }\n console.log(`Smoke tested ${entry.id}@${artifact.version}: build, pack, entry and integrity OK`);\n }\n console.log('Extension workspace smoke test passed.');\n}\n\nfunction commandBuild({ cwd, args }: CliOptions) {\n const extensionId = args[0] && !args[0].startsWith('--') ? args[0] : undefined;\n const { workspaceRoot, entries } = selectEntries(cwd, extensionId);\n const packageRoot = resolvePackageRoot(readFlag(args, '--package-root'));\n for (const entry of entries) {\n const result = buildExtension(entry, workspaceRoot, {\n bundle: true,\n packageRoot,\n });\n console.log(`Built ${result.id} -> ${path.relative(workspaceRoot, result.buildDir)}`);\n }\n}\n\nfunction commandPack({ cwd, args }: CliOptions) {\n const extensionId = args[0] && !args[0].startsWith('--') ? args[0] : undefined;\n const outDir = readFlag(args, '--out');\n const { workspaceRoot, entries } = selectEntries(cwd, extensionId);\n const packageRoot = resolvePackageRoot(readFlag(args, '--package-root'));\n for (const entry of entries) {\n const artifact = packExtension(entry, workspaceRoot, outDir, {\n bundle: true,\n packageRoot,\n });\n const targetDir = outDir ? path.resolve(workspaceRoot, outDir) : path.join(workspaceRoot, '.appthen', 'packages');\n const packagePath = path.join(targetDir, `${artifact.appId}-${artifact.version}${EXTENSION_PACKAGE_EXTENSION}`);\n console.log(`Packed ${artifact.appId}@${artifact.version} -> ${path.relative(workspaceRoot, packagePath)}`);\n }\n}\n\nfunction commandDev({ cwd, args }: CliOptions) {\n const workspaceRoot = getWorkspaceRoot(cwd);\n const port = readFlag(args, '--port') || '5177';\n const packageRoot = resolvePackageRoot(readFlag(args, '--package-root'));\n const { devRoot, count } = writeExtensionDevWorkbenchFiles(workspaceRoot, port, {\n packageRoot,\n });\n if (count === 0) {\n throw new Error('No local extensions found. Expected extensions/*/manifest.json.');\n }\n console.log(`Starting offline extension workbench with ${count} extension(s).`);\n console.log(`Dev app: ${devRoot}`);\n console.log(`Loaded extensions: ${discoverExtensionWorkspace(workspaceRoot).map((entry) => entry.id).join(', ')}`);\n\n let closeWatcher: (() => void) | undefined;\n if (!hasFlag(args, '--no-watch')) {\n closeWatcher = watchExtensionManifests(workspaceRoot, port, packageRoot);\n }\n\n const command = resolveViteCommand(workspaceRoot, packageRoot);\n const result = spawnSync(command, ['--host', '0.0.0.0', '--port', port], {\n cwd: devRoot,\n stdio: 'inherit',\n shell: process.platform === 'win32',\n });\n closeWatcher?.();\n process.exitCode = result.status ?? 1;\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 path.join(packageRoot || resolvePackageRoot(), 'node_modules', '.bin', binName),\n ];\n return candidates.find((candidate) => existsSync(candidate)) || 'vite';\n}\n\nfunction resolvePackageRoot(explicitRoot?: string) {\n if (explicitRoot) return path.resolve(explicitRoot);\n if (process.env.APPTHEN_VIBE_WORKSPACE_ROOT) {\n return path.resolve(process.env.APPTHEN_VIBE_WORKSPACE_ROOT);\n }\n return path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');\n}\n\nfunction watchExtensionManifests(workspaceRoot: string, port: string, packageRoot?: string) {\n const extensionsRoot = path.join(workspaceRoot, 'extensions');\n if (!existsSync(extensionsRoot)) {\n return () => undefined;\n }\n\n let timer: NodeJS.Timeout | undefined;\n const watcher = watch(extensionsRoot, { recursive: true }, (_event, filename) => {\n if (filename && !String(filename).endsWith('manifest.json')) {\n return;\n }\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n try {\n const result = validateExtensionWorkspace(workspaceRoot);\n result.warnings.forEach((warning) => console.warn(`Warning: ${warning}`));\n if (!result.valid) {\n result.errors.forEach((error) => console.error(`Error: ${error}`));\n return;\n }\n writeExtensionDevWorkbenchFiles(workspaceRoot, port, { packageRoot });\n console.log(`Regenerated dev workbench entry for ${discoverExtensionWorkspace(workspaceRoot).length} extension(s).`);\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error));\n }\n }, 100);\n });\n\n return () => {\n if (timer) clearTimeout(timer);\n watcher.close();\n };\n}\n\nasync function commandInstall({ args }: CliOptions) {\n const packageFile = args[0];\n if (!packageFile || packageFile.startsWith('--')) {\n throw new Error('install requires a package file.');\n }\n const server = readFlag(args, '--server');\n const tenantId = readFlag(args, '--tenant');\n const workbenchId = readFlag(args, '--workbench');\n const token = readFlag(args, '--token') || process.env.APPTHEN_TOKEN;\n if (!server) throw new Error('install requires --server.');\n if (!tenantId) throw new Error('install requires --tenant.');\n if (workbenchId) {\n console.warn('Installing with --workbench is an isolated path; omit it for the default tenant-level install.');\n }\n\n const artifact = JSON.parse(readFileSync(path.resolve(packageFile), 'utf8'));\n const response = await fetch(`${server.replace(/\\/$/, '')}/marketplace/extensions/install-package`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n ...(token ? { authorization: `Bearer ${token}` } : {}),\n },\n body: JSON.stringify({\n tenantId,\n workbenchId,\n package: artifact,\n }),\n });\n\n if (!response.ok) {\n throw new Error(`Install failed: ${response.status} ${await response.text()}`);\n }\n console.log(await response.text());\n}\n\nasync function commandPublish({ cwd, args }: CliOptions) {\n const extensionId = args[0] && !args[0].startsWith('--') ? args[0] : undefined;\n const server = readFlag(args, '--server') || process.env.APPTHEN_SERVER || process.env.APPTHEN_API_BASE_URL;\n const tenantId = readFlag(args, '--tenant') || process.env.APPTHEN_TENANT_ID;\n const workbenchId = readFlag(args, '--workbench') || process.env.APPTHEN_WORKBENCH_ID;\n const installTenant = hasFlag(args, '--install-tenant') || Boolean(workbenchId);\n const token = readFlag(args, '--token') || process.env.APPTHEN_TOKEN;\n const tag = readFlag(args, '--tag') || 'dev';\n if (!server) throw new Error('publish requires --server or APPTHEN_SERVER.');\n if (!tenantId) throw new Error('publish requires --tenant or APPTHEN_TENANT_ID.');\n if (workbenchId) {\n console.warn('Publishing with --workbench is an isolated install path; prefer --install-tenant or a separate install command.');\n }\n\n const { workspaceRoot, entries } = selectEntries(cwd, extensionId);\n const packageRoot = resolvePackageRoot(readFlag(args, '--package-root'));\n for (const entry of entries) {\n const artifact = packExtension(entry, workspaceRoot, undefined, {\n bundle: !hasFlag(args, '--skip-build'),\n useExistingBuild: hasFlag(args, '--skip-build'),\n packageRoot,\n });\n const url = `${server.replace(/\\/$/, '')}/marketplace/tenants/${encodeURIComponent(tenantId)}/extensions/publish`;\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n ...(token ? { authorization: `Bearer ${token}` } : {}),\n },\n body: JSON.stringify({\n tenantId,\n tag,\n artifact,\n }),\n });\n\n if (!response.ok) {\n throw new Error(`Publish failed for ${artifact.appId}: ${response.status} ${await response.text()}`);\n }\n const published = await response.json();\n let installed;\n if (installTenant) {\n const installResponse = await fetch(\n `${server.replace(/\\/$/, '')}/marketplace/extensions/${encodeURIComponent(artifact.appId)}/install`,\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n ...(token ? { authorization: `Bearer ${token}` } : {}),\n },\n body: JSON.stringify({\n tenantId,\n ...(workbenchId ? { workbenchId } : {}),\n version: artifact.version,\n metadata: {\n source: 'appthen-extension-publish',\n tag,\n installScope: workbenchId ? 'workbench' : 'tenant',\n experimentalSourceAccepted: true,\n },\n }),\n },\n );\n if (!installResponse.ok) {\n throw new Error(`Install failed for ${artifact.appId}: ${installResponse.status} ${await installResponse.text()}`);\n }\n installed = await installResponse.json();\n }\n console.log(JSON.stringify({ published, ...(installed ? { installed } : {}) }, null, 2));\n }\n}\n\nasync function main() {\n const [, , command, ...args] = process.argv;\n const options = { cwd: process.cwd(), args };\n try {\n if (!command || command === '--help' || hasFlag(args, '--help') || command === 'help') {\n printUsage();\n return;\n }\n if (command === 'init') return commandInit(options);\n if (command === 'doctor') return commandDoctor(options);\n if (command === 'test') return commandTest(options);\n if (command === 'validate') return commandValidate(options);\n if (command === 'build') return commandBuild(options);\n if (command === 'pack') return commandPack(options);\n if (command === 'dev') return commandDev(options);\n if (command === 'install') return await commandInstall(options);\n if (command === 'publish') return await commandPublish(options);\n throw new Error(`Unknown command: ${command}`);\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error));\n process.exitCode = 1;\n }\n}\n\nvoid main();\n"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { E, a, b, c, d, f, l, p, v, e, w } from "../devWorkbench-BmYheR6S.js";
1
+ import { E, a, b, c, d, f, l, p, v, e, w } from "../devWorkbench-C-rC8sz8.js";
2
2
  export {
3
3
  E as EXTENSION_PACKAGE_EXTENSION,
4
4
  a as EXTENSION_WORKSPACE_CONFIG,