From 36eea0d308f1312d1a446ec8813ed30b0bdba62c Mon Sep 17 00:00:00 2001 From: Charles Lavery Date: Fri, 30 Oct 2026 21:58:41 -0400 Subject: [PATCH] feat(mcp): bundle cap-dev Commerce App Package skills Vendor the cap-dev skills from the public commerce-apps repository into the MCP as the cap-dev collection, with a sync script and recorded upstream commit. Add short index-only skill summaries so skill://index stays compact, and raise the index budget to 24 KiB. --- .agents/skills/mcp-development/SKILL.md | 4 +- .changeset/b2c-cap-skill-mcp-cap-dev.md | 5 + .changeset/guidance-index-summaries.md | 5 + .changeset/mcp-bundle-cap-dev-skills.md | 5 + docs/guide/agent-skills.md | 3 +- docs/guide/commerce-apps.md | 2 + packages/b2c-dx-mcp/docs/skills.md | 15 +- packages/b2c-dx-mcp/package.json | 1 + .../b2c-dx-mcp/scripts/generate-guidance.ts | 6 + .../scripts/sync-cap-dev-skills.mjs | 91 ++ .../b2c-dx-mcp/skills/b2c-mcp-server/SKILL.md | 4 +- packages/b2c-dx-mcp/skills/collections.json | 6 + .../b2c-dx-mcp/skills/index-summaries.json | 91 ++ packages/b2c-dx-mcp/test/e2e/guidance.test.ts | 4 +- packages/b2c-dx-mcp/test/guidance.test.ts | 19 +- packages/b2c-dx-mcp/vendor/cap-dev/README.md | 29 + .../generate-custom-object-impex/SKILL.md | 259 ++++ .../references/patterns.md | 307 +++++ .../skills/generate-service-impex/SKILL.md | 262 ++++ .../references/service-patterns.md | 139 ++ .../generate-site-preferences-impex/SKILL.md | 246 ++++ .../references/app-patterns.md | 203 +++ .../references/attribute-types.md | 162 +++ .../cap-dev/skills/package-app/SKILL.md | 215 +++ .../references/folder-structure.md | 43 + .../package-app/references/security-rules.md | 40 + .../package-app/references/security-scan.md | 26 + .../cap-dev/skills/scaffold-app/SKILL.md | 263 ++++ .../references/storefront-plugin-templates.md | 1186 +++++++++++++++++ .../scaffold-app/references/templates.md | 105 ++ .../vendor/cap-dev/skills/submit-app/SKILL.md | 189 +++ .../cap-dev/skills/validate-app/SKILL.md | 274 ++++ .../references/impex-validation.md | 111 ++ .../validate-app/references/security-rules.md | 40 + .../validate-app/references/security-scan.md | 54 + .../cap-dev/skills/validate-impex/SKILL.md | 197 +++ .../b2c-dx-mcp/vendor/cap-dev/source.json | 7 + .../b2c-tooling-sdk/src/guidance/bundle.ts | 24 + .../b2c-tooling-sdk/src/guidance/catalog.ts | 8 +- .../b2c-tooling-sdk/src/guidance/types.ts | 2 + .../test/guidance/bundle.test.ts | 21 + .../test/guidance/catalog.test.ts | 14 + skills/b2c-cli/skills/b2c-cap/SKILL.md | 2 +- 43 files changed, 4674 insertions(+), 15 deletions(-) create mode 100644 .changeset/b2c-cap-skill-mcp-cap-dev.md create mode 100644 .changeset/guidance-index-summaries.md create mode 100644 .changeset/mcp-bundle-cap-dev-skills.md create mode 100644 packages/b2c-dx-mcp/scripts/sync-cap-dev-skills.mjs create mode 100644 packages/b2c-dx-mcp/skills/index-summaries.json create mode 100644 packages/b2c-dx-mcp/vendor/cap-dev/README.md create mode 100644 packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-custom-object-impex/SKILL.md create mode 100644 packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-custom-object-impex/references/patterns.md create mode 100644 packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-service-impex/SKILL.md create mode 100644 packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-service-impex/references/service-patterns.md create mode 100644 packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-site-preferences-impex/SKILL.md create mode 100644 packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-site-preferences-impex/references/app-patterns.md create mode 100644 packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-site-preferences-impex/references/attribute-types.md create mode 100644 packages/b2c-dx-mcp/vendor/cap-dev/skills/package-app/SKILL.md create mode 100644 packages/b2c-dx-mcp/vendor/cap-dev/skills/package-app/references/folder-structure.md create mode 100644 packages/b2c-dx-mcp/vendor/cap-dev/skills/package-app/references/security-rules.md create mode 100644 packages/b2c-dx-mcp/vendor/cap-dev/skills/package-app/references/security-scan.md create mode 100644 packages/b2c-dx-mcp/vendor/cap-dev/skills/scaffold-app/SKILL.md create mode 100644 packages/b2c-dx-mcp/vendor/cap-dev/skills/scaffold-app/references/storefront-plugin-templates.md create mode 100644 packages/b2c-dx-mcp/vendor/cap-dev/skills/scaffold-app/references/templates.md create mode 100644 packages/b2c-dx-mcp/vendor/cap-dev/skills/submit-app/SKILL.md create mode 100644 packages/b2c-dx-mcp/vendor/cap-dev/skills/validate-app/SKILL.md create mode 100644 packages/b2c-dx-mcp/vendor/cap-dev/skills/validate-app/references/impex-validation.md create mode 100644 packages/b2c-dx-mcp/vendor/cap-dev/skills/validate-app/references/security-rules.md create mode 100644 packages/b2c-dx-mcp/vendor/cap-dev/skills/validate-app/references/security-scan.md create mode 100644 packages/b2c-dx-mcp/vendor/cap-dev/skills/validate-impex/SKILL.md create mode 100644 packages/b2c-dx-mcp/vendor/cap-dev/source.json diff --git a/.agents/skills/mcp-development/SKILL.md b/.agents/skills/mcp-development/SKILL.md index 33af9c6fc..91f952795 100644 --- a/.agents/skills/mcp-development/SKILL.md +++ b/.agents/skills/mcp-development/SKILL.md @@ -37,7 +37,9 @@ For packaging and protocol details, read [the catalog contract](../../../package Native skill changes use an agent-plugin changeset; the MCP's bundled `workspace:*` dependency automatically triggers an MCP patch release. Keep it in `dependencies` and `bundledDependencies`, not `devDependencies`. MCP-specific -skills and collection changes need an MCP changeset. +skills and collection changes need an MCP changeset. Every bundled skill needs a +short `skill://index` line in `packages/b2c-dx-mcp/skills/index-summaries.json`; +add one when you add a skill (a test enforces this). ## Tools and context diff --git a/.changeset/b2c-cap-skill-mcp-cap-dev.md b/.changeset/b2c-cap-skill-mcp-cap-dev.md new file mode 100644 index 000000000..e3c5d67f3 --- /dev/null +++ b/.changeset/b2c-cap-skill-mcp-cap-dev.md @@ -0,0 +1,5 @@ +--- +'@salesforce/b2c-agent-plugins': patch +--- + +The `b2c-cap` skill now points MCP users to the bundled `cap-dev` authoring skills. diff --git a/.changeset/guidance-index-summaries.md b/.changeset/guidance-index-summaries.md new file mode 100644 index 000000000..404d32ef5 --- /dev/null +++ b/.changeset/guidance-index-summaries.md @@ -0,0 +1,5 @@ +--- +'@salesforce/b2c-tooling-sdk': minor +--- + +`bundleGuidance` accepts `indexSummaries`, short per-skill lines used only in the `skill://index` listing; skill descriptions and search are unchanged. diff --git a/.changeset/mcp-bundle-cap-dev-skills.md b/.changeset/mcp-bundle-cap-dev-skills.md new file mode 100644 index 000000000..366d72c7f --- /dev/null +++ b/.changeset/mcp-bundle-cap-dev-skills.md @@ -0,0 +1,5 @@ +--- +'@salesforce/b2c-dx-mcp': minor +--- + +The MCP now includes the `cap-dev` Commerce App Package authoring skills (scaffold, generate IMPEX, validate, package, and submit), so you don't need to install them separately. diff --git a/docs/guide/agent-skills.md b/docs/guide/agent-skills.md index 689ef8702..30e96aee7 100644 --- a/docs/guide/agent-skills.md +++ b/docs/guide/agent-skills.md @@ -15,7 +15,8 @@ B2C skills give your AI assistant guidance for B2C Commerce development, operations, CLI workflows, and Storefront Next projects. **The [B2C MCP](../mcp/) gives your assistant access to guidance from the `b2c`, -`b2c-cli`, `b2c-ops`, and `storefront-next` collections** through its +`b2c-cli`, `b2c-ops`, and `storefront-next` collections, plus the +[`cap-dev`](./commerce-apps) Commerce App Package authoring skills,** through its [`skills_read` tool](../mcp/toolsets#documentation). Your assistant can find and read that guidance as needed, without a separate skills installation. You can also install these collections directly in your assistant, alongside the MCP or on their own. diff --git a/docs/guide/commerce-apps.md b/docs/guide/commerce-apps.md index d4c15cf30..a56a096db 100644 --- a/docs/guide/commerce-apps.md +++ b/docs/guide/commerce-apps.md @@ -18,6 +18,8 @@ If you build CAPs with an AI coding agent, install the agent skills so it unders `b2c-cli` and `b2c` ship in the [B2C Developer Tooling marketplace](/guide/agent-skills); `cap-dev` ships separately from the [`SalesforceCommerceCloud/commerce-apps`](https://github.com/SalesforceCommerceCloud/commerce-apps) registry repository. +If you use the [B2C MCP](/mcp/), you don't need to install these separately: it includes all three, including a copy of the `cap-dev` skills that is refreshed in each MCP release. Install the `cap-dev` plugin directly for changes made in the commerce-apps repository since the last MCP release. + ### Claude Code ```bash diff --git a/packages/b2c-dx-mcp/docs/skills.md b/packages/b2c-dx-mcp/docs/skills.md index 3c0080a23..893bf2741 100644 --- a/packages/b2c-dx-mcp/docs/skills.md +++ b/packages/b2c-dx-mcp/docs/skills.md @@ -8,7 +8,9 @@ under `references/`. This package's `skills/collections.json` selects entire plugin collections by their existing name in the repository's `skills/plugins.json`; it does not duplicate the per-skill inventory. Collections -can instead name a package-relative directory for MCP-only skills. `isGA` +can instead name a package-relative directory for MCP-only skills. The `cap-dev` collection is a +directory collection of skills vendored from the public commerce-apps repository; see +[`vendor/cap-dev/README.md`](../vendor/cap-dev/README.md) for how to refresh it. `isGA` is internal collection metadata; MCP includes every selected collection regardless of it. `workspaces` only influences ranking. Discovery responses expose only collection IDs and titles; `isGA` and `workspaces` are absent from the MCP output schema. Neither native @@ -20,15 +22,20 @@ skill installation nor `--docs-topics` defines the skill catalog. chosen by the top-level `featuredResources` IDs in `skills/collections.json`. Featuring an entry controls listing only. All available skills and references are readable through the resource template and `skills_read`, grouped into `b2c`, `b2c-cli`, -`b2c-ops`, `storefront-next`, and `mcp`. Every tool discovery/read result includes a URI. MCP resources are always registered. +`b2c-ops`, `storefront-next`, `cap-dev`, and `mcp`. Every tool discovery/read result includes a URI. MCP resources are always registered. When `skills_read` is omitted from an individual tool selection, the index and resource template expose only the `mcp` collection; all other collections are excluded from discovery and direct reads. The index is generated from the filtered manifest at read time: collection, -skill ID, entrypoint URI, and a description of at most 120 code points per entry. +skill ID, entrypoint URI, and a short summary per entry. Summaries come from +`skills/index-summaries.json` (at most 100 code points, keyed by entry ID) and are +used only in the index; skill descriptions, `skills_read` results, the skills +extension, and search keep the full `description`. An entry without a summary +falls back to its description truncated to 120 code points; a test requires +every bundled skill to have one, so add a summary when you add a skill. It includes no skill bodies or reference inventory. Current bundled index content -stays below 16 KiB; the runtime resource ceiling is 64 KiB. It is not another +stays below 24 KiB; the runtime resource ceiling is 64 KiB. It is not another authored skill and does not increase the skill count. Clients can discover files through the index or tool search without template argument completion. Passing the index URI to `skills_read` returns its normal paginated catalog diff --git a/packages/b2c-dx-mcp/package.json b/packages/b2c-dx-mcp/package.json index 12f668fea..3744d15d3 100644 --- a/packages/b2c-dx-mcp/package.json +++ b/packages/b2c-dx-mcp/package.json @@ -97,6 +97,7 @@ "prepack": "pnpm run generate:guidance && node scripts/prepare-sdk-bundle.mjs && oclif manifest", "postpack": "shx rm -f oclif.manifest.json", "generate:guidance": "tsx --conditions=development scripts/generate-guidance.ts", + "sync:cap-dev-skills": "node scripts/sync-cap-dev-skills.mjs", "prepare:guidance-test": "node scripts/prepare-guidance-test.mjs" }, "dependencies": { diff --git a/packages/b2c-dx-mcp/scripts/generate-guidance.ts b/packages/b2c-dx-mcp/scripts/generate-guidance.ts index 6ec3a1550..f6b53c76f 100644 --- a/packages/b2c-dx-mcp/scripts/generate-guidance.ts +++ b/packages/b2c-dx-mcp/scripts/generate-guidance.ts @@ -29,11 +29,17 @@ const config = JSON.parse(readFileSync(join(packageRoot, 'skills/collections.jso collections: GuidanceCollectionSource[]; }; if (config.version !== 1) throw new Error('Unsupported guidance collections manifest'); +// Short skill://index lines; skill descriptions and search are unaffected. +const indexSummaries = JSON.parse(readFileSync(join(packageRoot, 'skills/index-summaries.json'), 'utf8')) as Record< + string, + string +>; const result = bundleGuidance({ repoRoot, baseDirectory: packageRoot, collections: config.collections, featuredResources: config.featuredResources, + indexSummaries, destination: join(packageRoot, 'content/guidance'), }); process.stdout.write(`Bundled ${result.entries} guidance entries and ${result.files} Markdown files.\n`); diff --git a/packages/b2c-dx-mcp/scripts/sync-cap-dev-skills.mjs b/packages/b2c-dx-mcp/scripts/sync-cap-dev-skills.mjs new file mode 100644 index 000000000..70e6d1ad8 --- /dev/null +++ b/packages/b2c-dx-mcp/scripts/sync-cap-dev-skills.mjs @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ + +/** + * Vendors the `cap-dev` (Commerce App Package development) skills from the + * public commerce-apps repository into `vendor/cap-dev/skills`, which + * `generate:guidance` bundles as the `cap-dev` collection. + * + * The skills are authored upstream; never edit the vendored copy. Refresh with: + * + * pnpm --filter @salesforce/b2c-dx-mcp run sync:cap-dev-skills [-- --ref ] + * + * Only Markdown is vendored (the guidance bundle serves Markdown only). Links + * from a skill into the upstream `shared/` folder are rewritten to a copy inside + * that skill, because bundled skills must be self-contained. + */ +import {execFileSync} from 'node:child_process'; +import {cpSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync} from 'node:fs'; +import {tmpdir} from 'node:os'; +import {dirname, join, posix, resolve} from 'node:path'; +import {fileURLToPath} from 'node:url'; + +const REPO = 'SalesforceCommerceCloud/commerce-apps'; +const SKILLS_PATH = '.claude/skills'; +const SHARED = 'shared'; + +const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..'); +const vendorRoot = join(packageRoot, 'vendor/cap-dev'); +const refIndex = process.argv.indexOf('--ref'); +const ref = refIndex === -1 ? 'main' : process.argv[refIndex + 1]; +if (!ref) throw new Error('--ref requires a branch, tag, or commit'); + +function git(cwd, ...args) { + return execFileSync('git', args, {cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'inherit']}).trim(); +} + +function markdownFiles(root, prefix = '') { + const files = []; + for (const item of readdirSync(root, {withFileTypes: true})) { + if (item.name === 'evals' || item.name.startsWith('.')) continue; + const path = prefix ? `${prefix}/${item.name}` : item.name; + if (item.isDirectory()) files.push(...markdownFiles(join(root, item.name), path)); + else if (item.isFile() && item.name.endsWith('.md')) files.push(path); + } + return files; +} + +const checkout = mkdtempSync(join(tmpdir(), 'cap-dev-skills-')); +try { + git(checkout, 'init', '--quiet'); + git(checkout, 'remote', 'add', 'origin', `https://github.com/${REPO}.git`); + git(checkout, 'fetch', '--quiet', '--depth', '1', 'origin', ref); + git(checkout, 'checkout', '--quiet', 'FETCH_HEAD'); + const sha = git(checkout, 'rev-parse', 'HEAD'); + const committedAt = git(checkout, 'show', '-s', '--format=%cI', 'HEAD'); + const source = join(checkout, SKILLS_PATH); + + const destination = join(vendorRoot, 'skills'); + rmSync(destination, {recursive: true, force: true}); + const skills = readdirSync(source, {withFileTypes: true}) + .filter((item) => item.isDirectory() && item.name !== SHARED && !item.name.startsWith('.')) + .map((item) => item.name) + .sort(); + for (const skill of skills) { + for (const file of markdownFiles(join(source, skill))) { + let content = readFileSync(join(source, skill, file), 'utf8'); + content = content.replaceAll(/\]\(([^)\s#]+)(#[^)\s]*)?\)/g, (match, target, anchor = '') => { + if (/^[a-z][a-z0-9+.-]*:/i.test(target)) return match; + const resolved = posix.normalize(posix.join(skill, posix.dirname(file), target)); + if (!resolved.startsWith(`${SHARED}/`)) return match; + const copy = `references/${resolved.slice(SHARED.length + 1)}`; + mkdirSync(dirname(join(destination, skill, copy)), {recursive: true}); + cpSync(join(source, resolved), join(destination, skill, copy)); + return `](${posix.relative(posix.dirname(file), copy)}${anchor})`; + }); + mkdirSync(dirname(join(destination, skill, file)), {recursive: true}); + writeFileSync(join(destination, skill, file), content); + } + } + + writeFileSync( + join(vendorRoot, 'source.json'), + `${JSON.stringify({repository: REPO, path: SKILLS_PATH, ref, sha, committedAt}, null, 2)}\n`, + ); + process.stdout.write(`Vendored ${skills.length} cap-dev skills from ${REPO}@${sha.slice(0, 12)} (${ref}).\n`); +} finally { + rmSync(checkout, {recursive: true, force: true}); +} diff --git a/packages/b2c-dx-mcp/skills/b2c-mcp-server/SKILL.md b/packages/b2c-dx-mcp/skills/b2c-mcp-server/SKILL.md index 5422574e4..42460e912 100644 --- a/packages/b2c-dx-mcp/skills/b2c-mcp-server/SKILL.md +++ b/packages/b2c-dx-mcp/skills/b2c-mcp-server/SKILL.md @@ -28,8 +28,8 @@ Read only the skill that matches the task; each links its own references. Every skill and reference file is readable as an MCP resource (`skill:////`) or with `skills_read({uri})`. Collections: `b2c` (platform/cartridges), `b2c-cli` (CLI), `b2c-ops` -(operator/admin runbooks), `storefront-next` (storefronts), `mcp` (server/tool -workflows). Search with `skills_read({query, collection})` or browse `skill://index`. +(operator/admin runbooks), `storefront-next` (storefronts), `cap-dev` (authoring +Commerce App Packages), `mcp` (server/tool workflows). Search with `skills_read({query, collection})` or browse `skill://index`. ## Server configuration and tool availability diff --git a/packages/b2c-dx-mcp/skills/collections.json b/packages/b2c-dx-mcp/skills/collections.json index b1ab825d0..128c2f8d3 100644 --- a/packages/b2c-dx-mcp/skills/collections.json +++ b/packages/b2c-dx-mcp/skills/collections.json @@ -35,6 +35,12 @@ "isGA": true, "workspaces": ["storefront-next"] }, + { + "id": "cap-dev", + "title": "Commerce App Package Development", + "directory": "vendor/cap-dev/skills", + "isGA": true + }, { "id": "mcp", "title": "MCP Workflows", diff --git a/packages/b2c-dx-mcp/skills/index-summaries.json b/packages/b2c-dx-mcp/skills/index-summaries.json new file mode 100644 index 000000000..8ebc1706f --- /dev/null +++ b/packages/b2c-dx-mcp/skills/index-summaries.json @@ -0,0 +1,91 @@ +{ + "b2c-cli/b2c-am": "Account Manager API clients, users, roles, and orgs; onboard developers or provision CI clients.", + "b2c-cli/b2c-bm-users-roles": "Business Manager users, access roles, permissions, and per-user access keys on an instance.", + "b2c-cli/b2c-cap": "Operate Commerce App Packages: validate, package, install, uninstall, list, and pull apps.", + "b2c-cli/b2c-cip": "CLI CIP analytics: discover reports and tables, run scoped SQL, export results, resolve access.", + "b2c-cli/b2c-code": "Deploy, download, watch, and activate cartridge code versions on an instance.", + "b2c-cli/b2c-config": "CLI/MCP auth, instances, and project defaults; fix missing credentials or wrong targets.", + "b2c-cli/b2c-content": "Export, list, and validate Page Designer pages and components from content libraries.", + "b2c-cli/b2c-debug": "CLI script debugger: breakpoints, stepping, variables, and expressions on an instance.", + "b2c-cli/b2c-docs": "Search and read Script API, guides, Help, tooling docs, job steps, and XSDs from the CLI.", + "b2c-cli/b2c-ecdn": "eCDN zones: cache purge, certificates, WAF and rate-limit rules, logpush, and MRT routing.", + "b2c-cli/b2c-import-set-migrations": "Ordered, run-once site import sets for repeatable setup and CI migrations (job import-set).", + "b2c-cli/b2c-job": "Run and monitor jobs, inspect failures, rebuild search indexes, and import or export archives.", + "b2c-cli/b2c-logs": "Get, search, and tail instance logs to investigate errors and server-side failures.", + "b2c-cli/b2c-metrics": "CLI Metrics API (closed beta): request volume, latency, errors, cache, and integration health.", + "b2c-cli/b2c-mrt": "Managed Runtime: deploy bundles, manage projects, environments, env vars, and redirects.", + "b2c-cli/b2c-replication": "Automate staging-to-production code and data replication with a custom job.", + "b2c-cli/b2c-sandbox": "Create, list, start, stop, and manage on-demand sandboxes.", + "b2c-cli/b2c-scapi-custom": "Check custom SCAPI endpoint registration; debug 404 or endpoint-not-found errors.", + "b2c-cli/b2c-scapi-schemas": "Browse SCAPI OpenAPI specs: endpoints, request/response shapes, and versions.", + "b2c-cli/b2c-site-import-export": "Author, validate, import, and verify site archives and metadata XML; export data.", + "b2c-cli/b2c-sites": "List sites and status, and view or edit site and Business Manager cartridge paths.", + "b2c-cli/b2c-slas": "SLAS clients: create, update scopes, rotate secrets, and get shopper tokens.", + "b2c-cli/b2c-storefronts": "Set up, connect, export, and import Storefront Next storefronts across instances.", + "b2c-cli/b2c-webdav": "List, upload, download, zip, and manage instance files over WebDAV, including IMPEX.", + "b2c/b2c-business-manager-extensions": "Build bm_* cartridges with custom Business Manager menus, pages, and dialog actions.", + "b2c/b2c-controllers": "SFRA and classic controllers: routes, middleware, form posts, AJAX, and overrides.", + "b2c/b2c-custom-api-development": "Build Custom SCAPI endpoints: api.json, schema.yaml, scopes, and registration fixes.", + "b2c/b2c-custom-caches": "Server-side caching with CacheMgr and caches.json regions, TTLs, and invalidation.", + "b2c/b2c-custom-job-steps": "Write custom job steps (steptypes.json, chunk/task) and jobs.xml for scheduled batch work.", + "b2c/b2c-custom-objects": "Store and query custom data with CustomObjectMgr, OCAPI, and Shopper Custom Objects.", + "b2c/b2c-forms": "SFRA forms: XML definitions, validation, controller handling, ISML rendering, and CSRF.", + "b2c/b2c-hooks": "Platform hooks in hooks.json via HookMgr: OCAPI/SCAPI before/after, payment, calculate.", + "b2c/b2c-isml": "ISML templates: tags, decorators, includes, expressions, and output encoding.", + "b2c/b2c-localization": "Translations and locales: resource bundles, Resource.msg, formatting, and fallback.", + "b2c/b2c-logging": "Script logging with dw.system.Logger, categories, levels, and custom log files.", + "b2c/b2c-metadata": "Metadata XML for custom attributes, custom object types, and site preferences.", + "b2c/b2c-onboarding": "First-time B2C Commerce setup: install the CLI, connect a sandbox, deploy a cartridge.", + "b2c/b2c-ordering": "Order lifecycle: create from basket, status changes, failures, and payment authorization.", + "b2c/b2c-page-designer": "Page Designer page and component types for ISML: regions, attributes, editor issues.", + "b2c/b2c-querying-data": "Efficient product, customer, and order queries; pagination and index-backed searches.", + "b2c/b2c-scapi-admin": "Server-to-server Admin API integrations with ERP/OMS/WMS; client credentials and bulk sync.", + "b2c/b2c-scapi-shopper": "Shopper APIs for headless storefronts: search, baskets, checkout, and customer data.", + "b2c/b2c-slas-auth-patterns": "SLAS patterns: passwordless, passkeys, session bridging, token refresh, TSOB, JWT checks.", + "b2c/b2c-webservices": "External REST/SOAP/SFTP calls via LocalServiceRegistry, services.xml, and circuit breakers.", + "b2c-ops/b2c-checkout-triage": "Runbook: checkout or payment failures, rising failed orders, or falling order volume.", + "b2c-ops/b2c-edge-traffic-triage": "Runbook: bots, scrapers, API abuse, and edge 403/429 spikes; propose eCDN rule changes.", + "b2c-ops/b2c-integration-triage": "Runbook: failing, slow, or stopped calls to payment, tax, shipping, OMS, or other services.", + "b2c-ops/b2c-job-health": "Runbook: routine job review, failed or missing runs, and stale or incomplete imports.", + "b2c-ops/b2c-order-failure-triage": "Runbook: find FAILED orders, measure their share, and correlate with logs and jobs.", + "b2c-ops/b2c-performance-triage": "Runbook: localize slow or erroring storefront and API responses with Metrics API signals.", + "b2c-ops/b2c-production-triage": "Start here for production incidents: route errors, stale data, or checkout failures.", + "storefront-next/sfnext-accessibility": "WCAG fixes in Storefront Next: names, labels, focus, aria-live, contrast, and axe tests.", + "storefront-next/sfnext-analytics-consent": "Storefront Next analytics adapters, consent gating, tracking events, and attribution.", + "storefront-next/sfnext-authentication": "Storefront Next SLAS sessions and cookies: login, logout, protected routes, basket merge.", + "storefront-next/sfnext-commerce-features": "Enable optional Storefront Next features and extensions; prerequisites and stubs.", + "storefront-next/sfnext-components": "Storefront Next UI components: Suspense pages, Tailwind tokens, shadcn/ui, Storybook.", + "storefront-next/sfnext-configuration": "Storefront Next config.server.ts, PUBLIC__ env overrides, secrets, and multi-site.", + "storefront-next/sfnext-data-fetching": "Storefront Next loaders and actions calling SCAPI: streaming, cart actions, fetchers.", + "storefront-next/sfnext-deployment": "Build and push Storefront Next to MRT, sync env vars, and deploy cartridge metadata.", + "storefront-next/sfnext-extensions": "Add or remove Storefront Next extensions: UITarget slots, hooks, and extension routes.", + "storefront-next/sfnext-hybrid-storefronts": "Run Storefront Next beside SFRA: hybrid proxy, legacy routes, and shared sessions.", + "storefront-next/sfnext-i18n": "Storefront Next translations with i18next: strings, plurals, new locales, and switching.", + "storefront-next/sfnext-overview": "Start here for Storefront Next: routes tasks to the right skill and lists key commands.", + "storefront-next/sfnext-page-designer": "Storefront Next Page Designer: decorated components, regions, loaders, and cartridge sync.", + "storefront-next/sfnext-performance": "Storefront Next performance: LCP/CLS, Suspense, lazy overlays, images, and bundle size.", + "storefront-next/sfnext-project-setup": "Create a Storefront Next project; layout, npm scripts, and first-run setup.", + "storefront-next/sfnext-quality-gates": "Pass Storefront Next lint, format, typecheck, bundle-size, and Lighthouse gates.", + "storefront-next/sfnext-revalidation": "Control which Storefront Next loaders re-run after actions: shouldRevalidate and tags.", + "storefront-next/sfnext-routing": "Storefront Next routes: flat files, layouts, splats, site-aware links, and URL prefixes.", + "storefront-next/sfnext-scapi": "Storefront Next SCAPI clients: typing c_ attributes and adding custom API clients.", + "storefront-next/sfnext-security": "Storefront Next security headers, CSP and contributors, Turnstile, and cookie domain.", + "storefront-next/sfnext-seo": "Storefront Next SEO: meta tags, JSON-LD, canonical and hreflang, and SEO URL routes.", + "storefront-next/sfnext-state-management": "Choose Storefront Next state: loader data, URL, cookies, optimistic UI, or context.", + "storefront-next/sfnext-testing": "Storefront Next tests: Vitest, loader/action tests, Storybook stories, and e2e pointers.", + "storefront-next/sfnext-theming": "Rebrand Storefront Next: colors, shape tokens, fonts, logo, and contrast checks.", + "cap-dev/generate-custom-object-impex": "Commerce apps: generate custom object type IMPEX for app data, caches, or records.", + "cap-dev/generate-service-impex": "Commerce apps: generate service credential, profile, and definition IMPEX for external APIs.", + "cap-dev/generate-site-preferences-impex": "Commerce apps: generate site preference IMPEX for merchant settings in Business Manager.", + "cap-dev/package-app": "Commerce apps: package an app directory into a registry-ready ZIP, or bump its version.", + "cap-dev/scaffold-app": "Commerce apps: scaffold a new UI-only, backend-only, or fullstack app. Start here to author.", + "cap-dev/submit-app": "Commerce apps: open the registry submission pull request for a packaged, validated app.", + "cap-dev/validate-app": "Commerce apps: run full pre-submission checks on structure, manifest, IMPEX, and security.", + "cap-dev/validate-impex": "Commerce apps: validate IMPEX XML syntax, structure, and install/uninstall pairs.", + "mcp/b2c-mcp-cip": "Read before cip_query: CIP reports and analytics SQL, warehouse access, and scoping.", + "mcp/b2c-mcp-claude-artifacts": "Read before building or sharing a Claude artifact or dashboard from B2C data.", + "mcp/b2c-mcp-config": "MCP configuration, authentication, and access grants for setup or wrong-target issues.", + "mcp/b2c-mcp-debugger": "MCP debugger workflow: breakpoint capture, request triggering, inspection, and cleanup.", + "mcp/b2c-mcp-scapi": "Read before scapi_search or scapi_execute: SCAPI contracts, requests, and Safety Mode.", + "mcp/b2c-mcp-server": "MCP setup and index: toolset selection, which tool to use, and the skill catalog." +} diff --git a/packages/b2c-dx-mcp/test/e2e/guidance.test.ts b/packages/b2c-dx-mcp/test/e2e/guidance.test.ts index 6a896d247..8e11fe318 100644 --- a/packages/b2c-dx-mcp/test/e2e/guidance.test.ts +++ b/packages/b2c-dx-mcp/test/e2e/guidance.test.ts @@ -126,7 +126,7 @@ describe('guidance over real stdio', function () { expect(ids.length).to.equal(total); expect(new Set(ids).size).to.equal(total); expect(new Set(ids.map((id) => id.split('/')[0]))).to.deep.equal( - new Set(['b2c', 'b2c-cli', 'b2c-ops', 'mcp', 'storefront-next']), + new Set(['b2c', 'b2c-cli', 'b2c-ops', 'cap-dev', 'mcp', 'storefront-next']), ); expect(ids).to.include('mcp/b2c-mcp-server'); }); @@ -213,7 +213,7 @@ describe('guidance over real stdio', function () { } expect(Buffer.byteLength(JSON.stringify(listed))).to.be.lessThan(3000); const index = (await client.call('resources/read', {uri: 'skill://index'})) as {contents: {text: string}[]}; - expect(Buffer.byteLength(index.contents[0].text)).to.be.lessThan(16 * 1024); + expect(Buffer.byteLength(index.contents[0].text)).to.be.lessThan(24 * 1024); const links = [...index.contents[0].text.matchAll(/\[([^\]]+)\]\((skill:\/\/[^)]+)\)/g)]; const directory = (await call({})).structuredContent.result as GuidancePage; expect(links.length).to.equal(directory.total); diff --git a/packages/b2c-dx-mcp/test/guidance.test.ts b/packages/b2c-dx-mcp/test/guidance.test.ts index f77b87427..01bd841ce 100644 --- a/packages/b2c-dx-mcp/test/guidance.test.ts +++ b/packages/b2c-dx-mcp/test/guidance.test.ts @@ -89,6 +89,17 @@ describe('guidance distribution and result contracts', () => { .sort(), ).to.deep.equal(folders); } + const capDev = readdirSync(join(packageRoot, 'vendor/cap-dev/skills'), {withFileTypes: true}) + .filter((entry) => entry.isDirectory()) + .map((entry) => `cap-dev/${entry.name}`) + .sort(); + expect(capDev.length).to.be.greaterThan(0); + expect( + manifest.entries + .filter((entry) => entry.collection === 'cap-dev') + .map((entry) => entry.id) + .sort(), + ).to.deep.equal(capDev); for (const entry of manifest.entries) { for (const file of entry.files) { const read = catalog.read({id: entry.id, file: file.path}) as GuidanceRead; @@ -99,6 +110,12 @@ describe('guidance distribution and result contracts', () => { } }); + it('gives every bundled skill a short index summary', () => { + const manifest = JSON.parse(readFileSync(join(bundleRoot, 'index.json'), 'utf8')) as GuidanceManifest; + const missing = manifest.entries.filter((entry) => !entry.indexSummary).map((entry) => entry.id); + expect(missing, 'add these to skills/index-summaries.json').to.deep.equal([]); + }); + it('does not load configuration for guidance and rejects unexpected input', async () => { const tool = createGuidanceTool(); const response = await tool.handler({id: 'mcp/b2c-mcp-server'}); @@ -126,7 +143,7 @@ describe('guidance distribution and result contracts', () => { const tool = createGuidanceTool(); expect(tool.inputSchema).not.to.have.property('projectDirectory'); await Promise.all( - ['b2c', 'b2c-cli', 'b2c-ops', 'storefront-next', 'mcp'].map(async (collection) => { + ['b2c', 'b2c-cli', 'b2c-ops', 'storefront-next', 'cap-dev', 'mcp'].map(async (collection) => { const response = await tool.handler({collection}); expect(response.isError).not.to.equal(true); const page = (response.structuredContent as {result: {entries: {id: string}[]}}).result; diff --git a/packages/b2c-dx-mcp/vendor/cap-dev/README.md b/packages/b2c-dx-mcp/vendor/cap-dev/README.md new file mode 100644 index 000000000..577ee0ae2 --- /dev/null +++ b/packages/b2c-dx-mcp/vendor/cap-dev/README.md @@ -0,0 +1,29 @@ +# Vendored `cap-dev` skills + +The skills in `skills/` are copied from the public +[`SalesforceCommerceCloud/commerce-apps`](https://github.com/SalesforceCommerceCloud/commerce-apps) +repository (`.claude/skills`). The MCP server bundles them as the `cap-dev` collection +(`skill://cap-dev/...`). `source.json` records the upstream commit they were copied from. + +**Do not edit these files here.** Change the skills upstream, then refresh this copy: + +```bash +# Copy the latest skills from the upstream default branch (or pass --ref ) +pnpm --filter @salesforce/b2c-dx-mcp run sync:cap-dev-skills + +# Review what changed upstream since the last sync +git diff -- packages/b2c-dx-mcp/vendor/cap-dev + +# Rebuild and check the bundle +pnpm --filter @salesforce/b2c-dx-mcp run test:agent +``` + +If the sync adds or renames a skill, add its `cap-dev/` line to +`packages/b2c-dx-mcp/skills/index-summaries.json` (the tests fail until you do). Commit the refreshed files with an `@salesforce/b2c-dx-mcp` patch changeset so the update ships in +the next MCP release. + +The sync copies only Markdown, because the MCP serves only Markdown. It skips the upstream +`evals/`, `scripts/`, and `assets/` folders. Links into the upstream `shared/` folder are rewritten +to a copy in the linking skill's `references/` folder, because bundled skills must be +self-contained. Skill text that mentions those scripts or templates assumes a checkout of the +commerce-apps repository. diff --git a/packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-custom-object-impex/SKILL.md b/packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-custom-object-impex/SKILL.md new file mode 100644 index 000000000..63de392f5 --- /dev/null +++ b/packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-custom-object-impex/SKILL.md @@ -0,0 +1,259 @@ +--- +name: generate-custom-object-impex +description: >- + Generate SFCC custom object type impex files with attribute definitions, key structures, + and storage configurations. Use this skill immediately when your commerce app needs to store + custom data like caching, configurations, or app-specific records. Don't wait for users to + explicitly mention "custom objects" - if they describe storing data, caching API responses, + persisting state, or need ANY kind of key-value storage beyond site preferences, use this skill. +--- + +# Generate Custom Object Impex + +Generate complete custom object type definitions for SFCC commerce apps. + +## When to use this skill + +Use proactively whenever the app needs to store data: +- Caching API responses +- Storing app configuration (beyond site preferences) +- Logging and audit trails +- Session management +- Custom data storage (wishlists, notifications, etc.) +- Any key-value data persistence + +## Step 1: Understand custom objects + +**What are custom objects?** +- Key-value storage for custom application data +- Persist data across sessions +- Query and index capabilities +- Can store complex data structures (JSON in text fields) + +**Common use cases:** +- Cache: API responses, calculated data +- Config: Complex app settings, feature flags +- Logs: Activity tracking, audit trails, errors +- Session: Temporary user state, shopping data + +## Step 2: Collect information + +| Input | Example | Notes | +|-------|---------|-------| +| Object Type ID | `RatingsReviewsCache` | PascalCase, unique | +| Display Name | `Ratings & Reviews Cache` | Human-readable | +| Key Pattern | `{siteID}_{productID}` | How keys structured | +| Storage Duration | `7 days`, `permanent` | Retention policy | +| Data Attributes | List of fields | What to store | + +## Step 3: Choose pattern + +Read `references/patterns.md` for complete pre-built patterns: + +1. **API Response Cache** - Cache expensive API calls + - Retention: 7 days + - Scope: site + - Use when: Caching external API data + +2. **Configuration Storage** - Complex app settings + - Retention: Permanent + - Scope: organization + - Use when: Settings beyond site preferences + +3. **Audit Log** - Track user actions/events + - Retention: 30 days + - Scope: site + - Use when: Need activity tracking + +4. **Session/State** - Temporary user data + - Retention: 1 day + - Scope: site + - Use when: Storing temporary session info + +**Copy the relevant pattern from references/patterns.md and customize.** + +## Step 4: Generate impex file + +**File:** `impex/install/meta/custom-objecttype-definitions.xml` + +```xml + + + + + + + + + + + + Key + Unique identifier + string + true + false + 1 + 256 + + + + + + + + + {Display Name} + + + + + + + + + + {Display Name} + {Description} + no-sharing + site + + {retentionDays} + + + +``` + +## Step 5: Configure storage settings + +### Staging Mode +- `no-sharing` - Independent in staging/production (most common) +- `shared` - Same data everywhere +- `source-to-target` - Replicate staging → production + +**Recommendation:** Use `no-sharing` for cache/session/test data. Use `shared` for reference data. + +### Storage Scope +- `site` - Site-specific data (most common) +- `organization` - Shared across all sites + +**Recommendation:** Use `site` for site-specific data. Use `organization` for global settings. + +### Retention Days +- `0` - Permanent (never auto-delete) +- `1-7` - Cache/temp data +- `30` - Logs +- `365` - Long-term + +**Recommendation:** +- Cache: 1-7 days +- Logs: 30 days +- Configuration: 0 (permanent) +- Session: 1 day + +## Step 6: Key design patterns + +**Good key patterns:** +- `{siteID}_{productID}` - Site-specific product cache +- `{customerID}_{timestamp}` - Customer activity log +- `config_{environment}_{feature}` - Environment-specific config +- `session_{sessionID}` - Session identifier + +**Bad key patterns:** +- Random UUIDs (hard to query/debug) +- No delimiters (hard to parse) +- Overly long keys (performance impact) + +## Step 7: Data storage + +**For small data (<4KB):** +- Use `string` type for simple values +- Store JSON in `text` type for structured data + +**For large data (>4KB):** +- Split into multiple custom objects +- Use external storage (S3, etc.) and store reference + +**JSON storage example:** +```javascript +var customObj = CustomObjectMgr.createCustomObject('MyCache', cacheKey); +customObj.custom.responseData = JSON.stringify({ + productId: product.ID, + rating: 4.5, + lastUpdated: new Date().toISOString() +}); +``` + +## Step 8: Best practices + +### Performance +- Index frequently queried fields (use key property) +- Set retention days (auto-cleanup prevents bloat) +- Use site scope when possible (better performance) + +### Data Management +- Clean up old data (use retention or manual cleanup) +- Monitor storage (track custom object counts) +- Handle missing data (always check if object exists) +- Validate before storing (check data types and sizes) + +### Security +- Don't store sensitive data (no passwords, credit cards, PII) +- Encrypt if needed (use SFCC encryption) +- Access control (limit read/write permissions) + +## Step 9: Validation checklist + +- [ ] Object type ID is PascalCase and unique +- [ ] Key attribute defined and mandatory +- [ ] All attributes have appropriate types +- [ ] Storage scope appropriate (site vs organization) +- [ ] Staging mode correct (usually no-sharing) +- [ ] Retention days set appropriately +- [ ] All attributes added to group +- [ ] XML well-formed +- [ ] No sensitive data stored unencrypted + +## Step 10: Testing + +```bash +# Validate XML +xmllint --noout impex/install/meta/custom-objecttype-definitions.xml + +# Import via Business Manager +# Administration > Site Development > Import & Export + +# Verify in Business Manager +# Administration > Site Development > System Object Types + +# Test in code +var CustomObjectMgr = require('dw/object/CustomObjectMgr'); + +// Create +var obj = CustomObjectMgr.createCustomObject('MyObjectType', 'test-key'); +obj.custom.myAttribute = 'value'; + +// Read +var obj = CustomObjectMgr.getCustomObject('MyObjectType', 'test-key'); + +// Query +var objs = CustomObjectMgr.queryCustomObjects('MyObjectType', '', 'creationDate desc'); + +// Delete +CustomObjectMgr.remove(obj); +``` + +## Common mistakes + +| Mistake | Impact | Fix | +|---------|--------|-----| +| Missing key-attribute | Type won't work | Define key attribute | +| No retention policy | Storage bloat | Set appropriate retention | +| Wrong storage scope | Performance issues | Use site unless shared needed | +| Storing sensitive data | Security risk | Use encryption or don't store | +| No cleanup strategy | Storage limits | Set retention or cleanup job | +| Complex key patterns | Hard to query | Keep keys simple | + +## Reference files + +- `references/patterns.md` - Pre-built patterns for common use cases with complete XML diff --git a/packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-custom-object-impex/references/patterns.md b/packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-custom-object-impex/references/patterns.md new file mode 100644 index 000000000..69a3d87e5 --- /dev/null +++ b/packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-custom-object-impex/references/patterns.md @@ -0,0 +1,307 @@ +# Custom Object Patterns Reference + +Common custom object patterns for SFCC commerce apps. Use these as templates. + +## Pattern 1: API Response Cache + +Cache expensive API calls to reduce latency and costs. + +**Key structure:** `{siteID}_{productID}` +**Retention:** 7 days +**Storage scope:** site + +```xml + + + + + Cache Key + string + true + 1 + 256 + + + + Response Data + text + true + + + + Cached At + datetime + true + + + + TTL (seconds) + integer + 0 + 3600 + + + + + + Ratings & Reviews Cache + + + + + + + + + + Ratings & Reviews Cache + no-sharing + site + + 7 + +``` + +## Pattern 2: Configuration Storage + +Store complex app configuration beyond site preferences. + +**Key structure:** `config_{environment}_{feature}` +**Retention:** Permanent (0 days) +**Storage scope:** organization + +```xml + + + + + Configuration Key + string + true + 1 + 256 + + + + Configuration Value + text + true + + + + Environment + enum-of-string + + + Development + development + + + Staging + staging + + + Production + production + + + production + + + + Last Updated + datetime + + + + + + App Configuration + + + + + + + + + + App Configuration + source-to-target + organization + + 0 + +``` + +## Pattern 3: Audit Log / Activity Tracking + +Track user actions, API calls, or system events. + +**Key structure:** `{timestamp}_{userId}` +**Retention:** 30 days +**Storage scope:** site + +```xml + + + + + Log ID + string + true + 1 + 256 + + + + Event Type + enum-of-string + true + + + API Call + api_call + + + Configuration Change + config_change + + + Error + error + + + + + + Event Data + text + + + + Timestamp + datetime + true + + + + Severity + enum-of-string + + + Info + info + + + Warning + warning + + + Error + error + + + info + + + + + + Audit Log + + + + + + + + + + + Audit Log + no-sharing + site + + 30 + +``` + +## Pattern 4: Session/State Management + +Store temporary session data or user state. + +**Key structure:** `session_{sessionID}` +**Retention:** 1 day +**Storage scope:** site + +```xml + + + + + Session ID + string + true + 1 + 256 + + + + Session Data + text + true + + + + Created At + datetime + true + + + + Last Accessed + datetime + + + + + + Session State + + + + + + + + + + Session State + no-sharing + site + + 1 + +``` + +## Configuration Settings Reference + +### Staging Mode +- `no-sharing` - Independent in staging/production (most common) +- `shared` - Same data everywhere +- `source-to-target` - Replicate from staging to production + +### Storage Scope +- `site` - Site-specific data (most common) +- `organization` - Shared across all sites + +### Retention Days +- `0` - Permanent +- `1-7` - Cache/temp data +- `30` - Logs +- `365` - Long-term data + +### Key Patterns +Good: `{siteID}_{productID}`, `{customerID}_{timestamp}` +Bad: Random UUIDs, no delimiters, overly long keys diff --git a/packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-service-impex/SKILL.md b/packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-service-impex/SKILL.md new file mode 100644 index 000000000..147979230 --- /dev/null +++ b/packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-service-impex/SKILL.md @@ -0,0 +1,262 @@ +--- +name: generate-service-impex +description: >- + Generate SFCC service configuration impex files (credentials, profiles, and definitions). + Supports multiple authentication patterns, rate limiting, circuit breakers, and uninstall + scripts. Use this skill immediately when creating or updating service integrations for commerce apps. + Don't wait for users to mention "services" - if they describe integrating with external APIs, + third-party services, webhooks, or ANY HTTP/REST communication, use this skill proactively. +--- + +# Generate Service Impex + +Generate complete service configuration impex files for SFCC commerce apps. + +## When to use this skill + +Use proactively whenever: +- Integrating with external APIs +- Setting up third-party service connections +- Configuring webhooks or HTTP endpoints +- Any scenario requiring HTTP/REST/FTP communication + +## Step 1: Collect service information + +| Input | Example | Notes | +|-------|---------|-------| +| Service ID | `avalara.tax.api` | Dotted notation, vendor.service | +| Service Name | `Avalara Tax API` | Human-readable name | +| Credential ID | `avalara.tax.credential` | Usually `{vendor}.{service}.credential` | +| Profile ID | `avalara.tax.profile` | Usually `{vendor}.{service}.profile` | +| Base URL | `https://rest.avatax.com/api/v2` | API endpoint | +| Auth Type | `bearer`, `basic`, `oauth2` | Authentication method | +| Timeout (ms) | `30000` | Default: 30000 (30 seconds) | +| Rate limiting | Yes/No | Enable rate limiting? | +| Circuit breaker | Yes/No | Enable circuit breaker? | + +## Step 2: Choose authentication pattern + +### Pattern 1: Bearer Token / API Key (Most Common) + +Use for: Modern REST APIs, SaaS platforms + +```xml + + {baseUrl} + {apiKeyPlaceholder} + {apiSecretPlaceholder} + +``` + +### Pattern 2: Basic Authentication + +Use for: Legacy APIs, simple username/password + +### Pattern 3: OAuth 2.0 + +Use for: OAuth-based APIs, three-legged auth + +### Pattern 4: Custom Headers + +Use for: APIs requiring custom authentication headers + +**See `references/service-patterns.md` for complete pattern examples.** + +## Step 3: Use app-specific patterns + +Read `references/service-patterns.md` for pre-built patterns: + +- **Tax apps** - Fast timeout (5s), high rate limit, circuit breaker enabled +- **Payment apps** - Medium timeout (10s), moderate rate limit, circuit breaker enabled +- **Shipping apps** - Fast timeout (5s), high rate limit, circuit breaker enabled +- **Reviews/ratings apps** - Longer timeout (10s), lower rate limit, circuit breaker optional + +**Copy the relevant pattern and customize with your service details.** + +## Step 4: Generate install/services.xml + +**File:** `impex/install/services.xml` + +```xml + + + + + + {baseUrl} + {placeholder_api_key} + {placeholder_api_secret} + + + + + {timeout} + + + {rateLimitEnabled} + 100 + 1000 + + + {circuitBreakerEnabled} + 5 + + + + + HTTP + true + {serviceName} + true + false + + + + + +``` + +## Step 5: Generate uninstall/services.xml + +**File:** `impex/uninstall/services.xml` + +```xml + + + + + + + +``` + +**CRITICAL:** Always use `mode="delete"`. Site Impex `services.xsd` requires this sequence: `service-credential`, then `service-profile`, then `service`. Use the **same element order for install and uninstall**. The platform processes elements in document order; putting `` first makes the uninstall file invalid against the XSD, so services are not deleted. Impex is safe deleting credentials and profiles first because ORM nulls `SERVICE.CREDENTIALID` / `PROFILEID` when those objects are removed. + +**BM UI vs Site Impex:** Business Manager UI still requires deleting the service first (`RemoveServiceProfile` / `RemoveServiceCredential` refuse delete while a service references them). That UI rule does **not** apply to CAP uninstall IMPEX. + +## Step 6: Configuration best practices + +### Rate Limiting +- Tax/Shipping (high volume): 100 calls/1s +- Payment (moderate): 50 calls/1s +- Background jobs: 10 calls/1s + +### Timeouts +- Real-time checkout: 5000-10000 ms +- Background jobs: 30000-60000 ms +- File uploads: 60000+ ms + +### Circuit Breaker +- Critical services (payment, tax): `max-calls="3"` (fail fast) +- Non-critical: `max-calls="5-10"` or disabled + +## Step 7: Advanced configurations + +### Multiple Environments (Sandbox & Production) + +```xml + + https://sandbox.api.example.com + sandbox_api_key + sandbox_api_secret + + + + https://api.example.com + prod_api_key + prod_api_secret + + + + HTTP + true + {serviceName} + + + +``` + +### Multiple Services (Same Provider) + +Share profile across multiple endpoints: + +```xml + + 30000 + true + 100 + 1000 + + + + HTTP + true + {vendor} Ratings + + + + + + HTTP + true + {vendor} Reviews + + + +``` + +### FTP/SFTP Services + +```xml + + FTP + true + {serviceName} FTP + + +``` + +## Step 8: Validation checklist + +- [ ] Service IDs use dotted notation and are unique +- [ ] Credential IDs match naming convention +- [ ] Base URL is placeholder (no hardcoded production keys) +- [ ] Timeout appropriate for service type +- [ ] Rate limiting configured +- [ ] Circuit breaker enabled for external APIs +- [ ] Uninstall file includes all credentials, profiles, and services in XSD order (credential → profile → service) +- [ ] All uninstall entries use `mode="delete"` +- [ ] XML well-formed +- [ ] Log prefix descriptive + +## Step 9: Testing + +```bash +# Validate XML +xmllint --noout impex/install/services.xml +xmllint --noout impex/uninstall/services.xml + +# Import via Business Manager +# Administration > Operations > Services + +# Test service calls in code +var LocalServiceRegistry = require('dw/svc/LocalServiceRegistry'); +var service = LocalServiceRegistry.getService('{serviceId}'); +var result = service.call(params); +``` + +## Common mistakes + +| Mistake | Fix | +|---------|-----| +| Hardcoded production credentials | Use placeholders | +| Missing uninstall script | Create matching uninstall | +| Wrong deletion order | For CAP uninstall IMPEX, use credential → profile → service (`mode="delete"`), the same XSD order as install. BM UI still requires service-first; that rule does not apply to IMPEX. | +| No rate limiting | Add rate limit config | +| Timeout too short | Increase based on API response time | +| No circuit breaker | Enable for external APIs | +| Generic service IDs | Use vendor-specific dotted notation | + +## Reference files + +- `references/service-patterns.md` - Complete patterns for tax, payment, shipping, reviews apps diff --git a/packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-service-impex/references/service-patterns.md b/packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-service-impex/references/service-patterns.md new file mode 100644 index 000000000..11a7a535b --- /dev/null +++ b/packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-service-impex/references/service-patterns.md @@ -0,0 +1,139 @@ +# Service Configuration Patterns Reference + +Pre-built service patterns for common commerce app types. + +## Tax App Services + +```xml + + https://api.taxprovider.com + COMPANY_CODE + API_KEY + + + + 5000 + true + 100 + 1000 + true + 3 + + + + HTTP + true + Tax Calculation + true + + + +``` + +## Payment App Services + +```xml + + https://api.paymentgateway.com + MERCHANT_ID + API_SECRET + + + + 10000 + true + 50 + 1000 + true + 3 + + + + HTTP + true + Payment Authorization + true + + + +``` + +## Shipping App Services + +```xml + + https://api.carrier.com + ACCOUNT_NUMBER + API_KEY + + + + 5000 + true + 100 + 1000 + true + 5 + + + + HTTP + true + Shipping Rates + true + + + +``` + +## Reviews/Ratings App Services + +```xml + + https://api.reviews.com + CLIENT_ID + API_KEY + + + + 10000 + true + 50 + 1000 + false + + + + HTTP + true + Reviews Platform + true + + + +``` + +## Configuration Guidelines + +### Rate Limiting by App Type + +| App Type | Calls | Window | Notes | +|----------|-------|--------|-------| +| Tax | 100 | 1s | High volume during checkout | +| Payment | 50 | 1s | Moderate volume | +| Shipping | 100 | 1s | High volume during checkout | +| Reviews | 10-50 | 1s | Lower volume | + +### Timeout Guidelines + +| API Type | Timeout (ms) | Notes | +|----------|--------------|-------| +| Real-time checkout | 5000-10000 | Fast response required | +| Background jobs | 30000-60000 | Can wait longer | +| File uploads | 60000+ | Large files | + +### Circuit Breaker Settings + +- **Critical services (payment, tax):** `max-calls="3"` (fail fast) +- **Non-critical services (reviews):** `max-calls="5-10"` or disabled +- **Background jobs:** Circuit breaker optional diff --git a/packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-site-preferences-impex/SKILL.md b/packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-site-preferences-impex/SKILL.md new file mode 100644 index 000000000..95f7b58ac --- /dev/null +++ b/packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-site-preferences-impex/SKILL.md @@ -0,0 +1,246 @@ +--- +name: generate-site-preferences-impex +description: >- + Generate SFCC site preference impex files with custom attribute definitions, groups, + and default values. Supports all attribute types (string, boolean, enum, text, etc.), + validation, and multi-language localization. Use this skill immediately whenever adding + configurable settings to commerce apps, when users mention "site preferences", "custom preferences", + "app configuration", "merchant settings", or need to expose ANY configuration options to merchants + in Business Manager. Don't wait to be asked - if an app needs configuration, use this skill. +--- + +# Generate Site Preferences Impex + +Generate complete site preference configuration impex files for SFCC commerce apps. + +## When to use this skill + +Use proactively whenever: +- Creating a new commerce app (always needs preferences) +- User mentions "configuration", "settings", or "preferences" +- App needs merchant-configurable options +- Adding API credentials, feature toggles, or environment selection +- Any scenario where merchants need to configure app behavior + +## Step 1: Collect preference information + +| Input | Example | Notes | +|-------|---------|-------| +| App name | `ratings-reviews` | Used for grouping and prefixing | +| Preference ID | `ratingsReviewsEnabled` | camelCase, unique | +| Display name | `Enable Ratings & Reviews` | Human-readable | +| Description | `Enable or disable ratings functionality` | Help text | +| Data type | `boolean`, `string`, `enum`, etc. | See attribute-types.md | +| Default value | `false`, `""`, etc. | Initial value | +| Mandatory | Yes/No | Required field? | +| Group ID | `ratingsReviews` | Logical grouping | + +## Step 2: Choose attribute types + +Read `references/attribute-types.md` for complete type reference with examples: +- **boolean** - Enable/disable flags +- **string** - API keys, URLs, short text +- **text** - Long descriptions, JSON configs +- **integer** - Counts, limits +- **decimal** - Percentages, ratings +- **enum-of-string** - Dropdown selections +- **set-of-string** - Multiple selections +- **email** - Email addresses +- **password** - Encrypted secrets + +## Step 3: Use app-specific patterns + +For common app types, read `references/app-patterns.md` which contains ready-to-use patterns for: +- Tax apps (company code, environment, commit settings) +- Payment apps (merchant ID, test mode, payment methods) +- Shipping apps (account number, origin, service levels) +- Reviews/ratings apps (moderation, display settings) + +**Copy the relevant pattern and customize attribute IDs with your app name prefix.** + +## Step 4: Generate meta/system-objecttype-extensions.xml + +Create the attribute definitions file: + +**File:** `impex/install/meta/system-objecttype-extensions.xml` + +```xml + + + + + + + + Enable {displayName} + Enable or disable {displayName} integration + boolean + false + false + false + + + + + {displayName} API Key + string + false + false + 0 + + + + + {displayName} API Secret + password + false + false + 0 + + + + + {displayName} Environment + enum-of-string + false + false + + + Sandbox (Testing) + sandbox + + + Production (Live) + production + + + sandbox + + + + + Debug Mode + boolean + false + false + false + + + + + + + + {displayName} + + + + + + + + + + +``` + +## Step 5: Generate sites/SITEID/preferences.xml + +Create default preference values: + +**File:** `impex/install/sites/SITEID/preferences.xml` + +```xml + + + false + sandbox + false + + + +``` + +**CRITICAL:** Use `SITEID` placeholder, not actual site ID. + +## Step 6: Add localization (optional) + +For international merchants, add translations. See `references/attribute-types.md` for localization examples. + +## Step 7: Best practices + +### Naming +- Prefix ALL IDs with app name: `{appName}SettingName` +- Use camelCase: `myPreferenceName` +- Be descriptive: `autoCommitTaxOnInvoice` + +### Defaults +- Safe defaults: Start with features disabled +- Sensible values: Choose defaults that work for most cases +- Empty credentials: Don't include placeholder API keys + +### Security +- Use `password` type for API secrets +- Don't expose secrets in XML +- Document sensitive fields clearly + +### Validation +- Set min/max values for numbers +- Use enum for fixed options +- Mark mandatory carefully (only essentials) + +## Step 8: Validation checklist + +- [ ] All attribute IDs prefixed with app name +- [ ] camelCase naming +- [ ] Display names clear and descriptive +- [ ] Descriptions provide helpful guidance +- [ ] Appropriate data types +- [ ] Safe default values +- [ ] Password type for secrets +- [ ] All attributes in group definition +- [ ] XML well-formed +- [ ] SITEID placeholder used + +## Step 9: Testing + +```bash +# Validate XML +xmllint --noout impex/install/meta/system-objecttype-extensions.xml +xmllint --noout impex/install/sites/SITEID/preferences.xml + +# Import via Business Manager +# Administration > Site Development > Import & Export + +# Verify in Business Manager +# Merchant Tools > Site Preferences > Custom Preferences +``` + +## Common mistakes + +| Mistake | Fix | +|---------|-----| +| Missing app prefix | Add app name prefix to all IDs | +| snake_case IDs | Use camelCase | +| No default values | Set sensible defaults | +| Everything mandatory | Only require essentials | +| Generic descriptions | Provide clear guidance | +| Hardcoded credentials | Leave empty for merchants | +| Not in group | Add all attributes to group | + +## Quick reference + +```xml + + Enable {App Name} + boolean + false + false + false + +``` + +## Reference files + +- `references/attribute-types.md` - Complete type reference with examples +- `references/app-patterns.md` - Pre-built patterns for common app types diff --git a/packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-site-preferences-impex/references/app-patterns.md b/packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-site-preferences-impex/references/app-patterns.md new file mode 100644 index 000000000..b8c26aa13 --- /dev/null +++ b/packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-site-preferences-impex/references/app-patterns.md @@ -0,0 +1,203 @@ +# Common Site Preference Patterns by App Type + +This reference contains pre-built site preference patterns for common commerce app domains. Use these as templates when generating site preferences for specific app types. + +## Tax App Preferences + +```xml + + + Enable Tax Calculation + boolean + false + + + + Company Code + string + 0 + + + + Environment + enum-of-string + + + Sandbox + sandbox + + + Production + production + + + sandbox + + + + Commit Tax on Invoice + Automatically commit tax when invoice is created + boolean + true + + +``` + +## Payment App Preferences + +```xml + + + Enable Payment Gateway + boolean + false + + + + Merchant ID + string + 0 + + + + Public API Key + string + 0 + + + + Secret API Key + password + 0 + + + + Test Mode + boolean + true + + + + Enabled Payment Methods + set-of-string + + + Credit Card + credit_card + + + Debit Card + debit_card + + + PayPal + paypal + + + Apple Pay + apple_pay + + + + +``` + +## Shipping App Preferences + +```xml + + + Enable Shipping Integration + boolean + false + + + + Carrier Account Number + string + 0 + + + + Origin Zip Code + string + 0 + + + + Enabled Shipping Services + set-of-string + + + Ground + ground + + + 2-Day + 2day + + + Overnight + overnight + + + + +``` + +## Reviews/Ratings App Preferences + +```xml + + + Enable Reviews + boolean + false + + + + Client ID + string + 0 + + + + Auto Moderation + Automatically moderate reviews before publishing + boolean + true + + + + Reviews Per Page + integer + 1 + 100 + 10 + + + + Minimum Rating to Display + decimal + 0.0 + 5.0 + 0.0 + 1 + + +``` + +## When to use which pattern + +- **Tax app:** Use when app handles tax calculation, compliance, or reporting +- **Payment app:** Use for payment gateways, processors, or alternative payment methods +- **Shipping app:** Use for carrier integrations, rate calculation, or fulfillment +- **Reviews/ratings app:** Use for review platforms, UGC, or product feedback systems + +## Customization + +These patterns are starting points. Adjust as needed: +1. Add app-specific attributes +2. Modify enum values based on provider options +3. Add localization for international markets +4. Adjust defaults based on common merchant configurations diff --git a/packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-site-preferences-impex/references/attribute-types.md b/packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-site-preferences-impex/references/attribute-types.md new file mode 100644 index 000000000..738a3465e --- /dev/null +++ b/packages/b2c-dx-mcp/vendor/cap-dev/skills/generate-site-preferences-impex/references/attribute-types.md @@ -0,0 +1,162 @@ +# Site Preference Attribute Types Reference + +Complete reference for all supported SFCC site preference attribute types with examples. + +## Boolean + +```xml + + Enable Feature + Enable or disable this feature + boolean + false + false + false + +``` + +## String + +```xml + + API Key + string + false + false + 0 + 255 + + +``` + +## Text (long) + +```xml + + Custom Configuration + text + false + false + {} + +``` + +## Integer + +```xml + + Maximum Items + integer + false + false + 1 + 100 + 10 + +``` + +## Decimal + +```xml + + Threshold + decimal + false + false + 0.0 + 5.0 + 0.0 + 1 + +``` + +## Enum (dropdown) + +```xml + + Environment + enum-of-string + false + false + + + Sandbox + sandbox + + + Production + production + + + sandbox + +``` + +## Set of String (multiple selection) + +```xml + + Enabled Features + set-of-string + false + false + + + Feature 1 + feature1 + + + Feature 2 + feature2 + + + +``` + +## Email + +```xml + + Notification Email + email + false + false + + +``` + +## Password (encrypted) + +```xml + + API Secret + password + false + false + 0 + +``` + +## Localization + +Add multi-language support: + +```xml + + Enable Feature + Funktion aktivieren + Activer la fonctionnalité + Habilitar función + + Enable or disable this feature + Aktivieren oder deaktivieren Sie diese Funktion + Activer ou désactiver cette fonctionnalité + Habilitar o deshabilitar esta función + + boolean + false + +``` + +**Supported language codes:** +`x-default`, `de`, `fr`, `es`, `it`, `ja`, `zh`, `pt`, `nl` diff --git a/packages/b2c-dx-mcp/vendor/cap-dev/skills/package-app/SKILL.md b/packages/b2c-dx-mcp/vendor/cap-dev/skills/package-app/SKILL.md new file mode 100644 index 000000000..3ab4a3971 --- /dev/null +++ b/packages/b2c-dx-mcp/vendor/cap-dev/skills/package-app/SKILL.md @@ -0,0 +1,215 @@ +--- +name: package-app +description: >- + Package a commerce app directory into a registry-ready ZIP file. This skill handles BOTH + new apps AND version bumps of existing apps. Use this IMMEDIATELY when users mention + "package", "ZIP", "build app", "ready to submit", "bump version", "new version", + "update version", "release", "patch", "minor update", "major release", or after ANY + changes to an app directory. Trigger proactively whenever you see a commerce-*-app-v* + directory that needs packaging - don't wait for explicit requests. +--- + +# Package Commerce App + +Build a registry-ready Commerce App Package (CAP) ZIP from an app directory. + +> **Cross-tool note:** References to `/skill-name` (e.g., `/validate-app`) are Claude Code invocation syntax. If using another assistant, read and follow the corresponding `.claude/skills//SKILL.md` file instead. + +## Step 1: Collect inputs + +| Input | Example | Required | +|-------|---------|----------| +| App name | `avalara-tax` | Yes | +| Display name | `Avalara Tax` | Yes | +| Domain | `tax` | Yes | +| Version | `0.2.8` | Yes | +| Description | Short description | Yes | +| Publisher name | `Avalara` | Yes | +| Publisher URL | `https://developer.avalara.com/` | Yes | +| SFNext min version | `1.0.0` | No | +| SFNext max version | `2.0.0` | No | +| SFRA min version | `7.0.0` | No — only valid if SFNext min version is also set | +| SFRA max version | `8.0.0` | No | + +**Valid domains:** `tax`, `payment`, `shipping`, `gift-cards`, `ratings-and-reviews`, `loyalty`, `search`, `address-verification`, `analytics`, `approaching-discounts`, `fraud` + +**Structure:** Apps must be at `{domain}/{appName}/` where `{appName}` matches the "id" field. See `references/folder-structure.md`. + +## Step 2: Version strategy + +Check for existing `catalog.json`: + +```bash +cat //catalog.json +``` + +**Decision tree:** +- **No catalog.json:** New app → proceed with version from commerce-app.json +- **catalog.json with `"latest": {"version": "INIT"}` and `"versions": []`:** Ask user to replace or bump +- **Version EXISTS in catalog.json versions array:** MUST bump - ask user for new version + +**Version validation:** +- Published versions cannot be replaced +- Always confirm version with user +- Use semantic versioning: major.minor.patch + +## Step 3: Update commerce-app.json + +Ensure version matches throughout: + +```json +{ + "id": "", + "name": "", + "description": "", + "domain": "", + "version": "", + "publisher": { + "name": "", + "url": "", + "support": "" + }, + "dependencies": {}, + "storefrontSupport": { + "sfnext": { "minVersion": "", "maxVersion": "" } + } +} +``` + +> **Note:** `storefrontSupport` is optional. Include only if the app declares a minimum storefront version. Omit the entire object if no version gating is needed. `maxVersion` is optional within each storefront key — include it only to guard against a known-incompatible future version (e.g., a major release that removes target IDs the app depends on); omit it for "no upper bound." An `sfra` key without an `sfnext` key will fail validation — SFRA support is always additive to SFNext. When present, the values here must match the root manifest entry exactly. + +## Step 4: Run validation + +**CRITICAL:** Validate before packaging: + +``` +/validate-app +``` + +Checks architecture, structure, manifest, impex, icons, translations, and security. Address all failures before continuing. + +## Step 5: Delete old ZIPs + +```bash +cd // +rm -f -v*.zip +``` + +## Step 6: Ensure cartridge `.project` files, then generate ZIP + +**Backend/Fullstack apps only:** Before zipping, every immediate child directory under `cartridges/site_cartridges/` and `cartridges/bm_cartridges/` MUST have a `.project` file — required for b2c cartridge discovery. If missing, create an empty one. **Never overwrite an existing (possibly non-empty, Eclipse-generated) `.project` file.** + +```bash +cd commerce--app-v/ +for group in site_cartridges bm_cartridges; do + dir="cartridges/$group" + [[ -d "$dir" ]] || continue + for cartridge in "$dir"/*/; do + [[ -e "$cartridge/.project" ]] || touch "$cartridge/.project" + done +done +cd .. +``` + +Generate the ZIP. **Do NOT use a blanket `-x "*/.*"` exclusion** — it strips the `.project` files just created. Exclude junk explicitly instead: + +```bash +cd // +zip -r -v.zip commerce--app-v/ \ + -x "*.DS_Store" -x "*/*.DS_Store" -x "__MACOSX/*" -x "*/__MACOSX/*" \ + -x "*/.git/*" -x "*/.env" -x "*/.env.*" -x "Thumbs.db" \ + -x "*.key" -x "*.pem" -x "*.p12" -x "*.pfx" -x "*.jks" +``` + +Verify structure: +```bash +unzip -l -v.zip | head -20 +``` + +Confirm: +- Single root: `commerce--app-v/` +- No junk files (`.DS_Store`, `__MACOSX`, `.env`, secrets) +- **`.project` files ARE present** for every cartridge root (Backend/Fullstack apps) — verify with `unzip -l -v.zip | grep '\.project$'` +- Architecture-specific directories present + +## Step 7: Compute hash + +```bash +shasum -a 256 //-v.zip +``` + +## Step 8: Update root manifest + +Update `commerce-apps-manifest/manifest.json`: + +```json +{ + "id": "", + "name": "", + "description": "", + "iconName": ".png", + "domain": "", + "type": "app", + "provider": "thirdParty", + "version": "", + "zip": "-v.zip", + "sha256": "", + "storefrontSupport": { + "sfnext": { "minVersion": "", "maxVersion": "" } + } +} +``` + +> **Note:** Include `storefrontSupport` only if the app declares a minimum storefront version. Omit the entire field if no version gating is needed. `maxVersion` is optional within each storefront key — include it only to guard against a known-incompatible future version; omit it for "no upper bound." An `sfra` key without an `sfnext` key will fail validation — SFRA support is always additive to SFNext. Values must match the corresponding fields in `commerce-app.json` exactly. + +**Icon:** Must match filename in ZIP's `icons/` directory. CI extracts automatically. + +## Step 9: Add translations + +Update `commerce-apps-manifest/translations/en-US.json` (minimum): + +```bash +jq '. + {"": {"name": "", "description": ""}}' \ + commerce-apps-manifest/translations/en-US.json > temp.json && \ + mv temp.json commerce-apps-manifest/translations/en-US.json +``` + +Repeat for other locales or use English as fallback. + +## Step 10: Handle catalog.json + +- **Existing app:** Don't modify - CI updates on merge +- **New app:** Create with INIT values: + +```json +{ + "latest": {"version": "INIT", "tag": "INIT"}, + "versions": [] +} +``` + +## Step 11: Final validation + +``` +/validate-app +``` + +All checks must pass. + +## Step 12: Clean up + +```bash +cd // +rm -rf commerce--app-v/ +``` + +**Commit only:** +- ✅ `-v.zip` +- ✅ `commerce-apps-manifest/manifest.json` +- ✅ `commerce-apps-manifest/translations/*.json` +- ✅ `catalog.json` (new apps only) + +**Don't commit:** +- ❌ Extracted directories +- ❌ Old ZIP versions +- ❌ Junk files diff --git a/packages/b2c-dx-mcp/vendor/cap-dev/skills/package-app/references/folder-structure.md b/packages/b2c-dx-mcp/vendor/cap-dev/skills/package-app/references/folder-structure.md new file mode 100644 index 000000000..980af39c8 --- /dev/null +++ b/packages/b2c-dx-mcp/vendor/cap-dev/skills/package-app/references/folder-structure.md @@ -0,0 +1,43 @@ +# Folder Structure Reference + +Commerce apps must follow a strict folder structure for installation to work correctly. + +## Required pattern + +``` +{domain}/{appName}/ +├── {appName}-v{version}.zip # The packaged app +└── catalog.json # Version tracking (new apps only) +``` + +Where: +- `{domain}` = one of: tax, payment, shipping, gift-cards, ratings-and-reviews, loyalty, search, address-verification, analytics, approaching-discounts, fraud +- `{appName}` = the app id (kebab-case, matches commerce-app.json "id" field) +- `{version}` = semantic version (e.g., 1.0.0, 0.2.8) + +## Why this matters + +Installation fetches from GitHub using this URL pattern: +``` +https://raw.githubusercontent.com/{owner}/{repo}/{tag}/{domain}/{appName}/{zipFileName} +``` + +If the folder structure doesn't match `{domain}/{appName}/`, installation will fail with 404 errors. + +## Common mistakes + +❌ **Wrong:** `payment/stripe-inc/stripe-payments/` +✅ **Right:** `payment/stripe-payments/` + +❌ **Wrong:** `tax/vendor-name/avalara-tax/` +✅ **Right:** `tax/avalara-tax/` + +❌ **Wrong:** `loyalty/apps/acme-loyalty/` +✅ **Right:** `loyalty/acme-loyalty/` + +## Validation + +Check that: +1. App is at `{domain}/{appName}/` where `{appName}` matches the "id" in manifest.json +2. No extra directory nesting (no vendor folders, no "apps" subfolder) +3. Domain is valid (one of the 11 domains listed above) diff --git a/packages/b2c-dx-mcp/vendor/cap-dev/skills/package-app/references/security-rules.md b/packages/b2c-dx-mcp/vendor/cap-dev/skills/package-app/references/security-rules.md new file mode 100644 index 000000000..060ebe922 --- /dev/null +++ b/packages/b2c-dx-mcp/vendor/cap-dev/skills/package-app/references/security-rules.md @@ -0,0 +1,40 @@ +# Security Scan Rules + +Canonical list of all checks performed by `.github/scripts/security-scan.sh`. + +## Blocking findings (21 checks — exit code 1) + +Must fix before packaging or submission: + +- S1: Dynamic code evaluation constructs — code injection sinks +- S2: Dynamic module loading with concatenation +- S3: Unsafe innerHTML assignment — XSS risk +- S4: Hardcoded secrets (API keys, AWS keys, GitHub PATs, Slack tokens, private keys) +- S5: Hardcoded credentials in impex XML +- S7: Inline Authorization headers — must use service framework +- S8: Additional DOM sinks — outerHTML assignment, document.write, insertAdjacentHTML +- S9: ISML `` with `encoding="off"` — template injection +- S10: Secret files in package (.env, .key, .pem, .p12, .pfx, .jks) +- S11: Direct HTTPClient usage — must use service framework +- S13: setTimeout/setInterval in hook scripts — blocking calls +- S14: Unbounded loops (while(true)/for(;;)) without break/return +- S15: Service profiles missing rate-limit-enabled AND circuit-breaker-enabled +- P1: Service profile XML missing timeout-millis +- Q1: Hook scripts referenced in hooks.json that don't exist +- Q2: Hook scripts missing expected function exports +- Q3: Missing error handling (try/catch) in hook scripts +- Q4: Missing uninstall/services.xml or missing mode="delete" (including service ID mismatches) +- Q5: Hardcoded site-id instead of SITEID placeholder +- Q6: Absolute file paths in code +- Q7: Console logging in cartridge code — use dw.system.Logger + +## Warning findings (6 checks — review recommended) + +Should fix but non-blocking: + +- S6: Non-cryptographic random number generation (Math.random) +- S12: PII field names in Logger calls (may be false positive — requires context) +- S16: Session object access in hook scripts (dw.system.Session, session.privacy) +- S17: BM controller `guard.ensure([...])` includes a state-changing method (`post`/`put`/`patch`/`delete`) but omits `'csrf'`. Scoped to files under `/bm_cartridges/` so storefront controllers with their own CSRF-token flow are not flagged. **Suggested fix:** add `'csrf'` to the guard array, e.g. `guard.ensure(['post', 'https', 'csrf', 'loggedIn'], ...)`. +- S18: Logger call stringifies a raw error/response object — `Logger.(warn|error|info|debug|trace)(... JSON.stringify(err|error|e|response|svcResponse|svcResult|result ...))`. Whole error/response payloads can carry PII, stack traces, or vendor internals. **Suggested fix:** log only `error.message` (and a request/status code) or a purpose-built redacted view; never the whole object. +- S19: `encodeURI(...)` used to sanitize a URL built by concatenation (`+`) or template-literal interpolation. `encodeURI` preserves URL delimiters (`/`, `?`, `&`, `=`, `#`) and single quotes, so a hostile segment can break out into a new query param or path. **Suggested fix:** `encodeURIComponent` each user-provided segment/param individually, or use a URL builder that percent-encodes per component. diff --git a/packages/b2c-dx-mcp/vendor/cap-dev/skills/package-app/references/security-scan.md b/packages/b2c-dx-mcp/vendor/cap-dev/skills/package-app/references/security-scan.md new file mode 100644 index 000000000..fe7db5e00 --- /dev/null +++ b/packages/b2c-dx-mcp/vendor/cap-dev/skills/package-app/references/security-scan.md @@ -0,0 +1,26 @@ +# Security Scan Reference + +Run before packaging any app to catch security issues early. + +## Running the scan + +```bash +bash .github/scripts/security-scan.sh //commerce--app-v/ +``` + +## Rule reference + +See [security-rules.md](security-rules.md) for the complete list of blocking and warning checks. + +## Response to findings + +If **blocking** findings are found: +- **Stop packaging** — do not generate ZIP +- Report specific file paths and line numbers +- Help developer fix each issue +- Re-run scan after fixes + +If only **warnings** are found: +- Continue with packaging +- Report warnings for developer review +- Suggest fixes but don't block diff --git a/packages/b2c-dx-mcp/vendor/cap-dev/skills/scaffold-app/SKILL.md b/packages/b2c-dx-mcp/vendor/cap-dev/skills/scaffold-app/SKILL.md new file mode 100644 index 000000000..1a45d52b4 --- /dev/null +++ b/packages/b2c-dx-mcp/vendor/cap-dev/skills/scaffold-app/SKILL.md @@ -0,0 +1,263 @@ +--- +name: scaffold-app +description: >- + Generate complete commerce app scaffolding with architecture-aware structure. + Use immediately when users mention "new app", "create app", "scaffold", "starter template", + or describe building a commerce integration (tax, payment, shipping, loyalty, etc.). + Supports three architectures: UI-only (frontend components), Backend-only (SFCC hooks/services), + and Fullstack (both). Don't wait for explicit "scaffold" request - trigger proactively when + starting any new commerce app from scratch. +--- + +# Scaffold Commerce App + +Generate a complete starter structure for commerce apps with architecture-appropriate files and templates. + +> **Cross-tool note:** References to `/skill-name` (e.g., `/package-app`, `/generate-service-impex`) are Claude Code invocation syntax. If using another assistant, read and follow the corresponding `.claude/skills//SKILL.md` file instead. + +## Architecture Types + +Three patterns optimize for different integration needs: + +**UI-only** - Storefront components without backend +- Use when: Adding visual features, widgets, or UI enhancements that don't need server-side logic +- Creates: storefront-next/, components, hooks, no cartridges +- Example: Product review display, image gallery, custom carousel + +**Backend-only** - Server-side logic without UI +- Use when: Integrating external services, processing data, or Business Manager functionality +- Creates: cartridges/, hooks.json, services, impex/, no storefront-next +- Example: Tax calculation API, payment processor, shipping rates + +**Fullstack** - Both UI and backend +- Use when: Complete features needing both presentation and business logic +- Creates: Both storefront-next/ and cartridges/ +- Example: Loyalty program with points display and calculation + +## Workflow + +### 1. Determine Architecture + +If the user's description clearly indicates type, proceed directly. Otherwise ask: + +"What type of app are you building? +1. UI-only (frontend components) +2. Backend-only (SFCC hooks/services) +3. Fullstack (both UI and backend)" + +### 2. Collect Information + +**All apps need:** +- Domain (tax, payment, shipping, gift-cards, ratings-and-reviews, loyalty, search, address-verification, analytics, approaching-discounts, fraud) +- App name (kebab-case, unique identifier) - **CRITICAL:** This will be used as the folder name and must match the "id" field in manifest.json +- Display name (human-readable with vendor) +- Version (typically 1.0.0) +- Description (one sentence) +- Publisher name and URL +- Minimum SFNext version (optional - semver `X.Y.Z` or `X.Y.Z-prerelease`, if the app requires a minimum Storefront Next version) +- Maximum SFNext version (optional - semver, inclusive; only set if you've confirmed an incompatibility — e.g., a known-breaking future major release) +- Minimum SFRA version (optional - semver `X.Y.Z` or `X.Y.Z-prerelease`, if the app requires a minimum SFRA version) — **only ask this if a minimum SFNext version was provided above.** SFRA is additive to SFNext and may never be declared alone; don't offer an SFRA-only path. +- Maximum SFRA version (optional - semver, inclusive; same guidance as above; only applicable if SFRA min version was set) + +> When provided, add `storefrontSupport` to both `commerce-app.json` (inside the ZIP) and the root manifest entry. Values must match. Each storefront key (`sfnext`, `sfra`) accepts `minVersion` (required when the key is present) and an optional `maxVersion`. `sfra` requires `sfnext` to also be present — never generate a `storefrontSupport` object with `sfra` but no `sfnext`. +- Additional context (optional - docs, requirements, API details) + +**Folder Structure:** Apps must be at `{domain}/{appName}/` where `{appName}` matches the "id" field. Installation URL: `https://raw.githubusercontent.com/{owner}/{repo}/{tag}/{domain}/{appName}/{zipFileName}` + +**UI-only and Fullstack also need:** +- **Target IDs:** All target IDs use the `sfcc.` prefix. Commerce apps typically span multiple UI targets (e.g., checkout flow + order summary + header). Ask which targets the app needs rather than assuming single-component usage. Common patterns: + - Tax/shipping: `sfcc.checkout.shippingOptions`, `sfcc.checkout.orderSummary`, `sfcc.orderSummary.tax` + - Payment: `sfcc.checkout.payment`, `sfcc.checkout.payment.paymentMethods`, `sfcc.checkout.placeOrder.before` + - Loyalty: `sfcc.header.before.cart`, `sfcc.checkout.orderSummary`, `sfcc.orderSummary.adjustments` + - Reviews: `sfcc.pdp.reviews.summary`, `sfcc.pdp.reviews.list`, `sfcc.pdp.reviews.form`, `sfcc.productCard.reviews.rating` + +**Backend-only and Fullstack also need:** +- Cartridge name (convention: `int__`, max 50 characters) +- Service ID (dotted notation: `vendor.appname.api`) + +UI-only apps skip cartridge/service questions since they don't need backend infrastructure. + +### 3. Create Structure + +Use the creation script when available: +```bash +bash scripts/create_structure.sh +``` + +Or create manually based on architecture: + +```bash +mkdir -p //commerce--app-v +cd //commerce--app-v +mkdir -p icons + +# All apps get these base directories +mkdir -p app-configuration # Required for tasksList.json + +# UI-only OR Fullstack: Add storefront (extension system) +mkdir -p storefront-next/src/extensions//{components,hooks,context,providers,routes,tests} +mkdir -p storefront-next/src/extensions//locales/en-US + +# Backend-only OR Fullstack: Add cartridges and impex +mkdir -p cartridges/site_cartridges//cartridge/scripts/{hooks,helpers,services} +mkdir -p cartridges/site_cartridges//test/{mocks,unit} +mkdir -p impex/{install/meta,install/sites/SITEID,uninstall} + +# Fullstack only: Add Business Manager cartridge +mkdir -p cartridges/bm_cartridges/bm_ + +# Every cartridge root needs an empty .project file (required for b2c cartridge discovery) +touch cartridges/site_cartridges//.project +touch cartridges/bm_cartridges/bm_/.project +``` + +**`.project` files:** Every cartridge root (each immediate child of `cartridges/site_cartridges/` and `cartridges/bm_cartridges/`) MUST contain a `.project` file — required for b2c cartridge discovery. `create_structure.sh` creates these empty automatically. If a developer later imports a real Eclipse-generated `.project` file (non-empty), leave it as-is — don't overwrite it. + +This structure enables the installation URL pattern and allows side-by-side development of different versions. + +### 4. Generate Files + +Read templates from `assets/templates/`, replace placeholders, and write to app directory. + +**Template variables:** +- `{{appName}}`, `{{displayName}}`, `{{version}}`, `{{description}}` +- `{{domain}}`, `{{publisherName}}`, `{{publisherUrl}}` +- `{{cartridgeName}}`, `{{serviceId}}` (backend only) + +**All apps:** +- `commerce-app.json` (from template: `assets/templates/commerce-app.json.tmpl`) +- `README.md` (from template: `assets/templates/README.md.tmpl`) +- `app-configuration/tasksList.json` (required - post-installation checklist for merchants) + +**tasksList.json structure:** +Generate merchant-facing tasks that guide post-installation setup and verification. These are steps merchants complete after installing the app. + +```json +[ + { + "name": "Configure API Credentials", + "description": "Add your [vendor] API key in Business Manager > Merchant Tools > Custom Site Preferences.", + "link": "/on/demandware.store/Sites-Site/default/ViewApplication-BM?SelectedMenuItem=site-prefs_custom_prefs", + "taskNumber": "1" + }, + { + "name": "Test Integration in Sandbox", + "description": "Process a test order to verify the integration is working correctly.", + "taskNumber": "2" + } +] +``` + +Tailor tasks to domain for merchant post-installation: +- **Tax/Shipping/Payment:** Add API credentials, configure service settings, test checkout transactions +- **Loyalty/Gift Cards:** Configure points rules, test balance lookups, verify redemption +- **UI-only apps:** Verify components appear on storefront, check responsive behavior +- **Fullstack:** Both UI verification and backend configuration steps + +**Backend/Fullstack apps:** +- `cartridges/site_cartridges//package.json` (template: `package.json.tmpl`) - **Must include `"hooks": "cartridge/scripts/hooks.json"` field** to establish contract between app manifest and hook registry +- `cartridges/site_cartridges//cartridge/scripts/hooks.json` (template: `hooks.json.tmpl` - adjust for domain) - **Use explicit script paths, never return undefined from hooks (always return dw.system.Status)** +- Hook script (template: `hook-script.js.tmpl`) - **Use `require()` not `importPackage()` for module loading** +- Service wrapper (template: `service-wrapper.js.tmpl`) +- Helper and test files (inline templates in Step 4 reference below) +- **Both install and uninstall:** `impex/install/services.xml` and `impex/uninstall/services.xml` (templates: `services-install.xml.tmpl`, `services-uninstall.xml.tmpl`) - **Dual IMPEX structure ensures safe merchant lifecycle management and proper cleanup on app removal** + +For site preferences, invoke `/generate-site-preferences-impex` skill. + +**UI/Fullstack apps (Storefront Next Extension):** +- `storefront-next/src/extensions//target-config.json` - Component registration with targetId +- `storefront-next/src/extensions//index.ts` - Barrel file exports +- TypeScript components (`.tsx`) with prop interfaces and i18n support +- **All three locales:** `locales/en-US/translations.json`, `locales/en-GB/translations.json`, `locales/it-IT/translations.json` - Internationalization (must use useTranslation, not hardcoded strings) +- Test files (`.test.tsx`) for component testing (vi.mock MUST be outside describe/it blocks) + +**Important:** All storefront files must use TypeScript (.ts/.tsx), not JavaScript. The extension system requires: +- Proper type annotations and interfaces +- Components and providers MUST use default export (extension system uses dynamic imports) +- Use `import type` for ALL types/interfaces (React types, custom types); regular `import` only for runtime values +- Context providers registered in target-config.json (not inline wrapping) +- Unit tests (.test.tsx) for coverage enforcement +- Always use `useTranslation()` - never hardcode English strings; namespace uses ext + PascalCase (e.g., `useTranslation('extProductReviews')`), JSON root key uses camelCase (e.g., `"productReviews"`) +- **Generate all three locales:** en-US, en-GB, it-IT with identical key structures +- **Configuration:** Use `useConfig()` with direct property access (`appConfig.extension?.appName?.key || defaultValue`), NEVER use `.get()` method. PUBLIC__ env vars with double underscores (e.g., `PUBLIC__app__extension__appName__apiKey`) +- **Follow Storefront Next ESLint and Prettier rules:** semicolons, single quotes, 4-space indentation, trailing commas (ES5), parentheses around arrow params, bracket spacing, JSX bracket same line, no hardcoded Tailwind colors, no duplicate imports, no array index as React key, consistent type imports, no console statements, printWidth 120, useCallback formatting (see references/storefront-plugin-templates.md for complete config) +- **Use 4-space indentation** for all TypeScript, JSX, and JSON files (1 level = 4 spaces) +- Verify target IDs exist before using (grep for UITarget in codebase or check the complete target ID reference) + +**Critical Exclusions (DO NOT generate):** +- ❌ No Tailwind config files (Storefront Next uses `@theme inline` with CSS 4) +- ❌ No hardcoded Salesforce version numbers in dependencies +- ❌ No direct color/spacing values in components (use theme variables) +- ❌ No `importPackage()` in hook implementations (use `require()`) + +See `references/storefront-plugin-templates.md` for complete extension templates. + +### 5. Domain-Specific Hooks + +Configure hooks.json based on domain: +- **Tax:** `app.tax.calculate`, `app.tax.commit`, `app.tax.cancel` +- **Payment:** `app.payment.processor.` +- **Shipping:** `app.shipping.calculate` +- **Loyalty:** `app.loyalty.calculate`, `app.loyalty.points` +- **Gift Cards:** `app.payment.processor.`, `app.giftcard.balance` +- **Ratings/Reviews:** `app.data.enrich` + +### 6. Validate and Guide + +Check: +- [ ] All required directories exist +- [ ] commerce-app.json has correct version and metadata +- [ ] README created +- [ ] **app-configuration/tasksList.json created** with merchant post-installation tasks +- [ ] Backend apps: cartridge files, hooks.json (with explicit script paths), **both install/ and uninstall/ impex directories** +- [ ] Backend apps: package.json includes `"hooks": "cartridge/scripts/hooks.json"` field +- [ ] Backend/Fullstack apps: every cartridge root (`cartridges/site_cartridges//`, `cartridges/bm_cartridges/bm_/`) has a `.project` file (empty is fine) +- [ ] Backend apps: Hook implementations use `require()` not `importPackage()`, always return dw.system.Status +- [ ] UI apps: storefront-next structure with target-config.json, TypeScript components, tests +- [ ] UI apps: index.ts barrel file, **all three locale files** (en-US, en-GB, it-IT), i18n usage with useTranslation +- [ ] UI apps: Configuration uses `useConfig()` with **direct property access** (never `.get()` method), PUBLIC__ env vars +- [ ] UI apps: Verify target IDs exist in codebase (check Complete Target ID Reference) +- [ ] UI apps: ESLint and Prettier compliance (semicolons, single quotes, 4-space indent, trailing commas ES5, parentheses around arrow params, bracket spacing, JSX bracket same line, no duplicate imports, no array index keys, import type, no hardcoded colors, no console) +- [ ] UI apps: **No Tailwind config files, no hardcoded theme values** +- [ ] .gitignore updated to exclude `**/commerce-*-app-*/` + +Provide next steps: + +``` +✅ App structure created at: //commerce--app-v/ + +Next steps: +1. **Review and customize app-configuration/tasksList.json** - update tasks to match your implementation +2. Customize generated files for your use case +3. {UI: Implement components | Backend: Implement hooks/helpers | Fullstack: Implement both} +4. {Backend/Fullstack: Update service credentials and test with SFCC} +5. Write tests +6. **Add app icon to icons/ directory** (PNG 512x512px recommended). Icon filename becomes the `iconName` in root manifest (e.g., `icons/avalara.png` → `"iconName": "avalara.png"`) +7. Use /package-app when ready +8. Use /validate-app before submission +9. Delete extracted directory before committing (commit only the ZIP) + +⚠️ Only commit: -v.zip, catalog.json (if new), and update commerce-apps-manifest/manifest.json + +Get started: cd //commerce--app-v +{Backend/Fullstack: cd cartridges/site_cartridges/ && npm install} + +📚 Related skills for implementation guidance: +{UI/Fullstack: - Check references/storefront-plugin-templates.md for complete UI patterns and ESLint rules} +{Backend/Fullstack: - Use /generate-service-impex for additional service configurations} +{Backend/Fullstack: - Use /generate-site-preferences-impex for configuration options} +{Backend/Fullstack: - Use /generate-custom-object-impex for data storage needs} +{All: - Use /validate-impex to check XML files before importing} +``` + +## Best Practices + +- Use templates from `assets/templates/` - they include proper structure and error handling +- **Multi-target approach:** Commerce apps typically span multiple UI targets, not single components. Ask about all needed targets (e.g., checkout flow + order summary + header) and generate all component shells together. +- **Task list and icons:** Always generate `app-configuration/tasksList.json` with merchant-facing post-installation tasks (credential setup, testing, verification). Remind vendors to customize the task list for their app and **add app icon to icons/ directory before submission** (PNG, 512x512px recommended). +- **UI-only apps:** Use TypeScript (.tsx) for all components with proper type annotations. Focus on component reusability with clear prop interfaces. Must include tests (.test.tsx) for coverage enforcement. Always use `useTranslation()` for i18n - never hardcode strings. **Generate all three locales** (en-US, en-GB, it-IT) with identical key structures. Configuration uses `useConfig()` with **direct property access** (`appConfig.extension?.appName?.key || defaultValue`), never `.get()` method. PUBLIC__ env vars follow double underscore convention. **Follow Prettier and ESLint rules:** 4-space indentation, trailing commas, parentheses around arrow params, single quotes, consistent type imports, no duplicate imports, no array index keys, no hardcoded Tailwind colors, no console statements, useCallback proper indentation. **Never generate Tailwind config files** - use `@theme inline`. +- **Storefront extension system:** Register components via target-config.json using `targetId`, `path`, `order` fields. Context providers go in `contextProviders` array, not inline wrapping. Locales use `locales/{locale}/translations.json` structure. **Always verify targetId exists** using the Complete Target ID Reference in storefront-plugin-templates.md - non-existent targets cause components to never render. +- **Backend apps:** Need comprehensive error handling and logging for production debugging. **Hook implementations must use `require()` not `importPackage()`**, always return `dw.system.Status` (never undefined). **package.json must include `"hooks": "cartridge/scripts/hooks.json"` field.** Generate **both install/ and uninstall/ impex directories** for safe merchant lifecycle management. +- **Fullstack apps:** Maintain separation - UI in storefront-next/, business logic in cartridges/ +- **Naming conventions:** Cartridge names: `int__` (max 50 characters), Service IDs: dotted notation +- **Context capture:** Document API details, auth methods, special requirements for future reference diff --git a/packages/b2c-dx-mcp/vendor/cap-dev/skills/scaffold-app/references/storefront-plugin-templates.md b/packages/b2c-dx-mcp/vendor/cap-dev/skills/scaffold-app/references/storefront-plugin-templates.md new file mode 100644 index 000000000..f9b6dea7c --- /dev/null +++ b/packages/b2c-dx-mcp/vendor/cap-dev/skills/scaffold-app/references/storefront-plugin-templates.md @@ -0,0 +1,1186 @@ +# Storefront Next Extension Templates + +Complete templates for the extension system. All files must use TypeScript (.ts/.tsx). + +**⚠️ IMPORTANT:** Extensions inherit TypeScript configuration from the parent Storefront Next application. **Do NOT create tsconfig.json at the extension level** - it's unnecessary and can cause configuration conflicts. + +## Target Configuration + +**File:** `storefront-next/src/extensions/{{appName}}/target-config.json` + +```json +{ + "components": [ + { + "targetId": "sfcc.header.before.cart", + "path": "extensions/{{appName}}/components/{{ComponentName}}.tsx", + "order": 0 + } + ], + "contextProviders": [ + { + "path": "extensions/{{appName}}/providers/{{AppName}}Provider.tsx", + "order": 0 + } + ], + "actionHooks": [ + { + "hookId": "sfcc.checkout.fraud.afterSubmitContactInfo", + "handler": "extensions/{{appName}}/hooks/{{hookName}}.server.ts", + "order": 0 + } + ] +} +``` + +**Key fields:** +- `targetId`: UI target slot where component should be inserted — must include the `sfcc.` prefix (see "Complete Target ID Reference" below) +- `path`: Relative path from `src/` to the component file +- `order`: Insertion order when multiple components target the same slot (lower = earlier) +- `contextProviders`: Application-root level providers (injected after ComposeProviders) +- `actionHooks`: Server-side handlers that run during storefront actions (see "Action Hook Handler" below) +- `devOnly`: (optional) Set to `true` to exclude extension from production builds + +**⚠️ IMPORTANT:** Use `target-config.json` (not `plugin-config.json`) and `targetId` (not `pluginId`) + +## Finding Valid Target IDs + +All target IDs use the `sfcc.` prefix. To find valid target slots in the codebase: + +```bash +# Search for UITarget component usage +grep -r "UITarget" src/ --include="*.tsx" --include="*.ts" + +# Look for existing target-config.json files +find . -name "target-config.json" -exec cat {} \; +``` + +See the "Complete Target ID Reference" section below for the full list. **Always verify target IDs exist** before using them. Non-existent targets will cause components to never render. + +## Index Barrel File + +**File:** `storefront-next/src/extensions/{{appName}}/index.ts` + +```typescript +// Export all public components +export { default as {{ComponentName}} } from './components/{{ComponentName}}'; + +// Export hooks +export { use{{FeatureName}} } from './hooks/use{{FeatureName}}'; + +// Export types +export type { {{ComponentName}}Props } from './components/{{ComponentName}}'; + +// Export providers +export { {{AppName}}Provider, use{{AppName}}Context } from './providers/{{AppName}}Provider'; +``` + +**Why:** Provides clean import paths and explicit public API for the extension. + +**Import pattern from other files:** +```typescript +// Importing from the extension +import { ComponentName } from '@/extensions/appName'; // Component (runtime) +import type { ComponentNameProps } from '@/extensions/appName'; // Type (compile-time) +import { useFeatureName } from '@/extensions/appName'; // Hook (runtime) +import { AppNameProvider, useAppNameContext } from '@/extensions/appName'; // Provider (runtime) +``` + +**Rule:** Always use `import type` for types/interfaces. Use regular `import` for runtime values (functions, components). + +## TypeScript Component with i18n + +**File:** `storefront-next/src/extensions/{{appName}}/components/{{ComponentName}}.tsx` + +```typescript +import React, { type ReactElement } from 'react'; +import { useTranslation } from 'react-i18next'; + +export interface {{ComponentName}}Props { + /** + * Optional className for styling + */ + className?: string; + /** + * Additional data prop (adjust based on component needs) + */ + data?: unknown; +} + +/** + * {{ComponentName}} component for {{displayName}} + * + * @param props - Component props + * @returns React element + */ +export default function {{ComponentName}}({ className, data }: {{ComponentName}}Props): ReactElement { + const { t } = useTranslation('ext{{AppName}}'); + + return ( +
+

