@databricks/appkit-ui 0.47.1 → 0.49.0

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.
Files changed (42) hide show
  1. package/CLAUDE.md +11 -1
  2. package/dist/cli/commands/lint.js +6 -0
  3. package/dist/cli/commands/lint.js.map +1 -1
  4. package/dist/react/index.d.ts +4 -1
  5. package/dist/react/index.js +3 -1
  6. package/dist/react/ui-variants/index.d.ts +2 -0
  7. package/dist/react/ui-variants/variant.d.ts +21 -0
  8. package/dist/react/ui-variants/variant.d.ts.map +1 -0
  9. package/dist/react/ui-variants/variant.js +15 -0
  10. package/dist/react/ui-variants/variant.js.map +1 -0
  11. package/dist/react/ui-variants/variants.d.ts +87 -0
  12. package/dist/react/ui-variants/variants.d.ts.map +1 -0
  13. package/dist/react/ui-variants/variants.js +199 -0
  14. package/dist/react/ui-variants/variants.js.map +1 -0
  15. package/dist/schemas/manifest.d.ts +1 -0
  16. package/dist/schemas/manifest.d.ts.map +1 -1
  17. package/dist/schemas/manifest.js +1 -0
  18. package/dist/schemas/manifest.js.map +1 -1
  19. package/dist/shared/src/plugin.d.ts.map +1 -1
  20. package/docs/api/appkit/Class.DatabricksAdapter.md +34 -0
  21. package/docs/api/appkit/Class.SupervisorApiAdapter.md +121 -0
  22. package/docs/api/appkit/Function.fromSupervisorApi.md +63 -0
  23. package/docs/api/appkit/Function.isSupervisorTool.md +18 -0
  24. package/docs/api/appkit/Interface.AgentAdapter.md +24 -0
  25. package/docs/api/appkit/Interface.AgentInput.md +13 -0
  26. package/docs/api/appkit/Interface.HostedSupervisorTool.md +21 -0
  27. package/docs/api/appkit/Interface.PluginManifest.md +27 -9
  28. package/docs/api/appkit/Interface.SupervisorApiAdapterOptions.md +38 -0
  29. package/docs/api/appkit/Interface.SupervisorExtension.md +12 -0
  30. package/docs/api/appkit/Interface.WorkspaceClientLike.md +67 -0
  31. package/docs/api/appkit/TypeAlias.AgentTool.md +3 -2
  32. package/docs/api/appkit/TypeAlias.ResolvedToolEntry.md +167 -0
  33. package/docs/api/appkit/TypeAlias.SupervisorTool.md +45 -0
  34. package/docs/api/appkit/Variable.SUPERVISOR_EXTENSION_KEY.md +8 -0
  35. package/docs/api/appkit/Variable.supervisorTools.md +176 -0
  36. package/docs/api/appkit.md +118 -108
  37. package/docs/plugins/agents.md +131 -1
  38. package/docs/plugins/manifest.md +12 -11
  39. package/llms.txt +11 -1
  40. package/package.json +1 -1
  41. package/sbom.cdx.json +1 -1
  42. package/scripts/postinstall.js +0 -1
package/CLAUDE.md CHANGED
@@ -74,6 +74,7 @@ npx @databricks/appkit docs <query>
74
74
  - [Class: PolicyDeniedError](./docs/api/appkit/Class.PolicyDeniedError.md): Thrown when a policy denies an action.
75
75
  - [Class: ResourceRegistry](./docs/api/appkit/Class.ResourceRegistry.md): Central registry for tracking plugin resource requirements.
76
76
  - [Class: ServerError](./docs/api/appkit/Class.ServerError.md): Error thrown when server lifecycle operations fail.
77
+ - [Class: SupervisorApiAdapter](./docs/api/appkit/Class.SupervisorApiAdapter.md): Adapter that calls the Databricks AI Gateway Responses API
77
78
  - [Class: TunnelError](./docs/api/appkit/Class.TunnelError.md): Error thrown when remote tunnel operations fail.
78
79
  - [Class: ValidationError](./docs/api/appkit/Class.ValidationError.md): Error thrown when input validation fails.
79
80
  - [Enumeration: RequestedClaimsPermissionSet](./docs/api/appkit/Enumeration.RequestedClaimsPermissionSet.md): Permission set for Unity Catalog table access
@@ -89,6 +90,7 @@ npx @databricks/appkit docs <query>
89
90
  - [Function: executeFromRegistry()](./docs/api/appkit/Function.executeFromRegistry.md): Validates tool-call arguments against the entry's schema and invokes its
90
91
  - [Function: extractServingEndpoints()](./docs/api/appkit/Function.extractServingEndpoints.md): Extract serving endpoint config from a server file by AST-parsing it.
91
92
  - [Function: findServerFile()](./docs/api/appkit/Function.findServerFile.md): Find the server entry file by checking candidate paths in order.
93
+ - [Function: fromSupervisorApi()](./docs/api/appkit/Function.fromSupervisorApi.md): Creates an AgentAdapter backed by the Databricks AI Gateway
92
94
  - [Function: functionToolToDefinition()](./docs/api/appkit/Function.functionToolToDefinition.md): Parameters
93
95
  - [Function: generateDatabaseCredential()](./docs/api/appkit/Function.generateDatabaseCredential.md): Generate OAuth credentials for Postgres database connection using the proper Postgres API.
94
96
  - [Function: getExecutionContext()](./docs/api/appkit/Function.getExecutionContext.md): Get the current execution context.
@@ -101,6 +103,7 @@ npx @databricks/appkit docs <query>
101
103
  - [Function: isFunctionTool()](./docs/api/appkit/Function.isFunctionTool.md): Parameters
102
104
  - [Function: isHostedTool()](./docs/api/appkit/Function.isHostedTool.md): Parameters
103
105
  - [Function: isSQLTypeMarker()](./docs/api/appkit/Function.isSQLTypeMarker.md): Type guard to check if a value is a SQL type marker
106
+ - [Function: isSupervisorTool()](./docs/api/appkit/Function.isSupervisorTool.md): Type guard for HostedSupervisorTool. Used by the agents plugin
104
107
  - [Function: isToolkitEntry()](./docs/api/appkit/Function.isToolkitEntry.md): Type guard for ToolkitEntry — used by the agents plugin to differentiate
105
108
  - [Function: loadAgentFromFile()](./docs/api/appkit/Function.loadAgentFromFile.md): Loads a single markdown agent file and resolves its frontmatter against
106
109
  - [Function: loadAgentsFromDir()](./docs/api/appkit/Function.loadAgentsFromDir.md): Scans a directory for one subdirectory per agent, each containing
@@ -110,7 +113,7 @@ npx @databricks/appkit docs <query>
110
113
  - [Function: runAgent()](./docs/api/appkit/Function.runAgent.md): Standalone agent execution without createApp. Resolves the adapter, binds
111
114
  - [Function: tool()](./docs/api/appkit/Function.tool.md): Factory for defining function tools with Zod schemas.
112
115
  - [Function: toolsFromRegistry()](./docs/api/appkit/Function.toolsFromRegistry.md): Produces the AgentToolDefinition[] a ToolProvider exposes to the LLM,
113
- - [Interface: AgentAdapter](./docs/api/appkit/Interface.AgentAdapter.md): Methods
116
+ - [Interface: AgentAdapter](./docs/api/appkit/Interface.AgentAdapter.md): Properties
114
117
  - [Interface: AgentDefinition](./docs/api/appkit/Interface.AgentDefinition.md): Properties
115
118
  - [Interface: AgentInput](./docs/api/appkit/Interface.AgentInput.md): Properties
116
119
  - [Interface: AgentRunContext](./docs/api/appkit/Interface.AgentRunContext.md): Properties
@@ -126,6 +129,7 @@ npx @databricks/appkit docs <query>
126
129
  - [Interface: FunctionTool](./docs/api/appkit/Interface.FunctionTool.md): Properties
127
130
  - [Interface: GenerateDatabaseCredentialRequest](./docs/api/appkit/Interface.GenerateDatabaseCredentialRequest.md): Request parameters for generating database OAuth credentials
128
131
  - [Interface: GenerationParams](./docs/api/appkit/Interface.GenerationParams.md): Optional generation parameters forwarded to the OpenAI-compatible serving
132
+ - [Interface: HostedSupervisorTool](./docs/api/appkit/Interface.HostedSupervisorTool.md): Tagged record returned by every supervisorTools factory. The
129
133
  - [Interface: IJobsConfig](./docs/api/appkit/Interface.IJobsConfig.md): Configuration for the Jobs plugin.
130
134
  - [Interface: ITelemetry](./docs/api/appkit/Interface.ITelemetry.md): Plugin-facing interface for OpenTelemetry instrumentation.
131
135
  - [Interface: JobAPI](./docs/api/appkit/Interface.JobAPI.md): User-facing API for a single configured job.
@@ -149,6 +153,8 @@ npx @databricks/appkit docs <query>
149
153
  - [Interface: ServingEndpointEntry](./docs/api/appkit/Interface.ServingEndpointEntry.md): Shape of a single registry entry.
150
154
  - [Interface: ServingEndpointRegistry](./docs/api/appkit/Interface.ServingEndpointRegistry.md): Registry interface for serving endpoint type generation.
151
155
  - [Interface: StreamExecutionSettings](./docs/api/appkit/Interface.StreamExecutionSettings.md): Execution settings for streaming endpoints. Extends PluginExecutionSettings with SSE stream configuration.
156
+ - [Interface: SupervisorApiAdapterOptions](./docs/api/appkit/Interface.SupervisorApiAdapterOptions.md): Properties
157
+ - [Interface: SupervisorExtension](./docs/api/appkit/Interface.SupervisorExtension.md): Shape of the value at AgentInput.extensions[SUPERVISOREXTENSIONKEY].
152
158
  - [Interface: TelemetryConfig](./docs/api/appkit/Interface.TelemetryConfig.md): OpenTelemetry configuration for AppKit applications
153
159
  - [Interface: Thread](./docs/api/appkit/Interface.Thread.md): Properties
154
160
  - [Interface: ThreadStore](./docs/api/appkit/Interface.ThreadStore.md): Methods
@@ -159,6 +165,7 @@ npx @databricks/appkit docs <query>
159
165
  - [Interface: ToolkitOptions](./docs/api/appkit/Interface.ToolkitOptions.md): Properties
160
166
  - [Interface: ToolProvider](./docs/api/appkit/Interface.ToolProvider.md): Methods
161
167
  - [Interface: ValidationResult](./docs/api/appkit/Interface.ValidationResult.md): Result of validating all registered resources against the environment.
168
+ - [Interface: WorkspaceClientLike](./docs/api/appkit/Interface.WorkspaceClientLike.md): Structural shape of a Databricks SDK client used by fromSupervisorApi.
162
169
  - [Type Alias: AgentEvent](./docs/api/appkit/TypeAlias.AgentEvent.md): Type Declaration
