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