{t('{{appName}}.title')}

+

{t('{{appName}}.description')}

+ {/* TODO: Implement component logic */} +
+ ); +} +``` + +**⚠️ IMPORTANT:** Always use `useTranslation()` - never hardcode strings. The namespace should be `'ext{{AppName}}'` (ext + PascalCase) and the JSON root key should be `{{appName}}` (camelCase). + +**Important:** +- Always export a `Props` interface +- Include JSDoc comments for props +- Add `data-testid` for testing +- Use PascalCase for component names +- Export component as default (required for extension system dynamic imports) +- **Use `import type` for all TypeScript types** (ReactElement, ReactNode, custom interfaces) - only runtime values (functions, components) use regular import +- Ensure `useTranslation('ext{{AppName}}')` namespace uses ext + PascalCase, while JSON root key uses camelCase +- Follow ESLint recommended rules for code quality and consistency + +## Context Provider + +**File:** `storefront-next/src/extensions/{{appName}}/providers/{{AppName}}Provider.tsx` + +```typescript +import React, { createContext, useContext, type ReactNode, type ReactElement } from 'react'; + +interface {{AppName}}ContextType { + // Define context state and methods + isEnabled: boolean; + toggle: () => void; +} + +const {{AppName}}Context = createContext<{{AppName}}ContextType | undefined>(undefined); + +export interface {{AppName}}ProviderProps { + children: ReactNode; +} + +/** + * {{AppName}} context provider + * Register in target-config.json contextProviders, not inline wrapping + * MUST be default export for extension system dynamic imports + */ +export default function {{AppName}}Provider({ children }: {{AppName}}ProviderProps): ReactElement { + const [isEnabled, setIsEnabled] = React.useState(false); + + const value = { + isEnabled, + toggle: () => setIsEnabled(prev => !prev), + }; + + return ( + <{{AppName}}Context.Provider value={value}> + {children} + + ); +} + +/** + * Hook to use {{AppName}} context + * @throws Error if used outside {{AppName}}Provider + */ +export function use{{AppName}}Context(): {{AppName}}ContextType { + const context = useContext({{AppName}}Context); + if (context === undefined) { + throw new Error('use{{AppName}}Context must be used within {{AppName}}Provider'); + } + return context; +} +``` + +**Provider with configuration:** + +If your provider needs access to configuration (API keys, settings, etc.), use this pattern: + +```typescript +import React, { createContext, useContext, useState, useEffect, type ReactNode, type ReactElement } from 'react'; +import { useConfig } from '@salesforce/storefront-next-runtime/config'; + +interface AppConfig { + extension?: { + {{appName}}?: { + apiKey: string; + enabled: boolean; + }; + }; +} + +interface {{AppName}}Config { + apiKey: string; + enabled: boolean; +} + +interface {{AppName}}ContextType { + config: {{AppName}}Config; + isReady: boolean; +} + +const {{AppName}}Context = createContext<{{AppName}}ContextType | undefined>(undefined); + +export interface {{AppName}}ProviderProps { + children: ReactNode; +} + +export default function {{AppName}}Provider({ children }: {{AppName}}ProviderProps): ReactElement { + const appConfig = useConfig(); + const [config] = useState<{{AppName}}Config>({ + apiKey: appConfig.extension?.{{appName}}?.apiKey || '', + enabled: appConfig.extension?.{{appName}}?.enabled !== false, + }); + + const [isReady, setIsReady] = useState(false); + + useEffect(() => { + // Initialize provider with configuration + setIsReady(true); + }, []); + + const value = { + config, + isReady, + }; + + return ( + <{{AppName}}Context.Provider value={value}> + {children} + + ); +} + +export function use{{AppName}}Context(): {{AppName}}ContextType { + const context = useContext({{AppName}}Context); + if (context === undefined) { + throw new Error('use{{AppName}}Context must be used within {{AppName}}Provider'); + } + return context; +} +``` + +**Key points:** +- **Provider MUST be default export** for extension system dynamic imports +- Register providers in `target-config.json` under `contextProviders` +- Do NOT wrap components inline +- Hook is named export, provider is default export +- Include type safety with undefined check +- Use `import type` for TypeScript types to avoid Vite ESM/CJS interop issues +- Use `useConfig()` with TypeScript type for type-safe configuration access +- Access config with direct property access: `appConfig.extension?.{{appName}}?.key || defaultValue` + +## Injecting External SDK Scripts + +Context providers can render `