163
170
  - [Type Alias: AgentTool](./docs/api/appkit/TypeAlias.AgentTool.md): Any tool an agent can invoke: inline function tools (tool()), hosted MCP
164
171
  - [Type Alias: AgentTools](./docs/api/appkit/TypeAlias.AgentTools.md): Per-agent tool record. String keys map to inline tools, toolkit entries,
@@ -178,11 +185,14 @@ npx @databricks/appkit docs <query>
178
185
  - [Type Alias: ResourceFieldEntry](./docs/api/appkit/TypeAlias.ResourceFieldEntry.md)
179
186
  - [Type Alias: ResourcePermission](./docs/api/appkit/TypeAlias.ResourcePermission.md): Union of all possible permission levels across all resource types.
180
187
  - [Type Alias: ServingFactory](./docs/api/appkit/TypeAlias.ServingFactory.md): Factory function returned by AppKit.serving.
188
+ - [Type Alias: SupervisorTool](./docs/api/appkit/TypeAlias.SupervisorTool.md): Tools supported by the Databricks AI Gateway Responses API. The shapes match
181
189
  - [Type Alias: ToolRegistry](./docs/api/appkit/TypeAlias.ToolRegistry.md)
182
190
  - [Type Alias: ToPlugin()<T, U, N>](./docs/api/appkit/TypeAlias.ToPlugin.md): Factory function type returned by toPlugin(). Accepts optional config and returns a PluginData tuple.
