@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.
- package/dist/index.js +653 -50
- package/dist/server.js +653 -50
- 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 = "<
|
|
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.
|
|
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,
|
|
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
|
-
|
|
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
|
-
| \`
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
**
|
|
1863
|
-
1.
|
|
1864
|
-
2.
|
|
1865
|
-
3.
|
|
1866
|
-
4.
|
|
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
|
|
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
|
-
|
|
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
|
-
| **
|
|
2170
|
-
| **
|
|
2171
|
-
| **
|
|
2172
|
-
| **
|
|
2173
|
-
|
|
2174
|
-
|
|
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
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
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
|
|
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
|
|