@stackable-labs/mcp-app-extension 0.23.0 → 0.24.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 (3) hide show
  1. package/dist/index.js +653 -50
  2. package/dist/server.js +653 -50
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -532,6 +532,8 @@ const result = await capabilities.data.fetch('https://api.example.com/orders', {
532
532
  - For optional secret fields, the entire header is omitted if the value is not configured
533
533
  - Declare secret fields in your \`manifest.json\` \`settingsSchema\` with \`"secret": true\`
534
534
 
535
+ > See [Instance Settings](./instance-settings) for the full schema-declaration + storage-mode story, including which field types accept \`secret: true\`.
536
+
535
537
  ## context.read \u2014 Read Host Context
536
538
  Read host-provided context (customer ID, email, extension settings, etc.).
537
539
  - **Permission required:** \`context:read\`
@@ -1150,6 +1152,202 @@ const context = await capabilities.context.read()
1150
1152
  \`\`\`
1151
1153
  `;
1152
1154
  };
1155
+
1156
+ // ../../sdk/extension/ai-docs/src/generators/instance-settings.ts
1157
+ var SECRET_ALLOWED = ["text", "textarea", "email"];
1158
+ var generateInstanceSettings = () => {
1159
+ const fm = frontmatter({
1160
+ root: false,
1161
+ targets: ["*"],
1162
+ description: "Instance Settings: declaring per-Instance configuration in your extension manifest, the install-time admin form, and reading both regular and secure values from extension code.",
1163
+ globs: ["packages/extension/src/**/*.tsx", "packages/extension/src/**/*.ts", "packages/extension/public/manifest.json"]
1164
+ });
1165
+ return `${fm}
1166
+
1167
+ # Instance Settings
1168
+
1169
+ Instance Settings are the per-Instance configuration values your extension needs in
1170
+ order to do its job \u2014 API keys, account identifiers, environment toggles, feature
1171
+ flags. You declare them once in your extension's \`manifest.json\`; whoever installs
1172
+ your extension fills them in from the admin dashboard at install time; your code
1173
+ reads the values at runtime.
1174
+
1175
+ There are two flavors:
1176
+
1177
+ - **Regular** values live in plaintext and are readable from your extension code.
1178
+ Use them for non-sensitive configuration the UI needs to branch on.
1179
+ - **Secure** values are encrypted at rest and **never** leave the server. Use them
1180
+ for credentials. Your code references them as a placeholder; the proxy
1181
+ substitutes the real value server-side when it makes the outbound request.
1182
+
1183
+ ## 1. Declare your settings in \`manifest.json\`
1184
+
1185
+ Add a \`settingsSchema\` array to \`packages/extension/public/manifest.json\`. Each
1186
+ entry describes one input on the install-time admin form:
1187
+
1188
+ \`\`\`json
1189
+ {
1190
+ "name": "My Extension",
1191
+ "version": "1.0.0",
1192
+ "targets": ["slot.content"],
1193
+ "permissions": ["context:read", "data:fetch"],
1194
+ "allowedDomains": ["api.example.com"],
1195
+ "settingsSchema": [
1196
+ {
1197
+ "identifier": "apiKey",
1198
+ "label": "API Key",
1199
+ "type": "text",
1200
+ "secret": true,
1201
+ "required": true,
1202
+ "description": "Your account API key. Stored encrypted; injected server-side into outbound request headers."
1203
+ },
1204
+ {
1205
+ "identifier": "environmentType",
1206
+ "label": "Environment",
1207
+ "type": "select",
1208
+ "options": [
1209
+ { "label": "Production", "value": "prod" },
1210
+ { "label": "Sandbox", "value": "sandbox" }
1211
+ ]
1212
+ }
1213
+ ]
1214
+ }
1215
+ \`\`\`
1216
+
1217
+ That's the entire authoring step. The next time someone installs (or re-syncs)
1218
+ your extension, the admin dashboard renders a form from this schema on the
1219
+ Instance settings page. Regular fields show inline values; secret fields show a
1220
+ masked input that accepts a value once and displays \`\u2022\u2022\u2022\u2022\` after save (the
1221
+ cleartext value is never returned by the API).
1222
+
1223
+ ### Field types
1224
+
1225
+ | Type | Renders as | Accepts \`secret: true\` |
1226
+ |------|------------|--------------------------|
1227
+ | \`text\` | Single-line text input | Yes |
1228
+ | \`textarea\` | Multi-line text input | Yes |
1229
+ | \`email\` | Email input with format validation | Yes |
1230
+ | \`number\` | Numeric input (\`min\` / \`max\` / \`step\`) | No |
1231
+ | \`select\` | Dropdown (use \`allowMultiple\` for multi-select) | No |
1232
+ | \`radio\` | Radio button group | No |
1233
+ | \`toggle\` | On/off switch | No |
1234
+ | \`tags\` | Tag list / multi-string entry | No |
1235
+
1236
+ The \`secret: true\` flag is only valid on \`${SECRET_ALLOWED.join("`, `")}\` types.
1237
+
1238
+ All fields share these optional properties: \`required\`, \`placeholder\`,
1239
+ \`description\` (help text shown below the input), and \`dependsOn\` (conditional
1240
+ visibility \u2014 show this field only when another field has a matching value).
1241
+
1242
+ ## 2. The install-time admin form
1243
+
1244
+ When someone installs your extension into one of their Instances, the admin
1245
+ dashboard reads your \`settingsSchema\` and generates a form. Each field becomes
1246
+ an input; \`required\` fields block save; \`description\` text becomes inline help;
1247
+ \`dependsOn\` rules show or hide fields based on other field values.
1248
+
1249
+ Each Instance gets its own copy of these values, so the same extension can run
1250
+ side-by-side on multiple Instances with completely different credentials and
1251
+ configuration. The installer can edit values later from the same Instance
1252
+ settings page \u2014 your code always sees the current values.
1253
+
1254
+ ## 3. Read regular values: \`useSettings()\` (or \`useContextData()\`)
1255
+
1256
+ Regular (non-secret) values are exposed to your extension code via the
1257
+ \`useSettings()\` hook, keyed by each field's \`identifier\`. This requires the
1258
+ \`context:read\` permission.
1259
+
1260
+ \`\`\`tsx
1261
+ import { Surface, ui, useSettings } from '@stackable-labs/sdk-extension-react'
1262
+
1263
+ export const Content = () => {
1264
+ const settings = useSettings()
1265
+ const environmentType = (settings.environmentType as string) || 'prod'
1266
+
1267
+ return (
1268
+ <Surface id="slot.content">
1269
+ <ui.Card>
1270
+ <ui.CardContent>
1271
+ <ui.Text>Looking up orders\u2026</ui.Text>
1272
+ {environmentType === 'sandbox' && (
1273
+ <ui.Text className="text-xs opacity-50">Sandbox Mode</ui.Text>
1274
+ )}
1275
+ </ui.CardContent>
1276
+ </ui.Card>
1277
+ </Surface>
1278
+ )
1279
+ }
1280
+ \`\`\`
1281
+
1282
+ If you need settings alongside other context data (customer, locale, etc.), they
1283
+ also come back from \`useContextData()\`:
1284
+
1285
+ \`\`\`tsx
1286
+ import { useContextData } from '@stackable-labs/sdk-extension-react'
1287
+
1288
+ const { loading, settings, customerId } = useContextData()
1289
+ \`\`\`
1290
+
1291
+ > **Note:** Secret fields are **never** present in \`useSettings()\` or on
1292
+ > \`ctx.settings\`. Reading \`settings.apiKey\` for a \`secret: true\` field returns
1293
+ > \`undefined\`, even when a value is configured. If you find yourself reaching
1294
+ > for a secret value in extension code, you almost certainly want the
1295
+ > \`data.fetch\` placeholder pattern below instead.
1296
+
1297
+ ## 4. Use secure values: \`{{settings.<identifier>}}\` in \`data.fetch\`
1298
+
1299
+ Secure values are decrypted only by the proxy Lambda that handles \`data.fetch\` \u2014
1300
+ at substitution time, per-request, then discarded. Your code references them as
1301
+ template placeholders in **header values**:
1302
+
1303
+ \`\`\`tsx
1304
+ import { useCapabilities, useSettings } from '@stackable-labs/sdk-extension-react'
1305
+
1306
+ const capabilities = useCapabilities()
1307
+ const settings = useSettings()
1308
+ const environmentType = (settings.environmentType as string) || 'prod'
1309
+
1310
+ const result = await capabilities.data.fetch('https://api.example.com/orders', {
1311
+ method: 'GET',
1312
+ headers: {
1313
+ // environmentType is a regular value \u2014 interpolate it normally
1314
+ 'X-Environment': environmentType,
1315
+ // apiKey is secret \u2014 the proxy substitutes it server-side; the cleartext
1316
+ // value never enters this code path
1317
+ 'X-Api-Key': '{{settings.apiKey}}',
1318
+ },
1319
+ })
1320
+ if (!result.ok) throw new Error(\`Request failed: \${result.status}\`)
1321
+ \`\`\`
1322
+
1323
+ Placeholders are only resolved in **header values** \u2014 not URLs, not header
1324
+ names, not the request body. For \`required: true\` secret fields the proxy
1325
+ returns \`400\` when the value is not configured; for optional secret fields
1326
+ the entire header is omitted.
1327
+
1328
+ ## Regular vs secure at a glance
1329
+
1330
+ | | Regular | Secure (\`secret: true\`) |
1331
+ |--|---------|--------------------------|
1332
+ | **Stored** | Plaintext | Encrypted with a per-Instance derived key |
1333
+ | **Readable from extension code?** | Yes \u2014 \`useSettings().<identifier>\` | **Never** \u2014 secrets are not serialized to the browser or sandbox |
1334
+ | **How to use the value** | Read at render time and use freely | Reference as a \`{{settings.<identifier>}}\` placeholder in \`data.fetch\` headers \u2014 the proxy substitutes server-side |
1335
+ | **Returned by admin API after save?** | Yes (the value is shown back in the form) | No (the form shows \`\u2022\u2022\u2022\u2022\`; the cleartext value is unrecoverable) |
1336
+
1337
+ ## When in doubt, mark it \`secret: true\`
1338
+
1339
+ The cost is negligible \u2014 one encryption per write, one decryption per outbound
1340
+ request. The blast radius of an accidental log line, screenshot, or sandbox
1341
+ exfiltration drops to zero. Secrets on one Instance also can't be used to
1342
+ decrypt secrets on any other Instance, even when both Instances run the same
1343
+ extension \u2014 encryption keys are derived per-Instance.
1344
+
1345
+ If a value is sensitive at all (API keys, OAuth tokens, signing secrets, webhook
1346
+ shared secrets, personal access tokens), declare the field \`secret: true\` and
1347
+ reach for it via the \`data.fetch\` placeholder pattern. Save \`useSettings()\` for
1348
+ the values your UI legitimately needs to branch on.
1349
+ `;
1350
+ };
1153
1351
  var generatePermissions = () => {
1154
1352
  const fm = frontmatter({
1155
1353
  root: false,
@@ -1545,17 +1743,30 @@ export const Header = () => {
1545
1743
  var DLX = "pnpm --config.dlx-cache-max-age=0 dlx";
1546
1744
  var CLI = {
1547
1745
  /** Scaffold a new extension project */
1548
- create: (name = "<project-name>") => `${DLX} @stackable-labs/create-extension ${name}`,
1746
+ create: (name = "<extension-name>") => `${DLX} @stackable-labs/create-extension ${name}`,
1549
1747
  /** Start dev servers with hot reload */
1550
1748
  dev: `${DLX} @stackable-labs/cli-app-extension@latest dev`,
1551
- /** Deploy the extension */
1749
+ /** Deploy the extension (future) */
1552
1750
  deploy: `${DLX} @stackable-labs/cli-app-extension@latest deploy`,
1553
- /** Validate the extension for common errors */
1751
+ /** Validate the extension for common errors (coming soon) */
1554
1752
  validate: `${DLX} @stackable-labs/cli-app-extension@latest validate`,
1555
1753
  /** Scaffold from an existing extension */
1556
1754
  scaffold: `${DLX} @stackable-labs/cli-app-extension@latest scaffold`,
1557
1755
  /** Update an existing extension */
1558
- update: `${DLX} @stackable-labs/cli-app-extension@latest update`
1756
+ update: `${DLX} @stackable-labs/cli-app-extension@latest update`,
1757
+ /** Manage CLI authentication (browser-based OAuth) */
1758
+ auth: {
1759
+ login: `${DLX} @stackable-labs/cli-app-extension@latest auth login`,
1760
+ logout: `${DLX} @stackable-labs/cli-app-extension@latest auth logout`,
1761
+ status: `${DLX} @stackable-labs/cli-app-extension@latest auth status`
1762
+ },
1763
+ /** AI editor configuration tools (Skills + MCP) */
1764
+ ai: {
1765
+ /** Download AI editor config files (Stackable Skills) into your project */
1766
+ scaffold: `${DLX} @stackable-labs/cli-app-extension@latest ai scaffold`,
1767
+ /** Add Stackable MCP server config to your project */
1768
+ mcp: `${DLX} @stackable-labs/cli-app-extension@latest ai mcp`
1769
+ }
1559
1770
  };
1560
1771
  var TEMPLATE_FLAVORS = [
1561
1772
  { name: "minimal", label: "Minimal", description: "Bare minimum \u2014 single surface, hello-world component" },
@@ -1577,6 +1788,21 @@ var generateQuickStart = () => {
1577
1788
 
1578
1789
  Create, develop, and deploy your first Stackable extension in minutes.
1579
1790
 
1791
+ ## Choosing your path
1792
+
1793
+ Stackable supports two authoring paths. Both produce the same kind of extension and ship to the same marketplace.
1794
+
1795
+ | | AI Extension Studio | CLI (this guide) |
1796
+ |---|---|---|
1797
+ | **Best for** | Prototyping, learning, quick iterations | Production extensions, team workflows |
1798
+ | **Code structure** | Single file | Multi-file (surfaces/, components/, lib/) |
1799
+ | **Preview** | Built-in live preview | Local dev server + Cloudflare tunnel |
1800
+ | **AI assistance** | Sidekick chat + smart insertion | Skills, MCP server, and Claude Code plugin (see [AI-Accelerated Development](/docs/reference/ai-accelerated-development)) |
1801
+ | **Version control** | Auto-saved to cloud | Git-based |
1802
+ | **Deployment** | Link to extension + deploy | CLI deploy command |
1803
+
1804
+ Both produce the same output \u2014 a Stackable extension that runs in the host application via the same Remote DOM pipeline. **This guide covers the [CLI](/docs/reference/cli-reference) path.** For Studio, see [AI Extension Studio](/docs/reference/extension-studio).
1805
+
1580
1806
  ## Prerequisites
1581
1807
 
1582
1808
  - **Node.js** 22 or later
@@ -1715,21 +1941,11 @@ export const Content = () => {
1715
1941
  }
1716
1942
  \`\`\`
1717
1943
 
1718
- ## 6. Validate & Deploy
1719
-
1720
- Before deploying, validate your extension:
1721
-
1722
- \`\`\`bash
1723
- ${CLI.validate}
1724
- \`\`\`
1725
-
1726
- This checks manifest structure, permission usage, surface targets, and import patterns.
1944
+ ## 6. Submit for review
1727
1945
 
1728
- When ready, deploy:
1946
+ When your extension is ready, open it in the [Stackable admin dashboard](https://admin.stackablelabs.com), fill in the marketplace listing (icon, screenshots, description, tagline, support links), and submit for review. Most reviews complete within a few business days.
1729
1947
 
1730
- \`\`\`bash
1731
- ${CLI.deploy}
1732
- \`\`\`
1948
+ > *CLI \`validate\` and \`deploy\` commands are on the roadmap (see [CLI Reference](/docs/reference/cli-reference#validate-coming-soon)). Today, manifests are validated server-side during submission and via the \`validate_manifest\` MCP tool.*
1733
1949
 
1734
1950
  ## Next Steps
1735
1951
 
@@ -1767,7 +1983,7 @@ ${CLI.create()}
1767
1983
 
1768
1984
  | Argument | Description |
1769
1985
  |----------|-------------|
1770
- | \`project-name\` | Directory name for the new project |
1986
+ | \`extension-name\` | Name for your extension (saved as the manifest's \`name\`; kebab-cased to derive the directory and extension ID) |
1771
1987
 
1772
1988
  **Options:**
1773
1989
 
@@ -1828,9 +2044,11 @@ Append this to your deployed host app URL to load your local extension instead
1828
2044
  of the production bundle. The override is browser-session only \u2014 no DB changes,
1829
2045
  no shared state. Each developer gets isolated overrides.
1830
2046
 
1831
- ## validate
2047
+ ## validate *(coming soon)*
1832
2048
 
1833
- Check your extension for common errors before deploying:
2049
+ > *NOTE: manifests are validated server-side during the marketplace submission flow, in the AI Studio, or can be validated using the \`validate_manifest\` MCP tool \u2014 see [AI-Accelerated Development](/docs/reference/ai-accelerated-development#live-mcp-server).*
2050
+
2051
+ When shipped, the \`validate\` command will check your extension for common errors locally before submission:
1834
2052
 
1835
2053
  \`\`\`bash
1836
2054
  ${CLI.validate}
@@ -1851,23 +2069,21 @@ ${CLI.validate}
1851
2069
  - \`0\` \u2014 all checks pass
1852
2070
  - \`1\` \u2014 errors found (must fix before deploying)
1853
2071
 
1854
- ## deploy
2072
+ ## deploy *(future)*
2073
+
2074
+ > *This command is on the roadmap. Currently build, deployment and hosting are the responsibility of the extension developer with your hosted Bundle URL being updated via the admin dashboard or via CLI.*
1855
2075
 
1856
- Package and deploy the extension:
2076
+ When shipped, the \`deploy\` command will package and ship your extension straight from the terminal:
1857
2077
 
1858
2078
  \`\`\`bash
1859
2079
  ${CLI.deploy}
1860
2080
  \`\`\`
1861
2081
 
1862
- **What it does:**
1863
- 1. Runs validation checks (same as validate)
1864
- 2. Builds the extension for production
1865
- 3. Packages the build output
1866
- 4. Uploads to the Stackable extension registry
1867
-
1868
- **Prerequisites:**
1869
- - All validation checks must pass
1870
- - You must be authenticated (follow the prompts if not)
2082
+ **Planned behavior:**
2083
+ 1. Run validation checks (same as \`validate\`)
2084
+ 2. Build the extension for production
2085
+ 3. Package the build output
2086
+ 4. Upload to the Stackable extension registry
1871
2087
 
1872
2088
  ## scaffold
1873
2089
 
@@ -1904,6 +2120,62 @@ ${CLI.update} [extensionId]
1904
2120
  | \`--bundle-url <url>\` | New bundle URL |
1905
2121
  | \`--enabled <bool>\` | Enable/disable extension |
1906
2122
  | \`--dir <path>\` | Project root (default: cwd) |
2123
+
2124
+ ## auth
2125
+
2126
+ Manage CLI authentication. Subcommands open a browser-based OAuth flow against the Stackable platform and store the resulting credentials locally.
2127
+
2128
+ **Subcommands:**
2129
+
2130
+ | Subcommand | Description |
2131
+ |------------|-------------|
2132
+ | \`login\` | Authenticate with Stackable via browser-based OAuth |
2133
+ | \`logout\` | Clear stored CLI credentials |
2134
+ | \`status\` | Show current authentication status (signed-in user, org, token expiry) |
2135
+
2136
+ **Examples:**
2137
+
2138
+ \`\`\`bash
2139
+ # First-time setup
2140
+ ${CLI.auth.login}
2141
+
2142
+ # Check who's signed in
2143
+ ${CLI.auth.status}
2144
+
2145
+ # Sign out
2146
+ ${CLI.auth.logout}
2147
+ \`\`\`
2148
+
2149
+ ## ai
2150
+
2151
+ Manage AI editor configuration in your Extension project. Subcommands write Stackable's [AI tooling](/docs/reference/ai-accelerated-development) (Skills + MCP server config) into your project.
2152
+
2153
+ **Subcommands:**
2154
+
2155
+ | Subcommand | Description |
2156
+ |------------|-------------|
2157
+ | \`scaffold\` | Download Stackable Skills into your project's \`.claude/\`, \`.cursor/\`, \`.windsurf/\`, etc. |
2158
+ | \`mcp\` | Add Stackable MCP server config to your project so any MCP-compatible AI client can connect |
2159
+
2160
+ **Options:**
2161
+
2162
+ | Flag | Description | Applies to |
2163
+ |------|-------------|------------|
2164
+ | \`--version <version>\` | AI docs version (semver or \`latest\`, default: \`latest\`) | both |
2165
+ | \`--dir <path>\` | Project root directory (default: cwd) | \`mcp\` only |
2166
+
2167
+ **Examples:**
2168
+
2169
+ \`\`\`bash
2170
+ # Add the latest Stackable Skills to your project
2171
+ ${CLI.ai.scaffold}
2172
+
2173
+ # Pin a specific version
2174
+ ${CLI.ai.scaffold} --version 0.2.0
2175
+
2176
+ # Configure your project to talk to the Stackable MCP server
2177
+ ${CLI.ai.mcp}
2178
+ \`\`\`
1907
2179
  `;
1908
2180
  };
1909
2181
 
@@ -2062,29 +2334,29 @@ var generateExtensionStudio = () => {
2062
2334
  const fm = frontmatter({
2063
2335
  root: false,
2064
2336
  targets: ["*"],
2065
- description: "Extension Studio: in-browser builder with AI assistant, component palette, and live preview",
2337
+ description: "AI Extension Studio: in-browser builder with AI assistant, component palette, and live preview",
2066
2338
  globs: ["packages/extension/src/**/*.tsx", "packages/extension/src/**/*.ts"]
2067
2339
  });
2068
2340
  return `${fm}
2069
2341
 
2070
- # Extension Studio
2342
+ # AI Extension Studio
2071
2343
 
2072
- Extension Studio is an in-browser development environment for building Stackable
2344
+ Stackable's AI Extension Studio is an in-browser development environment for building Stackable
2073
2345
  extensions without local tooling. It runs inside the admin dashboard and provides
2074
2346
  a code editor, live preview, component palette, and an AI assistant \u2014 everything
2075
2347
  needed to create, iterate on, and deploy extensions from the browser.
2076
2348
 
2077
2349
  ## Layout
2078
2350
 
2079
- Studio is organized as a 3-pane workspace:
2351
+ "Studio" is organized as a 3-pane workspace:
2080
2352
 
2081
2353
  | Pane | Position | Purpose |
2082
2354
  |------|----------|---------|
2083
2355
  | **Shelf** | Left (collapsible) | Component palette, surface picker, capability list |
2084
- | **Stage** | Center | Code editor (CodeMirror) or live preview \u2014 toggle between modes |
2356
+ | **Stage** | Center | Code editor or live preview \u2014 toggle between modes |
2085
2357
  | **Sidekick** | Right (collapsible, resizable) | AI chat assistant for code generation and SDK guidance |
2086
2358
 
2087
- ## The Shelf
2359
+ ## The "Shelf"
2088
2360
 
2089
2361
  The Shelf is a collapsible sidebar with three sections:
2090
2362
 
@@ -2109,7 +2381,7 @@ The SDK capabilities your extension can use: \`data.query\`, \`data.fetch\`,
2109
2381
  \`events:identity\`, \`events:messaging\`, and \`events:activity\`. Clicking a
2110
2382
  capability adds the permission to your manifest and AI-inserts the hook usage.
2111
2383
 
2112
- ## The Stage
2384
+ ## The "Stage"
2113
2385
 
2114
2386
  The center pane switches between two modes:
2115
2387
 
@@ -2124,7 +2396,7 @@ Changes in Code mode recompile automatically via in-browser esbuild and update
2124
2396
  the preview. The toolbar shows the current status: Ready, Saving, Compiling,
2125
2397
  Thinking (AI), or Error.
2126
2398
 
2127
- ## The Sidekick
2399
+ ## The "Sidekick"
2128
2400
 
2129
2401
  The Sidekick is an AI chat assistant that understands the Stackable Extension SDK.
2130
2402
  It can:
@@ -2164,18 +2436,114 @@ Studio toolbar.
2164
2436
 
2165
2437
  ## Studio vs CLI
2166
2438
 
2167
- | | Studio | CLI |
2439
+ Comparing approaches? See [Choosing your path](/docs/guides/quick-start#choosing-your-path) in the Quick Start guide for the full Studio vs CLI comparison.
2440
+
2441
+ Both workflows produce the same output \u2014 a Stackable extension that runs in the host application via the same Remote DOM pipeline. Start in Studio to prototype, then scaffold to CLI when you need the full development workflow.
2442
+ `;
2443
+ };
2444
+
2445
+ // ../../sdk/extension/ai-docs/src/generators/ai-accelerated-development.ts
2446
+ var generateAIAcceleratedDevelopment = () => {
2447
+ const fm = frontmatter({
2448
+ root: false,
2449
+ targets: ["*"],
2450
+ description: "AI-Accelerated Development: AI Extension Studio, Agent Skills, the live MCP server, and the Claude Code plugin \u2014 and how to choose between them.",
2451
+ globs: ["*"]
2452
+ });
2453
+ return `${fm}
2454
+
2455
+ # AI-Accelerated Development
2456
+
2457
+ Stackable's AI-native messaging experience platform makes building extensions really simple - and incredibly fast. Four complementary surfaces (Studio, Agent Skills, MCP Server, and Claude Code Plugin) take you from possibility to production in minutes.
2458
+
2459
+ | Surface | Best for | Install |
2168
2460
  |---|---|---|
2169
- | **Best for** | Prototyping, learning, quick iterations | Production extensions, team workflows |
2170
- | **Code structure** | Single file | Multi-file (surfaces/, components/, lib/) |
2171
- | **Preview** | Built-in live preview | Local dev server + Cloudflare tunnel |
2172
- | **AI assistance** | Sidekick chat + smart insertion | Your own AI editor (with SDK skills) |
2173
- | **Version control** | Auto-saved to cloud | Git-based |
2174
- | **Deployment** | Link to extension + deploy | CLI deploy command |
2461
+ | **AI Extension Studio** | First extensions, prototyping, in-browser builds | Open the admin dashboard |
2462
+ | **Agent Skills** | Any AI coding assistant | \`pnpm dlx skills add stackable-labs/skills\` (auto-bundled in scaffolds) |
2463
+ | **Live MCP Server** | AI clients that speak MCP | Add to your client's MCP config |
2464
+ | **Claude Code Plugin** | Claude Code users (bundles Skills + MCP) | \`/plugin marketplace add stackable-labs/claude-plugins\` |
2465
+
2466
+ ---
2467
+
2468
+ ## AI Extension Studio
2469
+
2470
+ AI Extension Studio is more than just another AI App builder ([Lovable](https://lovable.dev), [v0](https://v0.dev), [Bolt](https://bolt.new), [Replit](https://replit.com), etc.). It's an in-browser companion trained specifically to conceptualize and build experiences for the Stackable framework that are secure, look great, and are **production ready in minutes!**
2471
+
2472
+ The 3-pane workspace (component palette, live preview, agentic chat) takes you from idea to shipped code in moments. The agentic chat ("Sidekick") writes and modifies code, updates your manifest, looks up SDK reference on demand, and suggests next steps as you work. No installs, no Node version to manage, no tunnel \u2014 open the admin dashboard and you're building.
2473
+
2474
+ **Best for:** first extensions, prototyping, non-developers, and quick experiments.
2475
+
2476
+ **When to move to the CLI:** Studio produces a simple single-file project. When you need multi-file structure, custom dependencies, your own build pipeline, or git-based version control, you can transition seamlessly. Either download your Studio project as a ZIP from the export menu, or pull it directly via the CLI. Either path produces a fully-structured local project ready for production build and deployment.
2477
+
2478
+ For full Studio details, see [AI Extension Studio](/docs/reference/extension-studio).
2479
+
2480
+ ## AI Agentic Skills
2481
+
2482
+ [Agent Skills](https://agentskills.io) is an open standard for publishing machine-readable knowledge that AI coding assistants can pull on demand instead of crawling your docs. Stackable publishes the core SDK concepts (surfaces, capabilities, components, hooks, patterns, recipes, and more) as Agent Skills, so any compatible assistant has just-in-time access to exactly the surface area it needs.
2483
+
2484
+ ### How to install
2485
+
2486
+ - **Bundled automatically when you scaffold** \u2014 \`@stackable-labs/cli-app-extension create\` writes the Stackable Skills into your project's \`.claude/\`, \`.cursor/\`, \`.windsurf/\`, and equivalent directories. No extra setup.
2487
+ - **Standalone install** \u2014 for an existing project, or to update to the latest skills, run:
2488
+ \`\`\`bash
2489
+ pnpm dlx skills add stackable-labs/skills
2490
+ \`\`\`
2491
+ This is powered by [Vercel's open \`skills\` CLI](https://github.com/vercel-labs/skills).
2492
+
2493
+ ### Compatible assistants
2494
+
2495
+ Agent Skills work with any tool that supports the format \u2014 Claude Code, Cursor, Windsurf, Codex, VS Code (with MCP-aware extensions), Continue, Zed, and 40+ others listed on agentskills.io. Stackable's Claude Code plugin (below) bundles + auto-updates these skills for Claude Code users.
2496
+
2497
+ ## Live MCP Server
2498
+
2499
+ The Stackable platform exposes a hosted MCP (Model Context Protocol) server that any compatible AI client can connect to for live access to your account's apps, extensions, and platform metadata.
2500
+
2501
+ **Endpoint:** \`https://api-use1.stackablelabs.io/mcp/app-extension\`
2175
2502
 
2176
- Both workflows produce the same output \u2014 a Stackable extension that runs in the
2177
- host application via the same Remote DOM pipeline. Start in Studio to prototype,
2178
- then scaffold to CLI when you need the full development workflow.
2503
+ ### Available tools (snapshot)
2504
+
2505
+ | Tool | What it does |
2506
+ |---|---|
2507
+ | \`list_apps\` | List apps in your account |
2508
+ | \`list_extensions\` | List extensions for a given app |
2509
+ | \`list_instances\` | List deployed instances of an extension |
2510
+ | \`list_skills\` | List available SDK skills |
2511
+ | \`lookup_skill\` | Fetch a specific SDK skill's content on demand |
2512
+ | \`get_extension\` | Fetch full details for a single extension |
2513
+ | \`validate_manifest\` | Validate an extension manifest against the platform |
2514
+ | \`validate_permissions\` | Validate manifest permissions |
2515
+
2516
+ ### Compatible clients
2517
+
2518
+ [Claude Desktop](https://claude.ai/download), [VS Code](https://code.visualstudio.com), [Cursor](https://cursor.com), [Codex](https://developers.openai.com/codex), [Antigravity](https://antigravity.google), [Windsurf](https://windsurf.com), and any other MCP-compatible AI tool. Each client has its own way to register MCP servers \u2014 see your client's docs for the exact config syntax.
2519
+
2520
+ Authentication uses standard OAuth2 \u2014 your client will prompt you to sign in on first use.
2521
+
2522
+ ## Claude Code Plugin
2523
+
2524
+ For Claude Code users, the Stackable Claude Code plugin bundles the Skills and pre-configures the MCP server in one install.
2525
+
2526
+ **Install:**
2527
+ \`\`\`bash
2528
+ # Add marketplace
2529
+ /plugin marketplace add stackable-labs/claude-plugins
2530
+
2531
+ # Install plugin
2532
+ /plugin install stackable-extension-dev@stackable-claude-plugins
2533
+ \`\`\`
2534
+
2535
+ **What it includes:**
2536
+ - Latest Stackable Agent Skills (auto-updated)
2537
+ - The Stackable MCP server pre-configured
2538
+ - Slash commands and workflows tailored for extension development
2539
+
2540
+ After install, Claude Code can scaffold, validate, and inspect your Stackable extensions directly from your editor without any extra config.
2541
+
2542
+ ## Choosing your tools
2543
+
2544
+ - **Just starting?** Open [AI Extension Studio](/docs/reference/extension-studio) in the admin dashboard. No installs, no decisions \u2014 get started on your first extension right in the browser.
2545
+ - **Want more control, or preparing for release?** Use the [CLI](/docs/guides/quick-start) for a full local TypeScript project: multi-file structure, your own dependencies, git-based version control, and your own build pipeline.
2546
+ - **Building from scratch with your own AI workflow?** Wire up your editor with [Agent Skills](#ai-agentic-skills), the [Live MCP Server](#live-mcp-server), or both \u2014 or use the [Claude Code Plugin](#claude-code-plugin) for Claude Code users, which auto-bundles Skills and pre-configures the MCP server in one install.
2179
2547
  `;
2180
2548
  };
2181
2549
  var generateProjectStructure = () => {
@@ -3019,7 +3387,17 @@ var generateValidateExtensionCommand = () => {
3019
3387
  # Validate Extension
3020
3388
 
3021
3389
  Check this extension for common errors before deploying. Run through each check
3022
- and report all issues found.
3390
+ and ensure no issues found before you submit.
3391
+
3392
+ > **Tip \u2014 let the platform validate for you.** The hosted Stackable MCP server
3393
+ > exposes a \`validate_manifest\` tool that runs the same server-side checks the
3394
+ > marketplace submission flow uses. If your AI client is connected to the
3395
+ > Stackable MCP server (see [AI-Accelerated Development](/docs/reference/ai-accelerated-development#live-mcp-server)),
3396
+ > just ask it to validate \`packages/extension/public/manifest.json\` for you \u2014
3397
+ > it returns structured errors and warnings without you having to walk the
3398
+ > checklist below by hand. The manual steps remain useful for code-level checks
3399
+ > the manifest validator can't see (permission usage, surface wiring, sandbox
3400
+ > compliance).
3023
3401
 
3024
3402
  ## 1. Manifest validation
3025
3403
  Read \`packages/extension/public/manifest.json\` and verify:
@@ -3061,6 +3439,202 @@ Verify that:
3061
3439
  ## 5. Summary
3062
3440
  Print a summary: total issues found, categorized by severity (error vs warning).
3063
3441
  Errors must be fixed before deploying. Warnings are recommendations.
3442
+
3443
+ ## Next: deploy
3444
+
3445
+ Once validation passes, build the production bundle, host it, and register the
3446
+ Bundle URL with Stackable. See the [Deploy guide](/docs/guides/deploy).
3447
+ `;
3448
+ };
3449
+
3450
+ // ../../sdk/extension/ai-docs/src/commands/deploy-extension.ts
3451
+ var generateDeployExtensionCommand = () => {
3452
+ const fm = frontmatter({
3453
+ description: "Build, host, and register the production Bundle URL for this Stackable extension",
3454
+ targets: ["*"]
3455
+ });
3456
+ return `${fm}
3457
+
3458
+ # Deploy
3459
+
3460
+ Stackable hosts the marketplace, the proxy, and the runtime \u2014 but **you host
3461
+ your extension's bundle/runtime**. Deployment is three steps: build for production,
3462
+ upload to a host of your choice, then point your extension's **Bundle URL** at
3463
+ the result.
3464
+
3465
+ ## 1. Build the production bundle
3466
+
3467
+ From the project root:
3468
+
3469
+ \`\`\`bash
3470
+ pnpm build
3471
+ \`\`\`
3472
+
3473
+ This runs Vite in production mode and writes the static bundle to
3474
+ \`packages/extension/dist/\` \u2014 a small set of JS/CSS files plus your
3475
+ \`manifest.json\`. That's the artifact you ship.
3476
+
3477
+ > **Tip:** Validate the build before you upload it. Run through the
3478
+ > [Validate guide](/docs/guides/validate) (or ask your AI client to call the
3479
+ > \`validate_manifest\` MCP tool) so manifest typos and missing permissions are
3480
+ > caught before they reach the marketplace.
3481
+
3482
+ ## 2. Upload to a hosting provider
3483
+
3484
+ Stackable doesn't care where the bundle lives \u2014 only that it's served over
3485
+ HTTPS with permissive CORS so the host runtime can fetch it. Anything that
3486
+ serves static files works. The most common options:
3487
+
3488
+ | Provider | Notes |
3489
+ |----------|-------|
3490
+ | **Netlify** | Drop \`packages/extension/dist/\` into a site, or wire up Git auto-deploys. CORS is already permissive. |
3491
+ | **Vercel** | Same idea \u2014 link the repo and let Vercel build/deploy on push. Set the build output to \`packages/extension/dist\`. |
3492
+ | **Cloudflare Pages** | Connect the repo, set the output directory, deploys land on the edge globally. |
3493
+ | **AWS S3 + CloudFront** | Sync \`dist/\` to an S3 bucket, front it with a CloudFront distribution. Make sure the CloudFront response headers include \`Access-Control-Allow-Origin: *\` (or your host origin). |
3494
+ | **Your own CDN / object storage** | Anything that returns \`200 OK\` with the right \`Content-Type\` and CORS headers will work. |
3495
+
3496
+ Whichever you pick, the only requirements are:
3497
+
3498
+ - Bundle is reachable over **HTTPS**
3499
+ - CORS allows the host application's origin (most providers do this by default; S3+CloudFront is the one that usually needs explicit configuration)
3500
+ - The URL is **stable** \u2014 every Instance running your extension fetches from this URL on load
3501
+
3502
+ > **Need help with setup or deployment?** Reach out at [developers@stackablelabs.com](mailto:developers@stackablelabs.com) or open an issue / discussion on [GitHub](https://github.com/stackable-labs).
3503
+
3504
+ ## 3. Register your Bundle URL with Stackable
3505
+
3506
+ Once your extension bundle is deployed/live, tell Stackable where to find it. You have two options:
3507
+
3508
+ - **Admin dashboard** \u2014 open your extension at [admin.stackablelabs.com](https://admin.stackablelabs.com), edit the **Bundle URL** field, and save. Existing Instances pick up the new bundle the next time they load.
3509
+ - **CLI** \u2014 from the project directory:
3510
+
3511
+ \`\`\`bash
3512
+ ${CLI.update} --bundle-url https://your-host.example.com/manifest.json
3513
+ \`\`\`
3514
+
3515
+ Or, with an explicit extension ID (handy for CI/CD):
3516
+
3517
+ \`\`\`bash
3518
+ ${CLI.update} ext_xxx --bundle-url https://your-host.example.com/manifest.json
3519
+ \`\`\`
3520
+
3521
+ Point the URL at your bundle's \`manifest.json\` \u2014 that's the entrypoint the
3522
+ runtime fetches first; everything else is loaded relative to it.
3523
+
3524
+ ## 4. Roll out and iterate
3525
+
3526
+ That's the entire deploy loop. Subsequent updates follow the same path: bump
3527
+ \`version\` in \`manifest.json\`, run \`pnpm build\`, re-upload, and (only if the
3528
+ URL changed) re-register. Most teams wire steps 1\u20133 into a single CI/CD job
3529
+ that runs on every merge to \`main\`.
3530
+
3531
+ ## Next: list it on the Marketplace
3532
+
3533
+ Deploying makes your extension **runnable** at a stable URL. To make it
3534
+ **installable** by other organizations, you also need to fill in the
3535
+ marketplace listing (icon, screenshots, description, visibility) and submit
3536
+ for review. See [Marketplace Listing](/docs/reference/marketplace-listing).
3537
+ `;
3538
+ };
3539
+
3540
+ // ../../sdk/extension/ai-docs/src/commands/marketplace-listing.ts
3541
+ var generateMarketplaceListing = () => {
3542
+ const fm = frontmatter({
3543
+ description: "Fill in your marketplace listing, choose visibility, and submit your Stackable extension for review and approval",
3544
+ targets: ["*"]
3545
+ });
3546
+ return `${fm}
3547
+
3548
+ # Listing & Submission
3549
+
3550
+ Once your extension is built, hosted, and registered with a Bundle URL (see
3551
+ [Deploy](/docs/guides/deploy)), the last step is to make it discoverable and
3552
+ installable. That happens entirely in the [admin dashboard](https://admin.stackablelabs.com)
3553
+ \u2014 you fill in your marketplace listing, pick a visibility mode, and submit for
3554
+ review.
3555
+
3556
+ ## 1. Fill in the listing fields
3557
+
3558
+ Open your extension in the admin dashboard and complete the **Listing** tab.
3559
+ Every field below is part of the marketplace metadata that prospective
3560
+ installers see when browsing or evaluating your extension.
3561
+
3562
+ | Field | Required | What it's for |
3563
+ |-------|----------|---------------|
3564
+ | **Icon** | Yes | Square image rendered on browse cards and the detail page. Square aspect ratio, transparent background recommended. |
3565
+ | **Short description** | Yes | One-line summary used on browse cards and search results. Keep it under ~120 characters. |
3566
+ | **Long description** | Yes | Markdown body for the extension detail page. Cover what the extension does, the problem it solves, and any setup requirements. Screenshots and links allowed. |
3567
+ | **Screenshots** | Recommended | Image gallery shown on the detail page. Pick views that demonstrate the extension actually working in a host application. |
3568
+ | **Categories** | Yes | One or more curated categories from the platform taxonomy (e.g., commerce, support, analytics). Drives marketplace browse filters. |
3569
+ | **Tags** | Optional | Freeform searchable tags. Used for keyword search across the marketplace. |
3570
+ | **Publisher** | Auto | Pulled from your organization profile \u2014 the org name shown as the listing's publisher. Update your org profile in the dashboard if this needs to change. |
3571
+
3572
+ > **Tip:** The icon and screenshots are what make a listing feel real. A
3573
+ > placeholder icon and no screenshots is the single biggest reason listings
3574
+ > get a "needs more info" review response.
3575
+
3576
+ ## 2. Choose a visibility mode
3577
+
3578
+ Every listing has a **visibility** setting that controls who can install it:
3579
+
3580
+ | Visibility | Who can find and install it |
3581
+ |------------|------------------------------|
3582
+ | **Public** | Anyone browsing the marketplace. Goes through full marketplace review. Best for extensions you want available to everyone. |
3583
+ | **Protected** | Only organizations you explicitly add to the **allowed orgs** list. The listing is hidden from public browse; people you've allowed see it in their marketplace as if it were public. Best for private/internal extensions, paid customers, or staged rollouts. |
3584
+
3585
+ Visibility can be changed later from the same Listing tab. Switching from
3586
+ **Protected** \u2192 **Public** triggers a fresh marketplace review.
3587
+
3588
+ ## 3. Submit for review
3589
+
3590
+ Click **Submit for review**. The platform runs a two-stage review:
3591
+
3592
+ ### Stage 1 \u2014 Automated Bundle scan
3593
+
3594
+ Runs immediately on submit. The platform fetches your bundle from the
3595
+ registered Bundle URL and runs deterministic checks:
3596
+
3597
+ - Bundle reachable, valid \`manifest.json\`, sane bundle size
3598
+ - Declared permissions match observed capability usage
3599
+ - Declared targets match the surfaces your code actually registers
3600
+ - Declared \`allowedDomains\` match the endpoints \`data.fetch\` actually hits
3601
+ - No use of forbidden browser globals (\`document\`, \`window.location\`, etc.)
3602
+
3603
+ Findings come back categorized as **error**, **warning**, or **info**. Errors
3604
+ must be fixed before the listing can move forward. Warnings don't block
3605
+ submission but factor into the review.
3606
+
3607
+ ### Stage 2 \u2014 Advanced review + Stackable approval
3608
+
3609
+ If Stage 1 passes, the platform runs an advanced review of your bundle \u2014
3610
+ framework analysis, permission surface, network behavior, and any
3611
+ security-relevant findings get scored and assessed against your listing
3612
+ content. From there, Stackable will either:
3613
+
3614
+ - **Approve** \u2014 your listing moves to **Published** and becomes installable.
3615
+ - **Request changes** \u2014 you'll see structured feedback on the listing page. Address it, re-deploy if needed, and resubmit.
3616
+
3617
+ Most reviews complete within a few business days. You'll get an email when
3618
+ the status changes; the listing's review status is also visible in the admin
3619
+ dashboard at all times.
3620
+
3621
+ ## Review status lifecycle
3622
+
3623
+ | Status | Meaning |
3624
+ |--------|---------|
3625
+ | **Draft** | Listing is being edited; not submitted. |
3626
+ | **Pending review** | Submitted; waiting on Stage 1 + Stage 2 + Stackable approval. |
3627
+ | **Rejected** | Stackable requested changes. Address the feedback and resubmit. |
3628
+ | **Published** | Live in the marketplace. Installable per your visibility setting. |
3629
+ | **Suspended** | Pulled from the marketplace by Stackable (security issue, ToS violation, etc.). Contact support. |
3630
+
3631
+ ## After publishing
3632
+
3633
+ Re-deploys to the same Bundle URL don't require re-submission \u2014 your existing
3634
+ Instances pick up the new bundle automatically. **Listing edits** (description,
3635
+ screenshots, categories, visibility) and **major version bumps** do go through
3636
+ review again. Patch updates that don't change permissions, targets, or
3637
+ \`allowedDomains\` typically clear review quickly.
3064
3638
  `;
3065
3639
  };
3066
3640
 
@@ -3154,6 +3728,12 @@ var SKILLS = [
3154
3728
  type: "knowledge",
3155
3729
  content: () => generateStylingAndTheming()
3156
3730
  },
3731
+ {
3732
+ id: "instance-settings",
3733
+ description: "Instance Settings: declaring settingsSchema in your extension manifest, the install-time admin form, and reading regular values via useSettings() vs secure values via {{settings.x}} placeholders in data.fetch. Use when adding per-Instance configuration to an extension.",
3734
+ type: "knowledge",
3735
+ content: () => generateInstanceSettings()
3736
+ },
3157
3737
  // ── Docs-only knowledge skills ──────────────────────────────
3158
3738
  {
3159
3739
  id: "quick-start",
@@ -3183,6 +3763,13 @@ var SKILLS = [
3183
3763
  scopes: ["docs"],
3184
3764
  content: () => generateExtensionStudio()
3185
3765
  },
3766
+ {
3767
+ id: "ai-accelerated-development",
3768
+ description: "AI-Accelerated Development: AI Extension Studio, Agent Skills, the live MCP server, and the Claude Code plugin \u2014 and how to choose between them.",
3769
+ type: "knowledge",
3770
+ scopes: ["docs"],
3771
+ content: () => generateAIAcceleratedDevelopment()
3772
+ },
3186
3773
  // ── Cookbook skills (docs-only) ────────────────────────────────
3187
3774
  {
3188
3775
  id: "cookbook-structural",
@@ -3205,6 +3792,13 @@ var SKILLS = [
3205
3792
  scopes: ["docs"],
3206
3793
  content: () => generateCookbookEvents()
3207
3794
  },
3795
+ {
3796
+ id: "marketplace-listing",
3797
+ description: "Marketplace listing reference: the listing fields (icon, screenshots, description, categories), Public vs Protected visibility, and the two-stage review process (bundle scan + security review + approval). Use when publishing a deployed extension to the marketplace.",
3798
+ type: "knowledge",
3799
+ scopes: ["docs"],
3800
+ content: () => generateMarketplaceListing()
3801
+ },
3208
3802
  // ── Action skills ─────────────────────────────────────────────
3209
3803
  {
3210
3804
  id: "add-surface",
@@ -3229,6 +3823,15 @@ var SKILLS = [
3229
3823
  description: "Validate this extension for common errors before deploying: manifest, permissions, surfaces, imports. Use before publishing or when debugging issues.",
3230
3824
  type: "action",
3231
3825
  content: () => generateValidateExtensionCommand()
3826
+ },
3827
+ {
3828
+ id: "deploy",
3829
+ description: "Build the production bundle, host it on Netlify / Vercel / Cloudflare Pages / S3+CloudFront, and register your Bundle URL with Stackable via the admin dashboard or CLI. Use when shipping an extension after validation passes.",
3830
+ type: "action",
3831
+ // TODO: T3 #24 — remove `scopes: ['docs']` once `cli deploy` is implemented so Studio's
3832
+ // AI assistant in the future should be able invoke the deploy flow (not just describe it).
3833
+ scopes: ["docs"],
3834
+ content: () => generateDeployExtensionCommand()
3232
3835
  }
3233
3836
  ];
3234
3837