183
191
  - [Variable: agents](./docs/api/appkit/Variable.agents.md): Plugin factory for the agents plugin. Reads config/agents/*.md by default,
184
192
  - [Variable: READ_ACTIONS](./docs/api/appkit/Variable.READ_ACTIONS.md): Actions that only read data.
185
193
  - [Variable: sql](./docs/api/appkit/Variable.sql.md): SQL helper namespace
194
+ - [Variable: SUPERVISOR_EXTENSION_KEY](./docs/api/appkit/Variable.SUPERVISOR_EXTENSION_KEY.md): Namespace key under which the adapter reads its hosted-tool payload
195
+ - [Variable: supervisorTools](./docs/api/appkit/Variable.supervisorTools.md): Concise factories for declaring Supervisor API tools.
186
196
  - [Variable: WRITE_ACTIONS](./docs/api/appkit/Variable.WRITE_ACTIONS.md): Actions that mutate data.
187
197
 
188
198
  ## appkit-ui API reference [collapsed]
@@ -26,6 +26,12 @@ const rules = [
26
26
  id: "no-parse-float-without-validation",
27
27
  pattern: "parseFloat($X).toFixed($Y)",
28
28
  message: "parseFloat can return NaN. Validate input or use toNumber() helper from shared/types.ts."
29
+ },
30
+ {
31
+ id: "no-variants-in-prod",
32
+ pattern: "<Variants $$$P>$$$C</Variants>",
33
+ message: "<Variants> is a development-only variant picker and must not be shipped. Finalize the chosen <Variant> before deploying.",
34
+ includeTests: false
29
35
  }
30
36
  ];
31
37
  function isTestFile(filePath, rootDir) {
@@ -1 +1 @@
1
- {"version":3,"file":"lint.js","names":[],"sources":["../../../src/cli/commands/lint.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Lang, parse } from \"@ast-grep/napi\";\nimport { Command } from \"commander\";\n\ninterface Rule {\n id: string;\n pattern: string;\n message: string;\n includeTests?: boolean;\n filter?: (code: string) => boolean;\n}\n\nconst rules: Rule[] = [\n {\n id: \"no-double-type-assertion\",\n pattern: \"$X as unknown as $Y\",\n message:\n \"Avoid double type assertion (as unknown as). Use proper type guards or fix the source type.\",\n },\n {\n id: \"no-as-any\",\n pattern: \"$X as any\",\n message:\n 'Avoid \"as any\" type assertion. Use proper typing or unknown with type guards.',\n includeTests: false, // acceptable in test mocks\n },\n {\n id: \"no-array-index-key\",\n pattern: \"key={$IDX}\",\n message:\n \"Avoid using array index as React key. Use a stable unique identifier.\",\n filter: (code) => /key=\\{(idx|index|i)\\}/.test(code),\n },\n {\n id: \"no-parse-float-without-validation\",\n pattern: \"parseFloat($X).toFixed($Y)\",\n message:\n \"parseFloat can return NaN. Validate input or use toNumber() helper from shared/types.ts.\",\n },\n];\n\nfunction isTestFile(filePath: string, rootDir: string): boolean {\n // Relative to scan root: an ancestor `tests` dir must not mark the whole project as tests.\n const rel = path.relative(rootDir, filePath);\n return (\n /\\.(test|spec)\\.(ts|tsx)$/.test(rel) || /(^|[/\\\\])tests[/\\\\]/.test(rel)\n );\n}\n\nfunction findTsFiles(dir: string, files: string[] = []): string[] {\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n if ([\"node_modules\", \"dist\", \"build\", \".git\"].includes(entry.name))\n continue;\n findTsFiles(fullPath, files);\n } else if (entry.isFile() && /\\.(ts|tsx)$/.test(entry.name)) {\n files.push(fullPath);\n }\n }\n\n return files;\n}\n\ninterface Violation {\n file: string;\n line: number;\n column: number;\n rule: string;\n message: string;\n code: string;\n}\n\nfunction lintFile(\n filePath: string,\n rules: Rule[],\n rootDir: string,\n): Violation[] {\n const violations: Violation[] = [];\n const content = fs.readFileSync(filePath, \"utf-8\");\n const lang = filePath.endsWith(\".tsx\") ? Lang.Tsx : Lang.TypeScript;\n const testFile = isTestFile(filePath, rootDir);\n\n const ast = parse(lang, content);\n const root = ast.root();\n\n for (const rule of rules) {\n // skip rules that don't apply to test files\n if (testFile && rule.includeTests === false) continue;\n\n const matches = root.findAll(rule.pattern);\n\n for (const match of matches) {\n const code = match.text();\n\n if (rule.filter && !rule.filter(code)) continue;\n\n const range = match.range();\n violations.push({\n file: filePath,\n line: range.start.line + 1,\n column: range.start.column + 1,\n rule: rule.id,\n message: rule.message,\n code: code.length > 80 ? `${code.slice(0, 77)}...` : code,\n });\n }\n }\n\n return violations;\n}\n\n/**\n * Lint command implementation\n */\nfunction runLint() {\n const rootDir = process.cwd();\n const files = findTsFiles(rootDir);\n\n console.log(`Scanning ${files.length} TypeScript files...\\n`);\n\n const allViolations: Violation[] = [];\n\n for (const file of files) {\n const violations = lintFile(file, rules, rootDir);\n allViolations.push(...violations);\n }\n\n if (allViolations.length === 0) {\n console.log(\"No ast-grep lint violations found.\");\n process.exit(0);\n }\n\n console.log(`Found ${allViolations.length} violation(s):\\n`);\n\n for (const v of allViolations) {\n const relPath = path.relative(rootDir, v.file);\n console.log(`${relPath}:${v.line}:${v.column}`);\n console.log(` ${v.rule}: ${v.message}`);\n console.log(` > ${v.code}\\n`);\n }\n\n process.exit(1);\n}\n\nexport const lintCommand = new Command(\"lint\")\n .description(\"Run AST-based linting on TypeScript files\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ appkit lint`,\n )\n .action(runLint);\n"],"mappings":";;;;;;AAaA,MAAM,QAAgB;CACpB;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACH;CACD;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACF,cAAc;EACf;CACD;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACF,SAAS,SAAS,wBAAwB,KAAK,KAAK;EACrD;CACD;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACH;CACF;AAED,SAAS,WAAW,UAAkB,SAA0B;CAE9D,MAAM,MAAM,KAAK,SAAS,SAAS,SAAS;AAC5C,QACE,2BAA2B,KAAK,IAAI,IAAI,sBAAsB,KAAK,IAAI;;AAI3E,SAAS,YAAY,KAAa,QAAkB,EAAE,EAAY;CAChE,MAAM,UAAU,GAAG,YAAY,KAAK,EAAE,eAAe,MAAM,CAAC;AAE5D,MAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,WAAW,KAAK,KAAK,KAAK,MAAM,KAAK;AAE3C,MAAI,MAAM,aAAa,EAAE;AACvB,OAAI;IAAC;IAAgB;IAAQ;IAAS;IAAO,CAAC,SAAS,MAAM,KAAK,CAChE;AACF,eAAY,UAAU,MAAM;aACnB,MAAM,QAAQ,IAAI,cAAc,KAAK,MAAM,KAAK,CACzD,OAAM,KAAK,SAAS;;AAIxB,QAAO;;AAYT,SAAS,SACP,UACA,OACA,SACa;CACb,MAAM,aAA0B,EAAE;CAClC,MAAM,UAAU,GAAG,aAAa,UAAU,QAAQ;CAClD,MAAM,OAAO,SAAS,SAAS,OAAO,GAAG,KAAK,MAAM,KAAK;CACzD,MAAM,WAAW,WAAW,UAAU,QAAQ;CAG9C,MAAM,OADM,MAAM,MAAM,QAAQ,CACf,MAAM;AAEvB,MAAK,MAAM,QAAQ,OAAO;AAExB,MAAI,YAAY,KAAK,iBAAiB,MAAO;EAE7C,MAAM,UAAU,KAAK,QAAQ,KAAK,QAAQ;AAE1C,OAAK,MAAM,SAAS,SAAS;GAC3B,MAAM,OAAO,MAAM,MAAM;AAEzB,OAAI,KAAK,UAAU,CAAC,KAAK,OAAO,KAAK,CAAE;GAEvC,MAAM,QAAQ,MAAM,OAAO;AAC3B,cAAW,KAAK;IACd,MAAM;IACN,MAAM,MAAM,MAAM,OAAO;IACzB,QAAQ,MAAM,MAAM,SAAS;IAC7B,MAAM,KAAK;IACX,SAAS,KAAK;IACd,MAAM,KAAK,SAAS,KAAK,GAAG,KAAK,MAAM,GAAG,GAAG,CAAC,OAAO;IACtD,CAAC;;;AAIN,QAAO;;;;;AAMT,SAAS,UAAU;CACjB,MAAM,UAAU,QAAQ,KAAK;CAC7B,MAAM,QAAQ,YAAY,QAAQ;AAElC,SAAQ,IAAI,YAAY,MAAM,OAAO,wBAAwB;CAE7D,MAAM,gBAA6B,EAAE;AAErC,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,aAAa,SAAS,MAAM,OAAO,QAAQ;AACjD,gBAAc,KAAK,GAAG,WAAW;;AAGnC,KAAI,cAAc,WAAW,GAAG;AAC9B,UAAQ,IAAI,qCAAqC;AACjD,UAAQ,KAAK,EAAE;;AAGjB,SAAQ,IAAI,SAAS,cAAc,OAAO,kBAAkB;AAE5D,MAAK,MAAM,KAAK,eAAe;EAC7B,MAAM,UAAU,KAAK,SAAS,SAAS,EAAE,KAAK;AAC9C,UAAQ,IAAI,GAAG,QAAQ,GAAG,EAAE,KAAK,GAAG,EAAE,SAAS;AAC/C,UAAQ,IAAI,KAAK,EAAE,KAAK,IAAI,EAAE,UAAU;AACxC,UAAQ,IAAI,OAAO,EAAE,KAAK,IAAI;;AAGhC,SAAQ,KAAK,EAAE;;AAGjB,MAAa,cAAc,IAAI,QAAQ,OAAO,CAC3C,YAAY,4CAA4C,CACxD,YACC,SACA;;iBAGD,CACA,OAAO,QAAQ"}
1
+ {"version":3,"file":"lint.js","names":[],"sources":["../../../src/cli/commands/lint.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Lang, parse } from \"@ast-grep/napi\";\nimport { Command } from \"commander\";\n\ninterface Rule {\n id: string;\n pattern: string;\n message: string;\n includeTests?: boolean;\n filter?: (code: string) => boolean;\n}\n\nconst rules: Rule[] = [\n {\n id: \"no-double-type-assertion\",\n pattern: \"$X as unknown as $Y\",\n message:\n \"Avoid double type assertion (as unknown as). Use proper type guards or fix the source type.\",\n },\n {\n id: \"no-as-any\",\n pattern: \"$X as any\",\n message:\n 'Avoid \"as any\" type assertion. Use proper typing or unknown with type guards.',\n includeTests: false, // acceptable in test mocks\n },\n {\n id: \"no-array-index-key\",\n pattern: \"key={$IDX}\",\n message:\n \"Avoid using array index as React key. Use a stable unique identifier.\",\n filter: (code) => /key=\\{(idx|index|i)\\}/.test(code),\n },\n {\n id: \"no-parse-float-without-validation\",\n pattern: \"parseFloat($X).toFixed($Y)\",\n message:\n \"parseFloat can return NaN. Validate input or use toNumber() helper from shared/types.ts.\",\n },\n {\n // <Variants> is the dev-only variant picker from @databricks/appkit-ui,\n // meant to drive the local edit loop. Finalize the chosen variant before\n // deploying so the picker chrome never reaches production.\n id: \"no-variants-in-prod\",\n pattern: \"<Variants $$$P>$$$C</Variants>\",\n message:\n \"<Variants> is a development-only variant picker and must not be shipped. Finalize the chosen <Variant> before deploying.\",\n includeTests: false,\n },\n];\n\nfunction isTestFile(filePath: string, rootDir: string): boolean {\n // Relative to scan root: an ancestor `tests` dir must not mark the whole project as tests.\n const rel = path.relative(rootDir, filePath);\n return (\n /\\.(test|spec)\\.(ts|tsx)$/.test(rel) || /(^|[/\\\\])tests[/\\\\]/.test(rel)\n );\n}\n\nfunction findTsFiles(dir: string, files: string[] = []): string[] {\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n if ([\"node_modules\", \"dist\", \"build\", \".git\"].includes(entry.name))\n continue;\n findTsFiles(fullPath, files);\n } else if (entry.isFile() && /\\.(ts|tsx)$/.test(entry.name)) {\n files.push(fullPath);\n }\n }\n\n return files;\n}\n\ninterface Violation {\n file: string;\n line: number;\n column: number;\n rule: string;\n message: string;\n code: string;\n}\n\nfunction lintFile(\n filePath: string,\n rules: Rule[],\n rootDir: string,\n): Violation[] {\n const violations: Violation[] = [];\n const content = fs.readFileSync(filePath, \"utf-8\");\n const lang = filePath.endsWith(\".tsx\") ? Lang.Tsx : Lang.TypeScript;\n const testFile = isTestFile(filePath, rootDir);\n\n const ast = parse(lang, content);\n const root = ast.root();\n\n for (const rule of rules) {\n // skip rules that don't apply to test files\n if (testFile && rule.includeTests === false) continue;\n\n const matches = root.findAll(rule.pattern);\n\n for (const match of matches) {\n const code = match.text();\n\n if (rule.filter && !rule.filter(code)) continue;\n\n const range = match.range();\n violations.push({\n file: filePath,\n line: range.start.line + 1,\n column: range.start.column + 1,\n rule: rule.id,\n message: rule.message,\n code: code.length > 80 ? `${code.slice(0, 77)}...` : code,\n });\n }\n }\n\n return violations;\n}\n\n/**\n * Lint command implementation\n */\nfunction runLint() {\n const rootDir = process.cwd();\n const files = findTsFiles(rootDir);\n\n console.log(`Scanning ${files.length} TypeScript files...\\n`);\n\n const allViolations: Violation[] = [];\n\n for (const file of files) {\n const violations = lintFile(file, rules, rootDir);\n allViolations.push(...violations);\n }\n\n if (allViolations.length === 0) {\n console.log(\"No ast-grep lint violations found.\");\n process.exit(0);\n }\n\n console.log(`Found ${allViolations.length} violation(s):\\n`);\n\n for (const v of allViolations) {\n const relPath = path.relative(rootDir, v.file);\n console.log(`${relPath}:${v.line}:${v.column}`);\n console.log(` ${v.rule}: ${v.message}`);\n console.log(` > ${v.code}\\n`);\n }\n\n process.exit(1);\n}\n\nexport const lintCommand = new Command(\"lint\")\n .description(\"Run AST-based linting on TypeScript files\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ appkit lint`,\n )\n .action(runLint);\n"],"mappings":";;;;;;AAaA,MAAM,QAAgB;CACpB;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACH;CACD;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACF,cAAc;EACf;CACD;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACF,SAAS,SAAS,wBAAwB,KAAK,KAAK;EACrD;CACD;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACH;CACD;EAIE,IAAI;EACJ,SAAS;EACT,SACE;EACF,cAAc;EACf;CACF;AAED,SAAS,WAAW,UAAkB,SAA0B;CAE9D,MAAM,MAAM,KAAK,SAAS,SAAS,SAAS;AAC5C,QACE,2BAA2B,KAAK,IAAI,IAAI,sBAAsB,KAAK,IAAI;;AAI3E,SAAS,YAAY,KAAa,QAAkB,EAAE,EAAY;CAChE,MAAM,UAAU,GAAG,YAAY,KAAK,EAAE,eAAe,MAAM,CAAC;AAE5D,MAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,WAAW,KAAK,KAAK,KAAK,MAAM,KAAK;AAE3C,MAAI,MAAM,aAAa,EAAE;AACvB,OAAI;IAAC;IAAgB;IAAQ;IAAS;IAAO,CAAC,SAAS,MAAM,KAAK,CAChE;AACF,eAAY,UAAU,MAAM;aACnB,MAAM,QAAQ,IAAI,cAAc,KAAK,MAAM,KAAK,CACzD,OAAM,KAAK,SAAS;;AAIxB,QAAO;;AAYT,SAAS,SACP,UACA,OACA,SACa;CACb,MAAM,aAA0B,EAAE;CAClC,MAAM,UAAU,GAAG,aAAa,UAAU,QAAQ;CAClD,MAAM,OAAO,SAAS,SAAS,OAAO,GAAG,KAAK,MAAM,KAAK;CACzD,MAAM,WAAW,WAAW,UAAU,QAAQ;CAG9C,MAAM,OADM,MAAM,MAAM,QAAQ,CACf,MAAM;AAEvB,MAAK,MAAM,QAAQ,OAAO;AAExB,MAAI,YAAY,KAAK,iBAAiB,MAAO;EAE7C,MAAM,UAAU,KAAK,QAAQ,KAAK,QAAQ;AAE1C,OAAK,MAAM,SAAS,SAAS;GAC3B,MAAM,OAAO,MAAM,MAAM;AAEzB,OAAI,KAAK,UAAU,CAAC,KAAK,OAAO,KAAK,CAAE;GAEvC,MAAM,QAAQ,MAAM,OAAO;AAC3B,cAAW,KAAK;IACd,MAAM;IACN,MAAM,MAAM,MAAM,OAAO;IACzB,QAAQ,MAAM,MAAM,SAAS;IAC7B,MAAM,KAAK;IACX,SAAS,KAAK;IACd,MAAM,KAAK,SAAS,KAAK,GAAG,KAAK,MAAM,GAAG,GAAG,CAAC,OAAO;IACtD,CAAC;;;AAIN,QAAO;;;;;AAMT,SAAS,UAAU;CACjB,MAAM,UAAU,QAAQ,KAAK;CAC7B,MAAM,QAAQ,YAAY,QAAQ;AAElC,SAAQ,IAAI,YAAY,MAAM,OAAO,wBAAwB;CAE7D,MAAM,gBAA6B,EAAE;AAErC,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,aAAa,SAAS,MAAM,OAAO,QAAQ;AACjD,gBAAc,KAAK,GAAG,WAAW;;AAGnC,KAAI,cAAc,WAAW,GAAG;AAC9B,UAAQ,IAAI,qCAAqC;AACjD,UAAQ,KAAK,EAAE;;AAGjB,SAAQ,IAAI,SAAS,cAAc,OAAO,kBAAkB;AAE5D,MAAK,MAAM,KAAK,eAAe;EAC7B,MAAM,UAAU,KAAK,SAAS,SAAS,EAAE,KAAK;AAC9C,UAAQ,IAAI,GAAG,QAAQ,GAAG,EAAE,KAAK,GAAG,EAAE,SAAS;AAC/C,UAAQ,IAAI,KAAK,EAAE,KAAK,IAAI,EAAE,UAAU;AACxC,UAAQ,IAAI,OAAO,EAAE,KAAK,IAAI;;AAGhC,SAAQ,KAAK,EAAE;;AAGjB,MAAa,cAAc,IAAI,QAAQ,OAAO,CAC3C,YAAY,4CAA4C,CACxD,YACC,SACA;;iBAGD,CACA,OAAO,QAAQ"}
@@ -104,4 +104,7 @@ import { Textarea } from "./ui/textarea.js";
104
104
  import { Toggle, toggleVariants } from "./ui/toggle.js";
105
105
  import { ToggleGroup, ToggleGroupItem } from "./ui/toggle-group.js";
106
106
  import "./ui/index.js";
107
- export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, AgentChatEvent, AggregatedResourceStatus, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AnalyticsFormat, AreaChart, AreaChartProps, AreaChartSpecificProps, AspectRatio, Avatar, AvatarFallback, AvatarImage, Badge, BarChart, BarChartProps, BarChartSpecificProps, BaseChart, BaseChartProps, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, CHART_COLOR_VARS, CHART_COLOR_VARS_CATEGORICAL, CHART_COLOR_VARS_DIVERGING, CHART_COLOR_VARS_SEQUENTIAL, Calendar, CalendarDayButton, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, CartesianContext, ChartBaseProps, ChartColorPalette, ChartData, ChartInference, ChartType, ChartUITokens, ChartWrapper, ChartWrapperProps, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, ColumnCategory, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, DATE_FIELD_PATTERNS, DataFormat, DataProps, DataTable, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DirectoryEntry, DirectoryList, DirectoryListProps, DonutChart, DonutChartProps, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, FALLBACK_COLORS_CATEGORICAL, FALLBACK_COLORS_DIVERGING, FALLBACK_COLORS_SEQUENTIAL, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, FileBreadcrumb, FileBreadcrumbProps, FileBrowserLabels, FileEntry, FileEntryProps, FilePreview, FilePreviewPanel, FilePreviewPanelProps, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, GenieAttachmentResponse, GenieChat, GenieChatInput, GenieChatMessage, GenieChatMessageList, GenieChatProps, GenieChatStatus, GenieColumnMeta, GenieMessageItem, GenieMessageResponse, GenieQueryVisualization, GenieStatementResponse, GenieStreamEvent, HeatmapChart, HeatmapChartProps, HeatmapChartSpecificProps, HeatmapContext, HoverCard, HoverCardContent, HoverCardTrigger, InferResultByFormat, InferRowType, InferServingChunk, InferServingRequest, InferServingResponse, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, Kbd, KbdGroup, Label, LineChart, LineChartProps, LineChartSpecificProps, LoadingSkeleton, METADATA_DATE_PATTERNS, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, NAME_FIELD_PATTERNS, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, NewFolderInput, NewFolderInputProps, NormalizedChartData, NormalizedChartDataBase, NormalizedHeatmapData, OptionBuilderContext, Orientation, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PieChart, PieChartProps, PieChartSpecificProps, PluginRegistry, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PortalContainerContext, PortalContainerProvider, Progress, QueryProps, QueryRegistry, RadarChart, RadarChartProps, RadarChartSpecificProps, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, ResourceKindRenderer, ResourceSeverity, ResourceStatus, ResourceStatusFilter, ResourceStatusIndicator, ResourceStatusIndicatorProps, ResourceStatusProvider, ResourceStatusProviderProps, ResourceStatusToasterOptions, ResourceWaitingPlaceholder, ScatterChart, ScatterChartProps, ScatterChartSpecificProps, ScrollArea, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, ServingAlias, ServingEndpointRegistry, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Slider, Spinner, Switch, TERMINAL_STATUSES, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TransformedGenieData, TypedArrowTable, UnifiedChartProps, UseAgentChatOptions, UseAgentChatResult, UseAnalyticsQueryOptions, UseAnalyticsQueryResult, UseChartDataOptions, UseChartDataResult, UseGenieChatOptions, UseGenieChatReturn, UseServingInvokeOptions, UseServingInvokeResult, UseServingStreamOptions, UseServingStreamResult, WarehouseState, WarehouseStatus, badgeVariants, buildCartesianOption, buildHeatmapOption, buildHorizontalBarOption, buildPieOption, buildRadarOption, buttonGroupVariants, buttonVariants, cn, createChart, createTimeSeriesData, formatFileSize, formatLabel, getCompatibleChartTypes, inferChartType, isArrowTable, isDataProps, isQueryProps, navigationMenuTriggerStyle, normalizeChartData, normalizeHeatmapData, sortTimeSeriesAscending, toChartArray, toChartValue, toggleVariants, transformGenieData, truncateLabel, useAgentChat, useAllThemeColors, useAnalyticsQuery, useChartData, useChartUITokens, useFormField, useGenieChat, useIsMobile, usePluginClientConfig, usePortalContainer, useResolvedPortalContainer, useResourceStatus, useResourceStatusPublisher, useResourceStatusToaster, useServingInvoke, useServingStream, useSidebar, useThemeColors };
107
+ import { Variant, VariantProps } from "./ui-variants/variant.js";
108
+ import { Variants, VariantsProps } from "./ui-variants/variants.js";
109
+ import "./ui-variants/index.js";
110
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, AgentChatEvent, AggregatedResourceStatus, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AnalyticsFormat, AreaChart, AreaChartProps, AreaChartSpecificProps, AspectRatio, Avatar, AvatarFallback, AvatarImage, Badge, BarChart, BarChartProps, BarChartSpecificProps, BaseChart, BaseChartProps, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, CHART_COLOR_VARS, CHART_COLOR_VARS_CATEGORICAL, CHART_COLOR_VARS_DIVERGING, CHART_COLOR_VARS_SEQUENTIAL, Calendar, CalendarDayButton, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, CartesianContext, ChartBaseProps, ChartColorPalette, ChartData, ChartInference, ChartType, ChartUITokens, ChartWrapper, ChartWrapperProps, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, ColumnCategory, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, DATE_FIELD_PATTERNS, DataFormat, DataProps, DataTable, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DirectoryEntry, DirectoryList, DirectoryListProps, DonutChart, DonutChartProps, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, FALLBACK_COLORS_CATEGORICAL, FALLBACK_COLORS_DIVERGING, FALLBACK_COLORS_SEQUENTIAL, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, FileBreadcrumb, FileBreadcrumbProps, FileBrowserLabels, FileEntry, FileEntryProps, FilePreview, FilePreviewPanel, FilePreviewPanelProps, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, GenieAttachmentResponse, GenieChat, GenieChatInput, GenieChatMessage, GenieChatMessageList, GenieChatProps, GenieChatStatus, GenieColumnMeta, GenieMessageItem, GenieMessageResponse, GenieQueryVisualization, GenieStatementResponse, GenieStreamEvent, HeatmapChart, HeatmapChartProps, HeatmapChartSpecificProps, HeatmapContext, HoverCard, HoverCardContent, HoverCardTrigger, InferResultByFormat, InferRowType, InferServingChunk, InferServingRequest, InferServingResponse, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, Kbd, KbdGroup, Label, LineChart, LineChartProps, LineChartSpecificProps, LoadingSkeleton, METADATA_DATE_PATTERNS, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, NAME_FIELD_PATTERNS, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, NewFolderInput, NewFolderInputProps, NormalizedChartData, NormalizedChartDataBase, NormalizedHeatmapData, OptionBuilderContext, Orientation, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PieChart, PieChartProps, PieChartSpecificProps, PluginRegistry, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PortalContainerContext, PortalContainerProvider, Progress, QueryProps, QueryRegistry, RadarChart, RadarChartProps, RadarChartSpecificProps, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, ResourceKindRenderer, ResourceSeverity, ResourceStatus, ResourceStatusFilter, ResourceStatusIndicator, ResourceStatusIndicatorProps, ResourceStatusProvider, ResourceStatusProviderProps, ResourceStatusToasterOptions, ResourceWaitingPlaceholder, ScatterChart, ScatterChartProps, ScatterChartSpecificProps, ScrollArea, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, ServingAlias, ServingEndpointRegistry, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Slider, Spinner, Switch, TERMINAL_STATUSES, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TransformedGenieData, TypedArrowTable, UnifiedChartProps, UseAgentChatOptions, UseAgentChatResult, UseAnalyticsQueryOptions, UseAnalyticsQueryResult, UseChartDataOptions, UseChartDataResult, UseGenieChatOptions, UseGenieChatReturn, UseServingInvokeOptions, UseServingInvokeResult, UseServingStreamOptions, UseServingStreamResult, Variant, VariantProps, Variants, VariantsProps, WarehouseState, WarehouseStatus, badgeVariants, buildCartesianOption, buildHeatmapOption, buildHorizontalBarOption, buildPieOption, buildRadarOption, buttonGroupVariants, buttonVariants, cn, createChart, createTimeSeriesData, formatFileSize, formatLabel, getCompatibleChartTypes, inferChartType, isArrowTable, isDataProps, isQueryProps, navigationMenuTriggerStyle, normalizeChartData, normalizeHeatmapData, sortTimeSeriesAscending, toChartArray, toChartValue, toggleVariants, transformGenieData, truncateLabel, useAgentChat, useAllThemeColors, useAnalyticsQuery, useChartData, useChartUITokens, useFormField, useGenieChat, useIsMobile, usePluginClientConfig, usePortalContainer, useResolvedPortalContainer, useResourceStatus, useResourceStatusPublisher, useResourceStatusToaster, useServingInvoke, useServingStream, useSidebar, useThemeColors };
@@ -94,5 +94,7 @@ import { Slider } from "./ui/slider.js";
94
94
  import { Switch } from "./ui/switch.js";
95
95
  import { Toggle, toggleVariants } from "./ui/toggle.js";
96
96
  import { ToggleGroup, ToggleGroupItem } from "./ui/toggle-group.js";
97
+ import { Variant } from "./ui-variants/variant.js";
98
+ import { Variants } from "./ui-variants/variants.js";
97
99
 
98
- export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AreaChart, AspectRatio, Avatar, AvatarFallback, AvatarImage, Badge, BarChart, BaseChart, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, CHART_COLOR_VARS, CHART_COLOR_VARS_CATEGORICAL, CHART_COLOR_VARS_DIVERGING, CHART_COLOR_VARS_SEQUENTIAL, Calendar, CalendarDayButton, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, ChartWrapper, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, DATE_FIELD_PATTERNS, DataTable, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DirectoryList, DonutChart, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, FALLBACK_COLORS_CATEGORICAL, FALLBACK_COLORS_DIVERGING, FALLBACK_COLORS_SEQUENTIAL, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, FileBreadcrumb, FileEntry, FilePreviewPanel, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, GenieChat, GenieChatInput, GenieChatMessage, GenieChatMessageList, GenieQueryVisualization, HeatmapChart, HoverCard, HoverCardContent, HoverCardTrigger, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, Kbd, KbdGroup, Label, LineChart, LoadingSkeleton, METADATA_DATE_PATTERNS, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, NAME_FIELD_PATTERNS, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, NewFolderInput, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PieChart, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PortalContainerContext, PortalContainerProvider, Progress, RadarChart, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, ResourceStatusIndicator, ResourceStatusProvider, ResourceWaitingPlaceholder, ScatterChart, ScrollArea, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Slider, Spinner, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, badgeVariants, buildCartesianOption, buildHeatmapOption, buildHorizontalBarOption, buildPieOption, buildRadarOption, buttonGroupVariants, buttonVariants, cn, createChart, createTimeSeriesData, formatFileSize, formatLabel, getCompatibleChartTypes, inferChartType, isArrowTable, isDataProps, isQueryProps, navigationMenuTriggerStyle, normalizeChartData, normalizeHeatmapData, sortTimeSeriesAscending, toChartArray, toChartValue, toggleVariants, transformGenieData, truncateLabel, useAgentChat, useAllThemeColors, useAnalyticsQuery, useChartData, useChartUITokens, useFormField, useGenieChat, useIsMobile, usePluginClientConfig, usePortalContainer, useResolvedPortalContainer, useResourceStatus, useResourceStatusPublisher, useResourceStatusToaster, useServingInvoke, useServingStream, useSidebar, useThemeColors };
100
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AreaChart, AspectRatio, Avatar, AvatarFallback, AvatarImage, Badge, BarChart, BaseChart, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, CHART_COLOR_VARS, CHART_COLOR_VARS_CATEGORICAL, CHART_COLOR_VARS_DIVERGING, CHART_COLOR_VARS_SEQUENTIAL, Calendar, CalendarDayButton, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, ChartWrapper, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, DATE_FIELD_PATTERNS, DataTable, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DirectoryList, DonutChart, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, FALLBACK_COLORS_CATEGORICAL, FALLBACK_COLORS_DIVERGING, FALLBACK_COLORS_SEQUENTIAL, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, FileBreadcrumb, FileEntry, FilePreviewPanel, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, GenieChat, GenieChatInput, GenieChatMessage, GenieChatMessageList, GenieQueryVisualization, HeatmapChart, HoverCard, HoverCardContent, HoverCardTrigger, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, Kbd, KbdGroup, Label, LineChart, LoadingSkeleton, METADATA_DATE_PATTERNS, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, NAME_FIELD_PATTERNS, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, NewFolderInput, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PieChart, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PortalContainerContext, PortalContainerProvider, Progress, RadarChart, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, ResourceStatusIndicator, ResourceStatusProvider, ResourceWaitingPlaceholder, ScatterChart, ScrollArea, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Slider, Spinner, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, Variant, Variants, badgeVariants, buildCartesianOption, buildHeatmapOption, buildHorizontalBarOption, buildPieOption, buildRadarOption, buttonGroupVariants, buttonVariants, cn, createChart, createTimeSeriesData, formatFileSize, formatLabel, getCompatibleChartTypes, inferChartType, isArrowTable, isDataProps, isQueryProps, navigationMenuTriggerStyle, normalizeChartData, normalizeHeatmapData, sortTimeSeriesAscending, toChartArray, toChartValue, toggleVariants, transformGenieData, truncateLabel, useAgentChat, useAllThemeColors, useAnalyticsQuery, useChartData, useChartUITokens, useFormField, useGenieChat, useIsMobile, usePluginClientConfig, usePortalContainer, useResolvedPortalContainer, useResourceStatus, useResourceStatusPublisher, useResourceStatusToaster, useServingInvoke, useServingStream, useSidebar, useThemeColors };
@@ -0,0 +1,2 @@
1
+ import { Variant, VariantProps } from "./variant.js";
2
+ import { Variants, VariantsProps } from "./variants.js";
@@ -0,0 +1,21 @@
1
+ import * as React$1 from "react";
2
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
3
+
4
+ //#region src/react/ui-variants/variant.d.ts
5
+ /** Props for a single {@link Variant} inside a {@link Variants} block. */
6
+ interface VariantProps {
7
+ /** Human-readable label shown in the switcher and recorded on confirm. */
8
+ label?: string;
9
+ children: React$1.ReactNode;
10
+ }
11
+ /**
12
+ * One candidate inside a {@link Variants} block. Purely a declarative marker:
13
+ * `Variants` reads its `label` and renders its `children` for the active
14
+ * index. It is not meant to be rendered on its own.
15
+ */
16
+ declare function Variant({
17
+ children
18
+ }: VariantProps): react_jsx_runtime0.JSX.Element;
19
+ //#endregion
20
+ export { Variant, VariantProps };
21
+ //# sourceMappingURL=variant.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"variant.d.ts","names":[],"sources":["../../../src/react/ui-variants/variant.tsx"],"mappings":";;;;;UAGiB,YAAA;;EAEf,KAAA;EACA,QAAA,EAAU,OAAA,CAAM,SAAA;AAAA;;;;;;iBAQF,OAAA,CAAA;EAAU;AAAA,GAAY,YAAA,GAAY,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -0,0 +1,15 @@
1
+ import { Fragment, jsx } from "react/jsx-runtime";
2
+
3
+ //#region src/react/ui-variants/variant.tsx
4
+ /**
5
+ * One candidate inside a {@link Variants} block. Purely a declarative marker:
6
+ * `Variants` reads its `label` and renders its `children` for the active
7
+ * index. It is not meant to be rendered on its own.
8
+ */
9
+ function Variant({ children }) {
10
+ return /* @__PURE__ */ jsx(Fragment, { children });
11
+ }
12
+
13
+ //#endregion
14
+ export { Variant };
15
+ //# sourceMappingURL=variant.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"variant.js","names":[],"sources":["../../../src/react/ui-variants/variant.tsx"],"sourcesContent":["import type * as React from \"react\";\n\n/** Props for a single {@link Variant} inside a {@link Variants} block. */\nexport interface VariantProps {\n /** Human-readable label shown in the switcher and recorded on confirm. */\n label?: string;\n children: React.ReactNode;\n}\n\n/**\n * One candidate inside a {@link Variants} block. Purely a declarative marker:\n * `Variants` reads its `label` and renders its `children` for the active\n * index. It is not meant to be rendered on its own.\n */\nexport function Variant({ children }: VariantProps) {\n return <>{children}</>;\n}\n"],"mappings":";;;;;;;;AAcA,SAAgB,QAAQ,EAAE,YAA0B;AAClD,QAAO,gCAAG,WAAY"}
@@ -0,0 +1,87 @@
1
+ import { ReactNode } from "react";
2
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
3
+
4
+ //#region src/react/ui-variants/variants.d.ts
5
+ /** Props for {@link Variants}. */
6
+ interface VariantsProps {
7
+ /**
8
+ * Stable, unique identifier for this block. The variant-picking agent matches
9
+ * on it to finalize the chosen variant into source, so it must be unique per
10
+ * file. (Named `blockId`, not `id`, because it is a semantic key — not a DOM
11
+ * element id.)
12
+ */
13
+ blockId: string;
14
+ /** `<Variant>` children — one candidate UI each. */
15
+ children: ReactNode;
16
+ /**
17
+ * How the wrapper flows in the layout. Defaults to `"block"` (full width,
18
+ * variants stack vertically) — the right choice for page sections, heroes,
19
+ * and other block-level regions, which is the common case. Use `"inline"`
20
+ * when wrapping a small inline element such as a single button, so the
21
+ * wrapper hugs its content instead of spanning the row.
22
+ */
23
+ layout?: "block" | "inline";
24
+ /** Class name applied to the block wrapper (merged after `layout`). */
25
+ className?: string;
26
+ /**
27
+ * Any CSS color for the switcher chrome (dot, ring, control cluster, count
28
+ * pill, confirm tick). Every accent element derives from this one value.
29
+ * Defaults to {@link DEFAULT_ACCENT}. The error state stays red regardless.
30
+ *
31
+ * @example accent="var(--primary)" // match the app theme
32
+ * @example accent="#f43f5e" // rose
33
+ */
34
+ accent?: string;
35
+ }
36
+ /**
37
+ * Dev-time UI picker: renders several `<Variant>` candidates one at a time.
38
+ *
39
+ * At rest the block shows a small, slowly-pulsing corner dot so it's clear
40
+ * it's "in variant state" without hovering — the dot pulses while a choice is
41
+ * still pending and goes calm once recorded. On hover (or focus) an accent
42
+ * ring outlines the block and the dot gives way to a compact control cluster
43
+ * (‹ index/total › ✓) that scales out of the corner. Confirming POSTs the
44
+ * choice to the `uiVariants()` recorder plugin; a coding agent then finalizes
45
+ * the chosen variant into source, removing this wrapper.
46
+ *
47
+ * All switcher chrome uses the `accent` color (default {@link DEFAULT_ACCENT},
48
+ * a violet distinct from most apps' `primary`) so it doesn't blend into the
49
+ * content it wraps.
50
+ *
51
+ * Degrades gracefully. In a production build the picker chrome is dropped
52
+ * entirely and only the first variant renders as plain content — a safety net
53
+ * for a block that shipped without being finalized. In dev, if the recorder
54
+ * endpoint is absent (feature off) the switcher still works as a viewer and
55
+ * Confirm reports that recording is unavailable.
56
+ *
57
+ * @example Page section (default layout — full-width, stacks vertically)
58
+ * ```tsx
59
+ * <Variants blockId="hero">
60
+ * <Variant label="Split"><section>…</section></Variant>
61
+ * <Variant label="Centered"><section>…</section></Variant>
62
+ * </Variants>
63
+ * ```
64
+ *
65
+ * @example Small inline element (hug the content)
66
+ * ```tsx
67
+ * <Variants blockId="hero-cta" layout="inline">
68
+ * <Variant label="Ghost"><Button variant="ghost">Get started</Button></Variant>
69
+ * <Variant label="Solid"><Button>Get started</Button></Variant>
70
+ * </Variants>
71
+ * ```
72
+ *
73
+ * @example Custom accent
74
+ * ```tsx
75
+ * <Variants blockId="hero" accent="#f43f5e">…</Variants>
76
+ * ```
77
+ */
78
+ declare function Variants({
79
+ blockId,
80
+ children,
81
+ layout,
82
+ className,
83
+ accent
84
+ }: VariantsProps): react_jsx_runtime0.JSX.Element | null;
85
+ //#endregion
86
+ export { Variants, VariantsProps };
87
+ //# sourceMappingURL=variants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"variants.d.ts","names":[],"sources":["../../../src/react/ui-variants/variants.tsx"],"mappings":";;;;;UAoCiB,aAAA;;AAAjB;;;;;EAOE,OAAA;EAEU;EAAV,QAAA,EAAU,SAAA;EAUV;;;;AA0DF;;;EA5DE,MAAA;EA8DA;EA5DA,SAAA;EA8DA;;;;;;;;EArDA,MAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiDc,QAAA,CAAA;EACd,OAAA;EACA,QAAA;EACA,MAAA;EACA,SAAA;EACA;AAAA,GACC,aAAA,GAAa,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -0,0 +1,199 @@
1
+ import { cn } from "../lib/utils.js";
2
+ import { Variant } from "./variant.js";
3
+ import { Children, isValidElement, useMemo, useState } from "react";
4
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
+ import { Check, CheckCheck, ChevronLeft, ChevronRight, Loader2 } from "lucide-react";
6
+
7
+ //#region src/react/ui-variants/variants.tsx
8
+ /** Endpoint the recorder plugin (`uiVariants()`) mounts in development. */
9
+ const CONFIRM_ENDPOINT = "/api/ui-variants/confirm";
10
+ /** Abort the confirm request after this long so the button can't hang. */
11
+ const CONFIRM_TIMEOUT_MS = 5e3;
12
+ /**
13
+ * Default switcher accent — a violet chosen to stand apart from most apps'
14
+ * `primary`, so the dev-only picker chrome doesn't blend into the content it
15
+ * wraps. Override per-block via the `accent` prop.
16
+ */
17
+ const DEFAULT_ACCENT = "#8b5cf6";
18
+ function isVariantElement(node) {
19
+ return isValidElement(node) && node.type === Variant;
20
+ }
21
+ /**
22
+ * Dev-time UI picker: renders several `<Variant>` candidates one at a time.
23
+ *
24
+ * At rest the block shows a small, slowly-pulsing corner dot so it's clear
25
+ * it's "in variant state" without hovering — the dot pulses while a choice is
26
+ * still pending and goes calm once recorded. On hover (or focus) an accent
27
+ * ring outlines the block and the dot gives way to a compact control cluster
28
+ * (‹ index/total › ✓) that scales out of the corner. Confirming POSTs the
29
+ * choice to the `uiVariants()` recorder plugin; a coding agent then finalizes
30
+ * the chosen variant into source, removing this wrapper.
31
+ *
32
+ * All switcher chrome uses the `accent` color (default {@link DEFAULT_ACCENT},
33
+ * a violet distinct from most apps' `primary`) so it doesn't blend into the
34
+ * content it wraps.
35
+ *
36
+ * Degrades gracefully. In a production build the picker chrome is dropped
37
+ * entirely and only the first variant renders as plain content — a safety net
38
+ * for a block that shipped without being finalized. In dev, if the recorder
39
+ * endpoint is absent (feature off) the switcher still works as a viewer and
40
+ * Confirm reports that recording is unavailable.
41
+ *
42
+ * @example Page section (default layout — full-width, stacks vertically)
43
+ * ```tsx
44
+ * <Variants blockId="hero">
45
+ * <Variant label="Split"><section>…</section></Variant>
46
+ * <Variant label="Centered"><section>…</section></Variant>
47
+ * </Variants>
48
+ * ```
49
+ *
50
+ * @example Small inline element (hug the content)
51
+ * ```tsx
52
+ * <Variants blockId="hero-cta" layout="inline">
53
+ * <Variant label="Ghost"><Button variant="ghost">Get started</Button></Variant>
54
+ * <Variant label="Solid"><Button>Get started</Button></Variant>
55
+ * </Variants>
56
+ * ```
57
+ *
58
+ * @example Custom accent
59
+ * ```tsx
60
+ * <Variants blockId="hero" accent="#f43f5e">…</Variants>
61
+ * ```
62
+ */
63
+ function Variants({ blockId, children, layout = "block", className, accent = DEFAULT_ACCENT }) {
64
+ const variants = useMemo(() => Children.toArray(children).filter(isVariantElement), [children]);
65
+ const [active, setActive] = useState(0);
66
+ const [confirmState, setConfirmState] = useState("idle");
67
+ if (variants.length === 0) return null;
68
+ if (!import.meta.env.DEV) return /* @__PURE__ */ jsx(Fragment, { children: variants[0] });
69
+ const clampedActive = Math.min(active, variants.length - 1);
70
+ const current = variants[clampedActive];
71
+ const label = current.props.label ?? `Variant ${clampedActive + 1}`;
72
+ const atStart = clampedActive === 0;
73
+ const atEnd = clampedActive === variants.length - 1;
74
+ const go = (delta) => {
75
+ setActive((i) => Math.max(0, Math.min(variants.length - 1, i + delta)));
76
+ setConfirmState("idle");
77
+ };
78
+ const confirm = async () => {
79
+ if (confirmState === "saving") return;
80
+ setConfirmState("saving");
81
+ const controller = new AbortController();
82
+ const timeout = setTimeout(() => controller.abort(), CONFIRM_TIMEOUT_MS);
83
+ try {
84
+ const res = await fetch(CONFIRM_ENDPOINT, {
85
+ method: "POST",
86
+ headers: { "Content-Type": "application/json" },
87
+ body: JSON.stringify({
88
+ blockId,
89
+ chosenIndex: clampedActive,
90
+ label
91
+ }),
92
+ signal: controller.signal
93
+ });
94
+ if (res.status === 404 || res.status === 403) {
95
+ setConfirmState("unavailable");
96
+ return;
97
+ }
98
+ setConfirmState(res.ok ? "recorded" : "error");
99
+ } catch {
100
+ setConfirmState("error");
101
+ } finally {
102
+ clearTimeout(timeout);
103
+ }
104
+ };
105
+ return /* @__PURE__ */ jsxs("div", {
106
+ "data-slot": "variants",
107
+ style: { "--variants-accent": accent },
108
+ className: cn("group relative rounded-md ring-[color:var(--variants-accent)] transition-[box-shadow] duration-200", layout === "inline" ? "inline-block" : "block w-full", "hover:ring-1 focus-within:ring-1", className),
109
+ children: [
110
+ current,
111
+ /* @__PURE__ */ jsx(StateDot, {
112
+ state: confirmState,
113
+ className: "group-hover:pointer-events-none group-hover:opacity-0 group-focus-within:pointer-events-none group-focus-within:opacity-0"
114
+ }),
115
+ /* @__PURE__ */ jsxs("div", {
116
+ "data-slot": "variants-switcher",
117
+ className: cn("absolute -top-3 right-0 z-20 flex items-center gap-0.5 rounded-full border bg-background/95 px-1 py-0.5 shadow-md backdrop-blur", "border-[color-mix(in_srgb,var(--variants-accent)_40%,transparent)]", "pointer-events-none origin-top-right scale-90 opacity-0 transition-all duration-150", "group-hover:pointer-events-auto group-hover:scale-100 group-hover:opacity-100", "group-focus-within:pointer-events-auto group-focus-within:scale-100 group-focus-within:opacity-100"),
118
+ children: [
119
+ /* @__PURE__ */ jsx(RoundButton, {
120
+ "aria-label": "Previous variant",
121
+ disabled: atStart,
122
+ onClick: () => go(-1),
123
+ children: /* @__PURE__ */ jsx(ChevronLeft, { className: "size-3.5" })
124
+ }),
125
+ /* @__PURE__ */ jsxs("span", {
126
+ className: "select-none rounded-full bg-[color-mix(in_srgb,var(--variants-accent)_15%,transparent)] px-1 text-[10px] font-semibold text-[color:var(--variants-accent)] tabular-nums",
127
+ children: [
128
+ clampedActive + 1,
129
+ "/",
130
+ variants.length
131
+ ]
132
+ }),
133
+ /* @__PURE__ */ jsx(RoundButton, {
134
+ "aria-label": "Next variant",
135
+ disabled: atEnd,
136
+ onClick: () => go(1),
137
+ children: /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5" })
138
+ }),
139
+ /* @__PURE__ */ jsx(ConfirmButton, {
140
+ state: confirmState,
141
+ label,
142
+ onClick: confirm
143
+ })
144
+ ]
145
+ })
146
+ ]
147
+ });
148
+ }
149
+ function dotColorFor(state) {
150
+ switch (state) {
151
+ case "error": return "bg-destructive";
152
+ case "unavailable": return "bg-muted-foreground/40";
153
+ default: return "bg-[color:var(--variants-accent)]";
154
+ }
155
+ }
156
+ /**
157
+ * Resting corner indicator: pulses while a choice is pending, calm once
158
+ * recorded — so a block's picked/unpicked state reads at a glance without
159
+ * hovering.
160
+ */
161
+ function StateDot({ state, className }) {
162
+ const pulsing = state === "idle" || state === "saving";
163
+ const color = dotColorFor(state);
164
+ return /* @__PURE__ */ jsxs("span", {
165
+ "aria-hidden": true,
166
+ "data-slot": "variants-dot",
167
+ className: cn("absolute -top-1 -right-1 z-10 flex size-3 items-center justify-center transition-opacity duration-150", className),
168
+ children: [pulsing && /* @__PURE__ */ jsx("span", { className: cn("absolute inline-flex size-full animate-ping rounded-full opacity-50 [animation-duration:2.5s]", color) }), /* @__PURE__ */ jsx("span", { className: cn("relative inline-flex size-2.5 rounded-full ring-2 ring-background", color) })]
169
+ });
170
+ }
171
+ function RoundButton({ children, disabled, className, ...props }) {
172
+ return /* @__PURE__ */ jsx("button", {
173
+ type: "button",
174
+ disabled,
175
+ className: cn("inline-flex size-6 items-center justify-center rounded-full text-muted-foreground transition-colors", "hover:bg-accent hover:text-accent-foreground", "disabled:pointer-events-none disabled:opacity-30", className),
176
+ ...props,
177
+ children
178
+ });
179
+ }
180
+ /**
181
+ * Round tick that confirms the active variant. State is conveyed by icon +
182
+ * color only (no text). The chosen `label` rides along in the title/aria for
183
+ * accessibility and hover context.
184
+ */
185
+ function ConfirmButton({ state, label, onClick }) {
186
+ const title = state === "recorded" ? `Recorded "${label}" — ask the agent to finalize` : state === "unavailable" ? "Recorder unavailable" : state === "error" ? "Failed — click to retry" : `Confirm "${label}"`;
187
+ return /* @__PURE__ */ jsx(RoundButton, {
188
+ "aria-label": title,
189
+ title,
190
+ disabled: state === "saving" || state === "unavailable",
191
+ onClick,
192
+ className: cn(state === "recorded" && "text-[color:var(--variants-accent)] hover:bg-[color-mix(in_srgb,var(--variants-accent)_12%,transparent)] hover:text-[color:var(--variants-accent)]", state === "error" && "text-destructive hover:bg-destructive/10 hover:text-destructive", (state === "idle" || state === "saving") && "hover:bg-[color-mix(in_srgb,var(--variants-accent)_12%,transparent)] hover:text-[color:var(--variants-accent)]"),
193
+ children: state === "saving" ? /* @__PURE__ */ jsx(Loader2, { className: "size-3.5 animate-spin" }) : state === "recorded" ? /* @__PURE__ */ jsx(CheckCheck, { className: "size-3.5" }) : /* @__PURE__ */ jsx(Check, { className: "size-3.5" })
194
+ });
195
+ }
196
+
197
+ //#endregion
198
+ export { Variants };
199
+ //# sourceMappingURL=variants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"variants.js","names":[],"sources":["../../../src/react/ui-variants/variants.tsx"],"sourcesContent":["import {\n Check,\n CheckCheck,\n ChevronLeft,\n ChevronRight,\n Loader2,\n} from \"lucide-react\";\nimport {\n Children,\n type ComponentProps,\n type CSSProperties,\n isValidElement,\n type ReactElement,\n type ReactNode,\n useMemo,\n useState,\n} from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Variant, type VariantProps } from \"./variant\";\n\n/** Endpoint the recorder plugin (`uiVariants()`) mounts in development. */\nconst CONFIRM_ENDPOINT = \"/api/ui-variants/confirm\";\n\n/** Abort the confirm request after this long so the button can't hang. */\nconst CONFIRM_TIMEOUT_MS = 5000;\n\n/**\n * Default switcher accent — a violet chosen to stand apart from most apps'\n * `primary`, so the dev-only picker chrome doesn't blend into the content it\n * wraps. Override per-block via the `accent` prop.\n */\nconst DEFAULT_ACCENT = \"#8b5cf6\";\n\ntype ConfirmState = \"idle\" | \"saving\" | \"recorded\" | \"unavailable\" | \"error\";\n\n/** Props for {@link Variants}. */\nexport interface VariantsProps {\n /**\n * Stable, unique identifier for this block. The variant-picking agent matches\n * on it to finalize the chosen variant into source, so it must be unique per\n * file. (Named `blockId`, not `id`, because it is a semantic key — not a DOM\n * element id.)\n */\n blockId: string;\n /** `<Variant>` children — one candidate UI each. */\n children: ReactNode;\n /**\n * How the wrapper flows in the layout. Defaults to `\"block\"` (full width,\n * variants stack vertically) — the right choice for page sections, heroes,\n * and other block-level regions, which is the common case. Use `\"inline\"`\n * when wrapping a small inline element such as a single button, so the\n * wrapper hugs its content instead of spanning the row.\n */\n layout?: \"block\" | \"inline\";\n /** Class name applied to the block wrapper (merged after `layout`). */\n className?: string;\n /**\n * Any CSS color for the switcher chrome (dot, ring, control cluster, count\n * pill, confirm tick). Every accent element derives from this one value.\n * Defaults to {@link DEFAULT_ACCENT}. The error state stays red regardless.\n *\n * @example accent=\"var(--primary)\" // match the app theme\n * @example accent=\"#f43f5e\" // rose\n */\n accent?: string;\n}\n\nfunction isVariantElement(node: ReactNode): node is ReactElement<VariantProps> {\n return isValidElement(node) && node.type === Variant;\n}\n\n/**\n * Dev-time UI picker: renders several `<Variant>` candidates one at a time.\n *\n * At rest the block shows a small, slowly-pulsing corner dot so it's clear\n * it's \"in variant state\" without hovering — the dot pulses while a choice is\n * still pending and goes calm once recorded. On hover (or focus) an accent\n * ring outlines the block and the dot gives way to a compact control cluster\n * (‹ index/total › ✓) that scales out of the corner. Confirming POSTs the\n * choice to the `uiVariants()` recorder plugin; a coding agent then finalizes\n * the chosen variant into source, removing this wrapper.\n *\n * All switcher chrome uses the `accent` color (default {@link DEFAULT_ACCENT},\n * a violet distinct from most apps' `primary`) so it doesn't blend into the\n * content it wraps.\n *\n * Degrades gracefully. In a production build the picker chrome is dropped\n * entirely and only the first variant renders as plain content — a safety net\n * for a block that shipped without being finalized. In dev, if the recorder\n * endpoint is absent (feature off) the switcher still works as a viewer and\n * Confirm reports that recording is unavailable.\n *\n * @example Page section (default layout — full-width, stacks vertically)\n * ```tsx\n * <Variants blockId=\"hero\">\n * <Variant label=\"Split\"><section>…</section></Variant>\n * <Variant label=\"Centered\"><section>…</section></Variant>\n * </Variants>\n * ```\n *\n * @example Small inline element (hug the content)\n * ```tsx\n * <Variants blockId=\"hero-cta\" layout=\"inline\">\n * <Variant label=\"Ghost\"><Button variant=\"ghost\">Get started</Button></Variant>\n * <Variant label=\"Solid\"><Button>Get started</Button></Variant>\n * </Variants>\n * ```\n *\n * @example Custom accent\n * ```tsx\n * <Variants blockId=\"hero\" accent=\"#f43f5e\">…</Variants>\n * ```\n */\nexport function Variants({\n blockId,\n children,\n layout = \"block\",\n className,\n accent = DEFAULT_ACCENT,\n}: VariantsProps) {\n const variants = useMemo(\n () => Children.toArray(children).filter(isVariantElement),\n [children],\n );\n const [active, setActive] = useState(0);\n const [confirmState, setConfirmState] = useState<ConfirmState>(\"idle\");\n\n if (variants.length === 0) return null;\n if (!import.meta.env.DEV) return <>{variants[0]}</>;\n\n const clampedActive = Math.min(active, variants.length - 1);\n const current = variants[clampedActive];\n const label = current.props.label ?? `Variant ${clampedActive + 1}`;\n const atStart = clampedActive === 0;\n const atEnd = clampedActive === variants.length - 1;\n\n const go = (delta: number) => {\n // No wrap-around: clamp within bounds.\n setActive((i) => Math.max(0, Math.min(variants.length - 1, i + delta)));\n setConfirmState(\"idle\");\n };\n\n const confirm = async () => {\n if (confirmState === \"saving\") return;\n setConfirmState(\"saving\");\n\n // Bound the request so a hung recorder can't leave the button stuck in\n // \"saving\" forever.\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), CONFIRM_TIMEOUT_MS);\n try {\n const res = await fetch(CONFIRM_ENDPOINT, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ blockId, chosenIndex: clampedActive, label }),\n signal: controller.signal,\n });\n // 404/403: the recorder isn't mounted (feature off or a production\n // build). Degrade to a plain viewer.\n if (res.status === 404 || res.status === 403) {\n setConfirmState(\"unavailable\");\n return;\n }\n // Any other non-OK status (e.g. a 500) is a failure the user can retry.\n setConfirmState(res.ok ? \"recorded\" : \"error\");\n } catch {\n // Network failure or timeout abort — the request never completed.\n setConfirmState(\"error\");\n } finally {\n clearTimeout(timeout);\n }\n };\n\n return (\n <div\n data-slot=\"variants\"\n // All accent chrome derives from this one variable; children read it via\n // the cascade, so the `accent` prop flows everywhere without prop-drilling.\n style={{ \"--variants-accent\": accent } as CSSProperties}\n className={cn(\n // Ring appears only on hover/focus so blocks stay calm at rest; the\n // corner dot is the resting \"in variant state\" indicator.\n \"group relative rounded-md ring-[color:var(--variants-accent)] transition-[box-shadow] duration-200\",\n layout === \"inline\" ? \"inline-block\" : \"block w-full\",\n \"hover:ring-1 focus-within:ring-1\",\n className,\n )}\n >\n {current}\n\n <StateDot\n state={confirmState}\n className=\"group-hover:pointer-events-none group-hover:opacity-0 group-focus-within:pointer-events-none group-focus-within:opacity-0\"\n />\n\n <div\n data-slot=\"variants-switcher\"\n className={cn(\n \"absolute -top-3 right-0 z-20 flex items-center gap-0.5 rounded-full border bg-background/95 px-1 py-0.5 shadow-md backdrop-blur\",\n \"border-[color-mix(in_srgb,var(--variants-accent)_40%,transparent)]\",\n \"pointer-events-none origin-top-right scale-90 opacity-0 transition-all duration-150\",\n \"group-hover:pointer-events-auto group-hover:scale-100 group-hover:opacity-100\",\n \"group-focus-within:pointer-events-auto group-focus-within:scale-100 group-focus-within:opacity-100\",\n )}\n >\n <RoundButton\n aria-label=\"Previous variant\"\n disabled={atStart}\n onClick={() => go(-1)}\n >\n <ChevronLeft className=\"size-3.5\" />\n </RoundButton>\n\n <span className=\"select-none rounded-full bg-[color-mix(in_srgb,var(--variants-accent)_15%,transparent)] px-1 text-[10px] font-semibold text-[color:var(--variants-accent)] tabular-nums\">\n {clampedActive + 1}/{variants.length}\n </span>\n\n <RoundButton\n aria-label=\"Next variant\"\n disabled={atEnd}\n onClick={() => go(1)}\n >\n <ChevronRight className=\"size-3.5\" />\n </RoundButton>\n\n <ConfirmButton state={confirmState} label={label} onClick={confirm} />\n </div>\n </div>\n );\n}\n\nfunction dotColorFor(state: ConfirmState): string {\n switch (state) {\n case \"error\":\n return \"bg-destructive\";\n case \"unavailable\":\n return \"bg-muted-foreground/40\";\n default:\n return \"bg-[color:var(--variants-accent)]\";\n }\n}\n\n/**\n * Resting corner indicator: pulses while a choice is pending, calm once\n * recorded — so a block's picked/unpicked state reads at a glance without\n * hovering.\n */\nfunction StateDot({\n state,\n className,\n}: {\n state: ConfirmState;\n className?: string;\n}) {\n const pulsing = state === \"idle\" || state === \"saving\";\n const color = dotColorFor(state);\n\n return (\n <span\n aria-hidden\n data-slot=\"variants-dot\"\n className={cn(\n \"absolute -top-1 -right-1 z-10 flex size-3 items-center justify-center transition-opacity duration-150\",\n className,\n )}\n >\n {pulsing && (\n <span\n className={cn(\n // Slow, gentle pulse (~2.5s) so it reads as an ambient hint,\n // not an alarm. Overrides tailwind's default 1s ping cadence.\n \"absolute inline-flex size-full animate-ping rounded-full opacity-50 [animation-duration:2.5s]\",\n color,\n )}\n />\n )}\n <span\n className={cn(\n \"relative inline-flex size-2.5 rounded-full ring-2 ring-background\",\n color,\n )}\n />\n </span>\n );\n}\n\nfunction RoundButton({\n children,\n disabled,\n className,\n ...props\n}: ComponentProps<\"button\">) {\n return (\n <button\n type=\"button\"\n disabled={disabled}\n className={cn(\n \"inline-flex size-6 items-center justify-center rounded-full text-muted-foreground transition-colors\",\n \"hover:bg-accent hover:text-accent-foreground\",\n \"disabled:pointer-events-none disabled:opacity-30\",\n className,\n )}\n {...props}\n >\n {children}\n </button>\n );\n}\n\n/**\n * Round tick that confirms the active variant. State is conveyed by icon +\n * color only (no text). The chosen `label` rides along in the title/aria for\n * accessibility and hover context.\n */\nfunction ConfirmButton({\n state,\n label,\n onClick,\n}: {\n state: ConfirmState;\n label: string;\n onClick: () => void;\n}) {\n const title =\n state === \"recorded\"\n ? `Recorded \"${label}\" — ask the agent to finalize`\n : state === \"unavailable\"\n ? \"Recorder unavailable\"\n : state === \"error\"\n ? \"Failed — click to retry\"\n : `Confirm \"${label}\"`;\n\n return (\n <RoundButton\n aria-label={title}\n title={title}\n disabled={state === \"saving\" || state === \"unavailable\"}\n onClick={onClick}\n className={cn(\n state === \"recorded\" &&\n \"text-[color:var(--variants-accent)] hover:bg-[color-mix(in_srgb,var(--variants-accent)_12%,transparent)] hover:text-[color:var(--variants-accent)]\",\n state === \"error\" &&\n \"text-destructive hover:bg-destructive/10 hover:text-destructive\",\n (state === \"idle\" || state === \"saving\") &&\n \"hover:bg-[color-mix(in_srgb,var(--variants-accent)_12%,transparent)] hover:text-[color:var(--variants-accent)]\",\n )}\n >\n {state === \"saving\" ? (\n <Loader2 className=\"size-3.5 animate-spin\" />\n ) : state === \"recorded\" ? (\n <CheckCheck className=\"size-3.5\" />\n ) : (\n <Check className=\"size-3.5\" />\n )}\n </RoundButton>\n );\n}\n"],"mappings":";;;;;;;;AAqBA,MAAM,mBAAmB;;AAGzB,MAAM,qBAAqB;;;;;;AAO3B,MAAM,iBAAiB;AAoCvB,SAAS,iBAAiB,MAAqD;AAC7E,QAAO,eAAe,KAAK,IAAI,KAAK,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6C/C,SAAgB,SAAS,EACvB,SACA,UACA,SAAS,SACT,WACA,SAAS,kBACO;CAChB,MAAM,WAAW,cACT,SAAS,QAAQ,SAAS,CAAC,OAAO,iBAAiB,EACzD,CAAC,SAAS,CACX;CACD,MAAM,CAAC,QAAQ,aAAa,SAAS,EAAE;CACvC,MAAM,CAAC,cAAc,mBAAmB,SAAuB,OAAO;AAEtE,KAAI,SAAS,WAAW,EAAG,QAAO;AAClC,KAAI,CAAC,OAAO,KAAK,IAAI,IAAK,QAAO,0CAAG,SAAS,KAAM;CAEnD,MAAM,gBAAgB,KAAK,IAAI,QAAQ,SAAS,SAAS,EAAE;CAC3D,MAAM,UAAU,SAAS;CACzB,MAAM,QAAQ,QAAQ,MAAM,SAAS,WAAW,gBAAgB;CAChE,MAAM,UAAU,kBAAkB;CAClC,MAAM,QAAQ,kBAAkB,SAAS,SAAS;CAElD,MAAM,MAAM,UAAkB;AAE5B,aAAW,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,SAAS,SAAS,GAAG,IAAI,MAAM,CAAC,CAAC;AACvE,kBAAgB,OAAO;;CAGzB,MAAM,UAAU,YAAY;AAC1B,MAAI,iBAAiB,SAAU;AAC/B,kBAAgB,SAAS;EAIzB,MAAM,aAAa,IAAI,iBAAiB;EACxC,MAAM,UAAU,iBAAiB,WAAW,OAAO,EAAE,mBAAmB;AACxE,MAAI;GACF,MAAM,MAAM,MAAM,MAAM,kBAAkB;IACxC,QAAQ;IACR,SAAS,EAAE,gBAAgB,oBAAoB;IAC/C,MAAM,KAAK,UAAU;KAAE;KAAS,aAAa;KAAe;KAAO,CAAC;IACpE,QAAQ,WAAW;IACpB,CAAC;AAGF,OAAI,IAAI,WAAW,OAAO,IAAI,WAAW,KAAK;AAC5C,oBAAgB,cAAc;AAC9B;;AAGF,mBAAgB,IAAI,KAAK,aAAa,QAAQ;UACxC;AAEN,mBAAgB,QAAQ;YAChB;AACR,gBAAa,QAAQ;;;AAIzB,QACE,qBAAC;EACC,aAAU;EAGV,OAAO,EAAE,qBAAqB,QAAQ;EACtC,WAAW,GAGT,sGACA,WAAW,WAAW,iBAAiB,gBACvC,oCACA,UACD;;GAEA;GAED,oBAAC;IACC,OAAO;IACP,WAAU;KACV;GAEF,qBAAC;IACC,aAAU;IACV,WAAW,GACT,mIACA,sEACA,uFACA,iFACA,qGACD;;KAED,oBAAC;MACC,cAAW;MACX,UAAU;MACV,eAAe,GAAG,GAAG;gBAErB,oBAAC,eAAY,WAAU,aAAa;OACxB;KAEd,qBAAC;MAAK,WAAU;;OACb,gBAAgB;OAAE;OAAE,SAAS;;OACzB;KAEP,oBAAC;MACC,cAAW;MACX,UAAU;MACV,eAAe,GAAG,EAAE;gBAEpB,oBAAC,gBAAa,WAAU,aAAa;OACzB;KAEd,oBAAC;MAAc,OAAO;MAAqB;MAAO,SAAS;OAAW;;KAClE;;GACF;;AAIV,SAAS,YAAY,OAA6B;AAChD,SAAQ,OAAR;EACE,KAAK,QACH,QAAO;EACT,KAAK,cACH,QAAO;EACT,QACE,QAAO;;;;;;;;AASb,SAAS,SAAS,EAChB,OACA,aAIC;CACD,MAAM,UAAU,UAAU,UAAU,UAAU;CAC9C,MAAM,QAAQ,YAAY,MAAM;AAEhC,QACE,qBAAC;EACC;EACA,aAAU;EACV,WAAW,GACT,yGACA,UACD;aAEA,WACC,oBAAC,UACC,WAAW,GAGT,iGACA,MACD,GACD,EAEJ,oBAAC,UACC,WAAW,GACT,qEACA,MACD,GACD;GACG;;AAIX,SAAS,YAAY,EACnB,UACA,UACA,WACA,GAAG,SACwB;AAC3B,QACE,oBAAC;EACC,MAAK;EACK;EACV,WAAW,GACT,uGACA,gDACA,oDACA,UACD;EACD,GAAI;EAEH;GACM;;;;;;;AASb,SAAS,cAAc,EACrB,OACA,OACA,WAKC;CACD,MAAM,QACJ,UAAU,aACN,aAAa,MAAM,iCACnB,UAAU,gBACR,yBACA,UAAU,UACR,4BACA,YAAY,MAAM;AAE5B,QACE,oBAAC;EACC,cAAY;EACL;EACP,UAAU,UAAU,YAAY,UAAU;EACjC;EACT,WAAW,GACT,UAAU,cACR,sJACF,UAAU,WACR,oEACD,UAAU,UAAU,UAAU,aAC7B,iHACH;YAEA,UAAU,WACT,oBAAC,WAAQ,WAAU,0BAA0B,GAC3C,UAAU,aACZ,oBAAC,cAAW,WAAU,aAAa,GAEnC,oBAAC,SAAM,WAAU,aAAa;GAEpB"}
@@ -1118,6 +1118,7 @@ declare const pluginManifestSchema: z.ZodObject<{
1118
1118
  license: z.ZodOptional<z.ZodString>;
1119
1119
  onSetupMessage: z.ZodOptional<z.ZodString>;
1120
1120
  hidden: z.ZodOptional<z.ZodBoolean>;
1121
+ devOnly: z.ZodOptional<z.ZodBoolean>;
1121
1122
  stability: z.ZodOptional<z.ZodEnum<{
1122
1123
  beta: "beta";
1123
1124
  ga: "ga";
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.d.ts","names":[],"sources":["../../src/schemas/manifest.ts"],"mappings":";;;cAsPa,yBAAA,EAAyB,CAAA,CAAA,qBAAA,EAAA,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;cA8FzB,wBAAA,EAAwB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAkQxB,4BAAA,EAA4B,CAAA,CAAA,SAAA;;;;;cAoE5B,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA+frB,mBAAA,GAAsB,CAAA,CAAE,KAAA,QAAa,yBAAA;AAAA,KACrC,kBAAA,GAAqB,CAAA,CAAE,KAAA,QAAa,wBAAA;AAAA,KAIpC,sBAAA,GAAyB,CAAA,CAAE,KAAA,QAC9B,4BAAA;AAAA,KAEG,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,oBAAA"}
1
+ {"version":3,"file":"manifest.d.ts","names":[],"sources":["../../src/schemas/manifest.ts"],"mappings":";;;cAsPa,yBAAA,EAAyB,CAAA,CAAA,qBAAA,EAAA,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;cA8FzB,wBAAA,EAAwB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAkQxB,4BAAA,EAA4B,CAAA,CAAA,SAAA;;;;;cAoE5B,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAqgBrB,mBAAA,GAAsB,CAAA,CAAE,KAAA,QAAa,yBAAA;AAAA,KACrC,kBAAA,GAAqB,CAAA,CAAE,KAAA,QAAa,wBAAA;AAAA,KAIpC,sBAAA,GAAyB,CAAA,CAAE,KAAA,QAC9B,4BAAA;AAAA,KAEG,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,oBAAA"}
@@ -334,6 +334,7 @@ const pluginManifestSchema = z.object({
334
334
  license: z.string().optional().describe("SPDX license identifier"),
335
335
  onSetupMessage: z.string().optional().describe("Message displayed to the user after project initialization. Use this to inform about manual setup steps (e.g. environment variables, resource provisioning)."),
336
336
  hidden: z.boolean().optional().describe("When true, this plugin is excluded from the template plugins manifest (appkit.plugins.json) during sync."),
337
+ devOnly: z.boolean().optional().describe("When true, this plugin is only registered when NODE_ENV === 'development'. In any other environment createApp skips it entirely (not constructed, no routes, resources not validated). Use for dev-only tooling that must never run in a deployed app."),
337
338
  stability: z.enum(["beta", "ga"]).optional().describe("Plugin stability level. Beta plugins may have breaking API changes between minor releases but are on a path to GA. GA (general availability) plugins follow semver strictly."),
338
339
  scaffolding: z.object({ rules: pluginScaffoldingRulesSchema.optional().describe("Structured rules for scaffolding agents declared at the plugin level.") }).strict().optional().describe("Plugin-level scaffolding metadata consumed by scaffolding agents. Symmetric with template-level `scaffolding`.")
339
340
  }).strict().describe("Schema for Databricks AppKit plugin manifest files. Defines plugin metadata, resource requirements, and configuration options.");