@fluentcommerce/ai-skills 0.8.2 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -29
- package/bin/cli.mjs +278 -10
- package/content/cli/skills/fluent-cli-mcp-cicd/SKILL.md +6 -3
- package/content/cli/skills/fluent-connect/SKILL.md +1 -1
- package/content/dev/skills/fluent-e2e-test/SKILL.md +3 -1
- package/content/dev/skills/fluent-event-api/SKILL.md +1 -0
- package/content/dev/skills/fluent-feature-explain/SKILL.md +1 -0
- package/content/dev/skills/fluent-feature-plan/SKILL.md +1 -0
- package/content/dev/skills/fluent-mystique-builder/SKILL.md +2 -3
- package/content/dev/skills/fluent-mystique-scaffold/SDK_REFERENCE.md +2 -2
- package/content/dev/skills/fluent-mystique-scaffold/TEMPLATES.md +1 -2
- package/content/dev/skills/fluent-mystique-sdk-reference/SKILL.md +2 -2
- package/content/dev/skills/fluent-pre-deploy-check/SKILL.md +25 -0
- package/content/dev/skills/fluent-sourcing/SKILL.md +4 -0
- package/content/dev/skills/fluent-test-data/SKILL.md +4 -0
- package/content/dev/skills/fluent-trace/SKILL.md +16 -1
- package/content/dev/skills/fluent-workflow-builder/SKILL.md +11 -1
- package/content/dev/skills/fluent-workflow-deploy/SKILL.md +27 -0
- package/content/knowledge/index.md +2 -0
- package/content/knowledge/platform/create-order-reference.md +797 -0
- package/content/knowledge/platform/domain-model.md +1 -1
- package/content/knowledge/platform/workflow-design.md +18 -0
- package/content/mcp-extn/skills/fluent-mcp-core/SKILL.md +1 -1
- package/content/mcp-extn/skills/fluent-mcp-tools/SKILL.md +1 -1
- package/docs/dev-workflow.md +5 -2
- package/docs/fluent-ai-skills-reference.md +2 -2
- package/docs/getting-started.md +2 -2
- package/docs/use-cases.md +1 -1
- package/docs/workflow-reference.md +4 -2
- package/metadata.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,8 +23,9 @@ Teach your AI assistant to work with [Fluent Commerce](https://fluentcommerce.co
|
|
|
23
23
|
## Quick Start (copy-paste)
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
# 1. Install
|
|
27
|
-
|
|
26
|
+
# 1. Install prerequisites (skip if already installed)
|
|
27
|
+
# Fluent CLI: https://docs.fluentcommerce.com/building-blocks/fluent-cli-package
|
|
28
|
+
npm install -g @anthropic-ai/claude-code
|
|
28
29
|
|
|
29
30
|
# 2. Create a Fluent CLI profile (get values from your Fluent account team)
|
|
30
31
|
fluent profile create MY_PROFILE \
|
|
@@ -178,7 +179,7 @@ See all 27 scenarios with exact prompts: [docs/use-cases.md](docs/use-cases.md)
|
|
|
178
179
|
| Requirement | How to install | Verify |
|
|
179
180
|
|---|---|---|
|
|
180
181
|
| **Node.js 20+** | [nodejs.org](https://nodejs.org) | `node --version` |
|
|
181
|
-
| **Fluent CLI 2.0+** |
|
|
182
|
+
| **Fluent CLI 2.0+** | [Install guide](https://docs.fluentcommerce.com/building-blocks/fluent-cli-package) | `fluent --version` |
|
|
182
183
|
| **Claude Code** | `npm install -g @anthropic-ai/claude-code` | `claude --version` |
|
|
183
184
|
| **A Fluent Commerce account** | Contact your Fluent account team | You'll need the 5 values below |
|
|
184
185
|
|
|
@@ -274,19 +275,37 @@ my-fluent-workspace/
|
|
|
274
275
|
| **Local** (`.agents/skills`) | Fluent Codex skills for this workspace only (`--target codex --scope project`) | No — one per workspace |
|
|
275
276
|
| **Local** (this folder) | `.mcp.json` — MCP server config pointing to your Fluent account | No — one per workspace |
|
|
276
277
|
| **Local** (this folder) | `knowledge/` — platform knowledge (domain model, SDK patterns, rule contracts) | No — managed by installer, refreshed on reinstall |
|
|
277
|
-
| **
|
|
278
|
+
| **Local** (this folder) | `CLAUDE.md` — starter workspace instructions (auto-generated, safe to edit; [details](#claudemd-workspace-instructions)) | No — one per workspace |
|
|
278
279
|
| **Local** (this folder) | `accounts/` — workflows, features, source code (created in Step 3) | No — one per workspace |
|
|
279
280
|
|
|
280
281
|
You can have multiple workspaces (e.g., one per client) each with different profiles and retailers. Skills are shared; everything else is workspace-specific.
|
|
281
282
|
|
|
282
283
|
### Verify the installation
|
|
283
284
|
|
|
285
|
+
**Run `doctor` — it checks everything in one shot:**
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
npx @fluentcommerce/ai-skills doctor
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
`doctor` validates: Node.js version, Fluent CLI installed, Claude Code installed, skills installed, `.mcp.json` present with correct server config, `knowledge/` docs present, Fluent CLI profile exists and can authenticate, and MCP extension reachable. Fix anything it flags before proceeding.
|
|
292
|
+
|
|
293
|
+
**Quick status check (skills only):**
|
|
294
|
+
|
|
284
295
|
```bash
|
|
285
296
|
npx @fluentcommerce/ai-skills status
|
|
286
297
|
```
|
|
287
298
|
|
|
288
299
|
Shows which skill groups are installed and their install method (marketplace or file-copy). If something is missing, re-run `npx @fluentcommerce/ai-skills install --profile MY_PROFILE --profile-retailer "My Retailer"`.
|
|
289
300
|
|
|
301
|
+
**If you need to wire MCP separately** (e.g., changed profile, new workspace, or skipped `--profile` during install):
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
npx @fluentcommerce/ai-skills mcp-setup --profile MY_PROFILE
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
This generates `.mcp.json` in the current folder pointing to your Fluent account. Without it, the AI has no live API access.
|
|
308
|
+
|
|
290
309
|
To verify MCP servers are actually **reachable** (run inside Claude Code chat, not in terminal):
|
|
291
310
|
```
|
|
292
311
|
"Test my MCP connection" → AI calls health_ping, confirms live API access
|
|
@@ -316,48 +335,54 @@ This creates the full `accounts/` directory tree, downloads all workflows from y
|
|
|
316
335
|
|
|
317
336
|
#### Workspace directory layout
|
|
318
337
|
|
|
338
|
+
Legend: **[auto]** = created by CLI/skills, **[you]** = you create/populate, **[ai]** = AI generates during sessions
|
|
339
|
+
|
|
319
340
|
```
|
|
320
341
|
<project-root>/ <- any directory where you run the installer
|
|
321
|
-
+-- .mcp.json
|
|
322
|
-
+--
|
|
342
|
+
+-- .mcp.json [auto] MCP server config (generated by install/mcp-setup)
|
|
343
|
+
+-- CLAUDE.md [auto] Starter workspace instructions (auto-generated, safe to edit)
|
|
344
|
+
+-- knowledge/ [auto] Platform knowledge docs — copied from package on install
|
|
345
|
+
| (domain model, SDK patterns, rule contracts, order patterns)
|
|
323
346
|
+-- accounts/
|
|
324
|
-
+-- MY_PROFILE/
|
|
347
|
+
+-- MY_PROFILE/ [auto] Created by /fluent-connect or install --profile
|
|
325
348
|
|
|
|
326
|
-
+-- SOURCE/
|
|
327
|
-
| +-- backend/
|
|
328
|
-
| | +-- fc-plugin-custom/
|
|
349
|
+
+-- SOURCE/ [you] YOUR implementation source code
|
|
350
|
+
| +-- backend/ [you] Clone or copy your Java plugin repos here
|
|
351
|
+
| | +-- fc-plugin-custom/ <- your repo (git clone or cp)
|
|
329
352
|
| | | +-- pom.xml
|
|
330
353
|
| | | +-- resources/module.json
|
|
331
354
|
| | | +-- src/main/java/...
|
|
332
|
-
| | +-- .decompiled/
|
|
355
|
+
| | +-- .decompiled/ [auto] Auto-generated from deployed JARs by /fluent-connect
|
|
333
356
|
| |
|
|
334
|
-
| +-- frontend/
|
|
335
|
-
| +-- mystique-appeasement/
|
|
357
|
+
| +-- frontend/ [you] Clone or copy your Mystique SDK component projects here
|
|
358
|
+
| +-- mystique-appeasement/ <- your repo
|
|
336
359
|
| +-- package.json
|
|
337
360
|
| +-- src/index.tsx
|
|
338
361
|
|
|
|
339
|
-
+-- knowledge/
|
|
362
|
+
+-- knowledge/ [you] Account-specific conventions (via /fluent-knowledge-init)
|
|
340
363
|
| +-- naming-conventions.md
|
|
341
364
|
| +-- coding-standards.md
|
|
342
365
|
| +-- client/
|
|
343
366
|
|
|
|
344
|
-
+-- workflows/
|
|
345
|
-
| +-- My Retailer/
|
|
346
|
-
| +-- ORDER__HD.json
|
|
367
|
+
+-- workflows/ [auto] Downloaded from Fluent by /fluent-connect
|
|
368
|
+
| +-- My Retailer/
|
|
369
|
+
| +-- ORDER__HD.json <- live workflow JSON from your account
|
|
347
370
|
| +-- workflow-context.json
|
|
348
371
|
|
|
|
349
|
-
+-- features/
|
|
372
|
+
+-- features/ [ai] Created by AI during feature development
|
|
350
373
|
| +-- return-order/
|
|
351
|
-
| +-- spec.md
|
|
352
|
-
| +-- plan.md
|
|
353
|
-
| +-- architecture.md
|
|
354
|
-
| +-- status.json
|
|
355
|
-
| +-- assets/
|
|
374
|
+
| +-- spec.md <- from /fluent-use-case-discover
|
|
375
|
+
| +-- plan.md <- from /fluent-feature-plan
|
|
376
|
+
| +-- architecture.md <- from /fluent-feature-explain
|
|
377
|
+
| +-- status.json <- lifecycle tracker (auto-updated)
|
|
378
|
+
| +-- assets/ <- screenshots, recordings, evidence
|
|
356
379
|
|
|
|
357
|
-
+--
|
|
358
|
-
+--
|
|
359
|
-
+--
|
|
360
|
-
+--
|
|
380
|
+
+-- memory/ [ai] Auto-accumulated learnings from your sessions
|
|
381
|
+
+-- feedback/ [ai] Skill execution feedback (success/failure patterns)
|
|
382
|
+
+-- reports/ [ai] Ephemeral: build/, pre-deploy/, e2e-test/
|
|
383
|
+
+-- analysis/ [ai] Persistent: code/, modules/, topology/
|
|
384
|
+
+-- tasks/ [ai] Operational plans (non-feature work)
|
|
385
|
+
+-- sessions/ [ai] Audit trail exports
|
|
361
386
|
```
|
|
362
387
|
|
|
363
388
|
#### Where to put your code
|
|
@@ -539,7 +564,7 @@ For server-by-server MCP details, auth notes, and optional hosting providers, se
|
|
|
539
564
|
|
|
540
565
|
| Symptom | Fix |
|
|
541
566
|
|---|---|
|
|
542
|
-
| "Fluent CLI not found" |
|
|
567
|
+
| "Fluent CLI not found" | Install from [docs.fluentcommerce.com](https://docs.fluentcommerce.com/building-blocks/fluent-cli-package) then `fluent --version` |
|
|
543
568
|
| "Profile directory not found" | `fluent profile create MY_PROFILE --id ... --username ... --password ... --client-secret ... --base-url ...` |
|
|
544
569
|
| `.mcp.json` not created | `npx @fluentcommerce/ai-skills mcp-setup --profile MY_PROFILE` |
|
|
545
570
|
| MCP tools return connection errors | Restart IDE, then `fluent profile retailers MY_PROFILE` to verify connectivity |
|
|
@@ -596,6 +621,31 @@ Just work normally # AI captures corrections progressively into
|
|
|
596
621
|
|
|
597
622
|
**Full guide with format specs, loading chains, and examples:** [Data Architecture](content/knowledge/DATA-ARCHITECTURE.md) | [Knowledge Guidelines](content/knowledge/GUIDELINES.md)
|
|
598
623
|
|
|
624
|
+
### CLAUDE.md — Workspace Instructions
|
|
625
|
+
|
|
626
|
+
The installer auto-generates a starter `CLAUDE.md` in your workspace root. Claude Code reads it automatically at the start of every session. It includes:
|
|
627
|
+
|
|
628
|
+
- **Account context** — profile and retailer (pre-filled if you used `--profile`)
|
|
629
|
+
- **First steps** — doctor, connect, explore
|
|
630
|
+
- **SDLC skill map** — which skills to use at each stage (setup → discover → plan → build → deploy → test → diagnose → audit)
|
|
631
|
+
- **Quick actions** — common prompts and slash commands
|
|
632
|
+
- **Knowledge pointers** — where platform and account-specific knowledge lives
|
|
633
|
+
- **Conventions placeholder** — add your team-specific rules here
|
|
634
|
+
|
|
635
|
+
**The installer never overwrites an existing CLAUDE.md** — so once generated, it's yours to customize.
|
|
636
|
+
|
|
637
|
+
**What to add:**
|
|
638
|
+
|
|
639
|
+
```markdown
|
|
640
|
+
## Conventions
|
|
641
|
+
- Order refs: ORD-{storeCode}-{seq}
|
|
642
|
+
- All custom rules use prefix `com.client.`
|
|
643
|
+
- Workflow subtypes: HD, CC, SFS (no custom types)
|
|
644
|
+
- Always use MCP tools for GraphQL — never hardcode queries
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
**What NOT to put in it:** Don't duplicate what's already in `knowledge/` or skills. CLAUDE.md is for workspace-level overrides and team preferences.
|
|
648
|
+
|
|
599
649
|
---
|
|
600
650
|
|
|
601
651
|
## Further Reading
|
|
@@ -621,7 +671,7 @@ Just work normally # AI captures corrections progressively into
|
|
|
621
671
|
| Package | Purpose |
|
|
622
672
|
|---|---|
|
|
623
673
|
| [`@fluentcommerce/fluent-mcp-extn`](https://www.npmjs.com/package/@fluentcommerce/fluent-mcp-extn) | MCP extension server — 45 tools for live API access (events, batch, metrics, settings, entities, workflows, cache) |
|
|
624
|
-
| Fluent CLI
|
|
674
|
+
| [Fluent CLI](https://docs.fluentcommerce.com/building-blocks/fluent-cli-package) | Official CLI + built-in MCP server. See [install guide](https://docs.fluentcommerce.com/building-blocks/fluent-cli-package) |
|
|
625
675
|
| [`chrome-devtools-mcp`](https://www.npmjs.com/package/chrome-devtools-mcp) | Browser automation — auto-configured for `/fluent-ui-test`, `/fluent-ui-record`, and `/fluent-mystique-preview` |
|
|
626
676
|
|
|
627
677
|
---
|
package/bin/cli.mjs
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
writeFileSync,
|
|
11
11
|
} from "node:fs";
|
|
12
12
|
import { spawnSync } from "node:child_process";
|
|
13
|
-
import { join, dirname, basename, isAbsolute } from "node:path";
|
|
13
|
+
import { join, dirname, basename, isAbsolute, resolve } from "node:path";
|
|
14
14
|
import { homedir } from "node:os";
|
|
15
15
|
import { fileURLToPath } from "node:url";
|
|
16
16
|
|
|
@@ -975,6 +975,106 @@ function installKnowledge() {
|
|
|
975
975
|
return count;
|
|
976
976
|
}
|
|
977
977
|
|
|
978
|
+
/**
|
|
979
|
+
* Generate a starter CLAUDE.md in the workspace if one doesn't exist.
|
|
980
|
+
* Never overwrites — user's CLAUDE.md is always preserved.
|
|
981
|
+
*/
|
|
982
|
+
function generateStarterClaudeMd(profile, retailer) {
|
|
983
|
+
const dest = join(getProjectRoot(), "CLAUDE.md");
|
|
984
|
+
if (existsSync(dest)) return false; // never overwrite user's file
|
|
985
|
+
|
|
986
|
+
const profileLine = profile ? `- Profile: \`${profile}\`` : "- Profile: `YOUR_PROFILE` (update after creating a profile)";
|
|
987
|
+
const retailerLine = retailer ? `- Retailer: \`${retailer}\`` : "- Retailer: `YOUR_RETAILER` (update after selecting a retailer)";
|
|
988
|
+
const profileRef = profile || "MY_PROFILE";
|
|
989
|
+
const retailerRef = retailer || "My Retailer";
|
|
990
|
+
|
|
991
|
+
const content = `# CLAUDE.md — Fluent Commerce AI Skills Workspace
|
|
992
|
+
|
|
993
|
+
> Auto-generated by \`@fluentcommerce/ai-skills install\`. Safe to edit — the installer never overwrites this file.
|
|
994
|
+
|
|
995
|
+
## Account
|
|
996
|
+
|
|
997
|
+
${profileLine}
|
|
998
|
+
${retailerLine}
|
|
999
|
+
|
|
1000
|
+
## First Steps
|
|
1001
|
+
|
|
1002
|
+
1. **Verify setup:** run \`npx @fluentcommerce/ai-skills doctor\` in terminal — checks skills, MCP, knowledge, profiles
|
|
1003
|
+
2. **Connect to account:** type \`/fluent-connect\` as your first prompt — downloads workflows, scans source, wires workspace
|
|
1004
|
+
3. **Explore:** ask \`What can you do?\` or \`Show me the SDLC skill map\`
|
|
1005
|
+
|
|
1006
|
+
## Reference Docs
|
|
1007
|
+
|
|
1008
|
+
When the user asks about capabilities, available skills, "what can you do", or needs help choosing a skill:
|
|
1009
|
+
- Read \`knowledge/index.md\` for the knowledge file registry
|
|
1010
|
+
- The SDLC skill map below covers all 64 skills organized by lifecycle stage
|
|
1011
|
+
- For scenario-based examples with exact prompts and outcomes, see:
|
|
1012
|
+
https://bitbucket.org/fluentcommerce/fluent-ai-skills/src/main/docs/use-cases.md
|
|
1013
|
+
- For agent routing and skill invocation guide:
|
|
1014
|
+
https://bitbucket.org/fluentcommerce/fluent-ai-skills/src/main/docs/agents-and-skills-guide.md
|
|
1015
|
+
- All docs: https://bitbucket.org/fluentcommerce/fluent-ai-skills/src/main/docs/index.md
|
|
1016
|
+
|
|
1017
|
+
## MCP Tools
|
|
1018
|
+
|
|
1019
|
+
Configured in \`.mcp.json\` — use MCP tools for ALL live API operations:
|
|
1020
|
+
- **fluent-mcp** — Official Fluent CLI MCP (workflows, profiles, modules)
|
|
1021
|
+
- **fluent-mcp-extn** — Extension MCP with 45+ tools (GraphQL, events, batch, metrics, settings, entities)
|
|
1022
|
+
- **chrome-devtools** — Browser automation for UI testing and preview
|
|
1023
|
+
|
|
1024
|
+
Run \`/fluent-mcp-tools\` for the full tool reference.
|
|
1025
|
+
|
|
1026
|
+
## SDLC Skill Map
|
|
1027
|
+
|
|
1028
|
+
Follow this lifecycle. Each stage has purpose-built skills:
|
|
1029
|
+
|
|
1030
|
+
| Stage | Skills | When |
|
|
1031
|
+
|---|---|---|
|
|
1032
|
+
| **Setup** | \`/fluent-connect\`, \`/fluent-bootstrap\`, \`/fluent-profile\` | First-time workspace setup, account onboarding |
|
|
1033
|
+
| **Discover** | \`/fluent-implementation-map\`, \`/fluent-feature-explain\`, \`/fluent-workflow-analyzer\`, \`/fluent-mystique-analyze\` | Understand what exists before changing anything |
|
|
1034
|
+
| **Requirements** | \`/fluent-use-case-discover\` | Turn business needs into an approved spec |
|
|
1035
|
+
| **Plan** | \`/fluent-feature-phase\`, \`/fluent-feature-plan\` | Break specs into phases, produce implementation contract |
|
|
1036
|
+
| **Build (backend)** | \`/fluent-workflow-builder\`, \`/fluent-rule-scaffold\`, \`/fluent-module-scaffold\`, \`/fluent-settings\` | Workflows, rules, modules, settings |
|
|
1037
|
+
| **Build (frontend)** | \`/fluent-mystique-builder\`, \`/fluent-mystique-scaffold\`, \`/fluent-mystique-component\` | Manifests, SDK components, pages |
|
|
1038
|
+
| **Validate** | \`/fluent-pre-deploy-check\`, \`/fluent-module-validate\`, \`/fluent-mystique-validate\`, \`/fluent-build\` | Quality gates before deploy |
|
|
1039
|
+
| **Deploy** | \`/fluent-module-deploy\`, \`/fluent-workflow-deploy\` | Push changes to environment |
|
|
1040
|
+
| **Test** | \`/fluent-test-data\`, \`/fluent-e2e-test\`, \`/fluent-ui-test\`, \`/fluent-transition-api\` | Create test data, run E2E, verify UI |
|
|
1041
|
+
| **Diagnose** | \`/fluent-trace\`, \`/fluent-system-monitoring\`, \`/fluent-connection-analysis\`, \`/fluent-rollback\` | Debug failures, monitor health, roll back |
|
|
1042
|
+
| **Audit** | \`/fluent-rfl-assess\`, \`/fluent-session\`, \`/fluent-feature-status\` | Go-live readiness, audit trail, status dashboard |
|
|
1043
|
+
|
|
1044
|
+
## Quick Actions
|
|
1045
|
+
|
|
1046
|
+
| What you want | Say this |
|
|
1047
|
+
|---|---|
|
|
1048
|
+
| Connect to account | \`/fluent-connect --profile ${profileRef}\` |
|
|
1049
|
+
| What's deployed? | \`Map the implementation\` |
|
|
1050
|
+
| Build a feature | \`Help me define use cases for ...\` → \`Plan it\` → \`Build it\` |
|
|
1051
|
+
| Debug stuck order | \`Why is order HD-001 stuck?\` |
|
|
1052
|
+
| Create test data | \`Create a test HD order\` |
|
|
1053
|
+
| Build a workflow | \`Build an ORDER::RETURN workflow\` |
|
|
1054
|
+
| Edit a manifest | \`Add an appeasement form to the order page\` |
|
|
1055
|
+
| Scaffold a rule | \`Create a rule for ...\` |
|
|
1056
|
+
| Deploy | \`Deploy to staging\` |
|
|
1057
|
+
| Go-live audit | \`Run a Ready For Launch assessment\` |
|
|
1058
|
+
|
|
1059
|
+
## Knowledge
|
|
1060
|
+
|
|
1061
|
+
- \`knowledge/\` — Platform knowledge (domain model, SDK reference, rule contracts, order patterns). Managed by installer.
|
|
1062
|
+
- \`accounts/<PROFILE>/knowledge/\` — Account-specific conventions. Create via \`/fluent-knowledge-init\`.
|
|
1063
|
+
- \`accounts/<PROFILE>/memory/\` — Auto-accumulated learnings from your sessions.
|
|
1064
|
+
|
|
1065
|
+
## Conventions
|
|
1066
|
+
|
|
1067
|
+
<!-- Add your team-specific conventions below. Examples: -->
|
|
1068
|
+
<!-- - Order refs: ORD-{storeCode}-{seq} -->
|
|
1069
|
+
<!-- - All custom rules use prefix com.client. -->
|
|
1070
|
+
<!-- - Workflow subtypes: HD, CC, SFS (no custom types) -->
|
|
1071
|
+
<!-- - Always use MCP tools for GraphQL — never hardcode queries -->
|
|
1072
|
+
`;
|
|
1073
|
+
|
|
1074
|
+
writeFileSync(dest, content, "utf-8");
|
|
1075
|
+
return true;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
978
1078
|
function uninstallKnowledge() {
|
|
979
1079
|
const dest = join(getProjectRoot(), "knowledge");
|
|
980
1080
|
if (!existsSync(dest)) return false;
|
|
@@ -1297,7 +1397,7 @@ function runVerify(profile) {
|
|
|
1297
1397
|
if (fluentVer) {
|
|
1298
1398
|
pass("Fluent CLI", fluentVer);
|
|
1299
1399
|
} else {
|
|
1300
|
-
fail("Fluent CLI not found", "
|
|
1400
|
+
fail("Fluent CLI not found", "Install from https://docs.fluentcommerce.com/building-blocks/fluent-cli-package");
|
|
1301
1401
|
}
|
|
1302
1402
|
|
|
1303
1403
|
// 3. Claude Code
|
|
@@ -1452,7 +1552,7 @@ function runVerify(profile) {
|
|
|
1452
1552
|
if (existsSync(claudeMdPath)) {
|
|
1453
1553
|
pass("CLAUDE.md", "workspace instructions present");
|
|
1454
1554
|
} else {
|
|
1455
|
-
warn("CLAUDE.md not found", "
|
|
1555
|
+
warn("CLAUDE.md not found", "Re-run install to generate a starter, or create one manually");
|
|
1456
1556
|
}
|
|
1457
1557
|
|
|
1458
1558
|
// 8. Fluent CLI profile (if --profile provided or detected from MCP config)
|
|
@@ -1678,6 +1778,8 @@ function parseMcpSetupArgs(args) {
|
|
|
1678
1778
|
extnRepo: DEFAULT_MCP_EXTN_REPO,
|
|
1679
1779
|
profile: "",
|
|
1680
1780
|
profileRetailer: "",
|
|
1781
|
+
profilesFile: "",
|
|
1782
|
+
discoverProfiles: false,
|
|
1681
1783
|
officialServerName: "fluent-mcp",
|
|
1682
1784
|
extnServerName: "fluent-mcp-extn",
|
|
1683
1785
|
browserServerName: "chrome-devtools",
|
|
@@ -1765,6 +1867,15 @@ function parseMcpSetupArgs(args) {
|
|
|
1765
1867
|
case "--save-video":
|
|
1766
1868
|
options.saveVideo = args[++i] || "1920x1080";
|
|
1767
1869
|
break;
|
|
1870
|
+
case "--profiles-file":
|
|
1871
|
+
options.profilesFile = args[++i];
|
|
1872
|
+
if (!options.profilesFile) {
|
|
1873
|
+
throw new Error("Missing value for --profiles-file");
|
|
1874
|
+
}
|
|
1875
|
+
break;
|
|
1876
|
+
case "--discover-profiles":
|
|
1877
|
+
options.discoverProfiles = true;
|
|
1878
|
+
break;
|
|
1768
1879
|
default:
|
|
1769
1880
|
throw new Error(`Unknown option for mcp-setup: ${arg}`);
|
|
1770
1881
|
}
|
|
@@ -1774,9 +1885,80 @@ function parseMcpSetupArgs(args) {
|
|
|
1774
1885
|
throw new Error("--profile-retailer requires --profile");
|
|
1775
1886
|
}
|
|
1776
1887
|
|
|
1888
|
+
if (options.discoverProfiles && options.profilesFile) {
|
|
1889
|
+
throw new Error("--discover-profiles and --profiles-file are mutually exclusive");
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1777
1892
|
return options;
|
|
1778
1893
|
}
|
|
1779
1894
|
|
|
1895
|
+
/**
|
|
1896
|
+
* Scan ~/.fluentcommerce/ for CLI profile directories and their retailer overrides.
|
|
1897
|
+
* Returns an array of { profile, retailer? } entries suitable for fluent-profiles.json.
|
|
1898
|
+
*/
|
|
1899
|
+
function discoverFluentProfiles() {
|
|
1900
|
+
const fluentDir = join(homedir(), ".fluentcommerce");
|
|
1901
|
+
if (!existsSync(fluentDir)) {
|
|
1902
|
+
throw new Error(`No Fluent CLI profiles found: ${fluentDir} does not exist`);
|
|
1903
|
+
}
|
|
1904
|
+
|
|
1905
|
+
const entries = [];
|
|
1906
|
+
const dirs = readdirSync(fluentDir, { withFileTypes: true })
|
|
1907
|
+
.filter((d) => d.isDirectory() && !d.name.startsWith("."))
|
|
1908
|
+
.map((d) => d.name)
|
|
1909
|
+
.sort();
|
|
1910
|
+
|
|
1911
|
+
for (const dirName of dirs) {
|
|
1912
|
+
const profileJsonPath = join(fluentDir, dirName, "profile.json");
|
|
1913
|
+
if (!existsSync(profileJsonPath)) continue;
|
|
1914
|
+
|
|
1915
|
+
// Find retailer override files: retailer.<REF>.json
|
|
1916
|
+
const profileDir = join(fluentDir, dirName);
|
|
1917
|
+
const retailerFiles = readdirSync(profileDir)
|
|
1918
|
+
.filter((f) => f.startsWith("retailer.") && f.endsWith(".json") && !f.endsWith(".bak"))
|
|
1919
|
+
.sort();
|
|
1920
|
+
|
|
1921
|
+
if (retailerFiles.length === 0) {
|
|
1922
|
+
// Profile with no retailer overrides — add as profile-only entry
|
|
1923
|
+
entries.push({ profile: dirName });
|
|
1924
|
+
} else {
|
|
1925
|
+
for (const rf of retailerFiles) {
|
|
1926
|
+
// Extract retailer ref from filename: retailer.<REF>.json
|
|
1927
|
+
const ref = rf.slice("retailer.".length, -".json".length);
|
|
1928
|
+
if (ref) {
|
|
1929
|
+
entries.push({ profile: dirName, retailer: ref });
|
|
1930
|
+
}
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1935
|
+
if (entries.length === 0) {
|
|
1936
|
+
throw new Error(`No valid profiles found in ${fluentDir} (no profile.json files)`);
|
|
1937
|
+
}
|
|
1938
|
+
|
|
1939
|
+
return entries;
|
|
1940
|
+
}
|
|
1941
|
+
|
|
1942
|
+
/**
|
|
1943
|
+
* Read and validate a profiles JSON file. Returns the parsed array.
|
|
1944
|
+
*/
|
|
1945
|
+
function readProfilesFile(filePath) {
|
|
1946
|
+
const resolved = resolve(filePath);
|
|
1947
|
+
if (!existsSync(resolved)) {
|
|
1948
|
+
throw new Error(`Profiles file not found: ${resolved}`);
|
|
1949
|
+
}
|
|
1950
|
+
const parsed = JSON.parse(readFileSync(resolved, "utf-8"));
|
|
1951
|
+
if (!Array.isArray(parsed) || parsed.length === 0) {
|
|
1952
|
+
throw new Error(`Profiles file must be a non-empty JSON array: ${resolved}`);
|
|
1953
|
+
}
|
|
1954
|
+
for (const entry of parsed) {
|
|
1955
|
+
if (!entry.profile || typeof entry.profile !== "string") {
|
|
1956
|
+
throw new Error(`Each entry in profiles file must have a "profile" string: ${JSON.stringify(entry)}`);
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1959
|
+
return parsed;
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1780
1962
|
function buildManagedMcpConfigs(options, settings = {}) {
|
|
1781
1963
|
const codexGlobal = Boolean(settings.codexGlobal);
|
|
1782
1964
|
const startup_timeout_sec = codexGlobal ? 30.0 : undefined;
|
|
@@ -1826,6 +2008,14 @@ function buildManagedMcpConfigs(options, settings = {}) {
|
|
|
1826
2008
|
FLUENT_RETAILER_ID: "YOUR_RETAILER",
|
|
1827
2009
|
};
|
|
1828
2010
|
}
|
|
2011
|
+
// Multi-profile: wire profiles file into extn server for connection.list/switch
|
|
2012
|
+
if (options.resolvedProfilesFile) {
|
|
2013
|
+
extnDesired.env = {
|
|
2014
|
+
...extnDesired.env,
|
|
2015
|
+
FLUENT_PROFILES_FILE: options.resolvedProfilesFile,
|
|
2016
|
+
FLUENT_CACHE_ENABLED: "true",
|
|
2017
|
+
};
|
|
2018
|
+
}
|
|
1829
2019
|
|
|
1830
2020
|
let browserDesired = null;
|
|
1831
2021
|
if (!options.noBrowser) {
|
|
@@ -2030,6 +2220,41 @@ function setupMcp(options) {
|
|
|
2030
2220
|
// lands in the workspace root, not inside a sub-package that happens to
|
|
2031
2221
|
// have its own .git directory.
|
|
2032
2222
|
const projectRoot = getProjectRoot();
|
|
2223
|
+
|
|
2224
|
+
// --- Multi-profile: discover or validate profiles file ---
|
|
2225
|
+
if (options.discoverProfiles) {
|
|
2226
|
+
const profiles = discoverFluentProfiles();
|
|
2227
|
+
const profilesPath = join(projectRoot, "fluent-profiles.json");
|
|
2228
|
+
writeFileSync(profilesPath, `${JSON.stringify(profiles, null, 2)}\n`);
|
|
2229
|
+
logOk(`discovered ${profiles.length} profile/retailer entries → fluent-profiles.json`);
|
|
2230
|
+
options.resolvedProfilesFile = "./fluent-profiles.json";
|
|
2231
|
+
// Use first entry as default profile if --profile not explicitly provided
|
|
2232
|
+
if (!options.profile && profiles[0]) {
|
|
2233
|
+
options.profile = profiles[0].profile;
|
|
2234
|
+
if (profiles[0].retailer && !options.profileRetailer) {
|
|
2235
|
+
options.profileRetailer = profiles[0].retailer;
|
|
2236
|
+
}
|
|
2237
|
+
log(` Default profile: ${options.profile}${options.profileRetailer ? ` / ${options.profileRetailer}` : ""}`);
|
|
2238
|
+
}
|
|
2239
|
+
} else if (options.profilesFile) {
|
|
2240
|
+
const profiles = readProfilesFile(options.profilesFile);
|
|
2241
|
+
// Store relative path for .mcp.json (relative to project root)
|
|
2242
|
+
const absPath = resolve(options.profilesFile);
|
|
2243
|
+
const relPath = absPath.startsWith(projectRoot)
|
|
2244
|
+
? "./" + absPath.slice(projectRoot.length + 1).replace(/\\/g, "/")
|
|
2245
|
+
: absPath.replace(/\\/g, "/");
|
|
2246
|
+
options.resolvedProfilesFile = relPath;
|
|
2247
|
+
logOk(`validated profiles file: ${relPath} (${profiles.length} entries)`);
|
|
2248
|
+
// Use first entry as default profile if --profile not explicitly provided
|
|
2249
|
+
if (!options.profile && profiles[0]) {
|
|
2250
|
+
options.profile = profiles[0].profile;
|
|
2251
|
+
if (profiles[0].retailer && !options.profileRetailer) {
|
|
2252
|
+
options.profileRetailer = profiles[0].retailer;
|
|
2253
|
+
}
|
|
2254
|
+
log(` Default profile: ${options.profile}${options.profileRetailer ? ` / ${options.profileRetailer}` : ""}`);
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2257
|
+
|
|
2033
2258
|
const mcpConfigPath = join(projectRoot, ".mcp.json");
|
|
2034
2259
|
const mcpConfig = readJsonObjectOrDefault(mcpConfigPath, {});
|
|
2035
2260
|
|
|
@@ -2062,6 +2287,14 @@ function setupMcp(options) {
|
|
|
2062
2287
|
: {}),
|
|
2063
2288
|
};
|
|
2064
2289
|
}
|
|
2290
|
+
// Preserve profiles file env from buildManagedMcpConfigs
|
|
2291
|
+
if (options.resolvedProfilesFile) {
|
|
2292
|
+
extnMerged.env = {
|
|
2293
|
+
...(extnMerged.env || {}),
|
|
2294
|
+
FLUENT_PROFILES_FILE: options.resolvedProfilesFile,
|
|
2295
|
+
FLUENT_CACHE_ENABLED: "true",
|
|
2296
|
+
};
|
|
2297
|
+
}
|
|
2065
2298
|
stripSensitiveEnv(extnMerged);
|
|
2066
2299
|
|
|
2067
2300
|
mcpConfig.mcpServers[options.officialServerName] = officialMerged;
|
|
@@ -2098,8 +2331,11 @@ function setupMcp(options) {
|
|
|
2098
2331
|
log("");
|
|
2099
2332
|
log("MCP bootstrap complete.");
|
|
2100
2333
|
log(`Updated: ${mcpConfigPath}`);
|
|
2101
|
-
logOk(`official server: ${options.officialServerName}`);
|
|
2102
|
-
logOk(`extension server: ${options.extnServerName}`);
|
|
2334
|
+
logOk(`official server: ${options.officialServerName}${options.profile ? ` (profile: ${options.profile})` : ""}`);
|
|
2335
|
+
logOk(`extension server: ${options.extnServerName}${options.resolvedProfilesFile ? " (multi-profile)" : ""}`);
|
|
2336
|
+
if (options.resolvedProfilesFile) {
|
|
2337
|
+
logOk(`profiles file: ${options.resolvedProfilesFile} → connection.list / connection.switch`);
|
|
2338
|
+
}
|
|
2103
2339
|
if (!options.noBrowser) {
|
|
2104
2340
|
logOk(`chrome-devtools server: ${options.browserServerName} (for /fluent-ui-test, /fluent-ui-record)`);
|
|
2105
2341
|
if (options.saveVideo) {
|
|
@@ -2825,6 +3061,8 @@ GLOBAL OPTIONS
|
|
|
2825
3061
|
--scope <name> Codex scope: user (default) or project
|
|
2826
3062
|
--profile <name> Fluent CLI profile — auto-configures .mcp.json on install
|
|
2827
3063
|
--profile-retailer <ref> Retailer ref (requires --profile)
|
|
3064
|
+
--profiles-file <path> Path to fluent-profiles.json for multi-profile switching
|
|
3065
|
+
--discover-profiles Scan ~/.fluentcommerce/ and generate fluent-profiles.json
|
|
2828
3066
|
--install-mcp-extn npm install @fluentcommerce/fluent-mcp-extn locally (faster startup)
|
|
2829
3067
|
|
|
2830
3068
|
GROUPS
|
|
@@ -2840,6 +3078,9 @@ EXAMPLES
|
|
|
2840
3078
|
npx @fluentcommerce/ai-skills generate
|
|
2841
3079
|
npx @fluentcommerce/ai-skills mcp-setup --profile MYPROFILE
|
|
2842
3080
|
npx @fluentcommerce/ai-skills mcp-setup --profile MYPROFILE --profile-retailer MY_RETAILER
|
|
3081
|
+
npx @fluentcommerce/ai-skills mcp-setup --discover-profiles
|
|
3082
|
+
npx @fluentcommerce/ai-skills mcp-setup --profiles-file ./fluent-profiles.json
|
|
3083
|
+
npx @fluentcommerce/ai-skills mcp-setup --profile MYPROFILE --profiles-file ./fluent-profiles.json
|
|
2843
3084
|
npx @fluentcommerce/ai-skills mcp-setup --with-chrome
|
|
2844
3085
|
npx @fluentcommerce/ai-skills mcp-setup --install-extn-source
|
|
2845
3086
|
npx @fluentcommerce/ai-skills flow-run --profile MYPROFILE --retailer MY_RETAILER --module dist/module.zip
|
|
@@ -2854,6 +3095,8 @@ NOTES
|
|
|
2854
3095
|
- Use --save-video [resolution] to enable browser video recording via experimentalScreencast (default: 1920x1080).
|
|
2855
3096
|
- Chrome MCP Extension is opt-in for manual debugging with existing Chrome sessions. Use --with-chrome to add it alongside Chrome DevTools MCP. Requires Chrome extension from https://github.com/hangwin/mcp-chrome
|
|
2856
3097
|
- mcp-setup writes/merges .mcp.json in the project root and preserves existing servers.
|
|
3098
|
+
- Multi-profile: --discover-profiles scans ~/.fluentcommerce/ for CLI profiles and retailer overrides, generates fluent-profiles.json, and wires it into the extension server. Use --profiles-file to point to an existing file instead. The first entry becomes the default profile. Switch profiles at runtime via connection.list / connection.switch MCP tools.
|
|
3099
|
+
- When --profiles-file or --discover-profiles is combined with --profile, the explicit --profile takes precedence as the default (overriding the first-entry default).
|
|
2857
3100
|
- Aliases: mcp -> mcp-extn, mcp-core -> mcp-official.
|
|
2858
3101
|
|
|
2859
3102
|
ENVIRONMENT VARIABLES (optional overrides — profile-based auth is primary)
|
|
@@ -2884,6 +3127,8 @@ function parseArgs(argv) {
|
|
|
2884
3127
|
let scope = "user";
|
|
2885
3128
|
let profile = "";
|
|
2886
3129
|
let profileRetailer = "";
|
|
3130
|
+
let profilesFile = "";
|
|
3131
|
+
let discoverProfilesFlag = false;
|
|
2887
3132
|
const rest = [];
|
|
2888
3133
|
|
|
2889
3134
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -2917,6 +3162,14 @@ function parseArgs(argv) {
|
|
|
2917
3162
|
throw new Error("Missing value for --profile-retailer");
|
|
2918
3163
|
}
|
|
2919
3164
|
i++;
|
|
3165
|
+
} else if (argv[i] === "--profiles-file") {
|
|
3166
|
+
profilesFile = argv[i + 1] || "";
|
|
3167
|
+
if (!profilesFile) {
|
|
3168
|
+
throw new Error("Missing value for --profiles-file");
|
|
3169
|
+
}
|
|
3170
|
+
i++;
|
|
3171
|
+
} else if (argv[i] === "--discover-profiles") {
|
|
3172
|
+
discoverProfilesFlag = true;
|
|
2920
3173
|
} else {
|
|
2921
3174
|
rest.push(argv[i]);
|
|
2922
3175
|
}
|
|
@@ -2928,6 +3181,8 @@ function parseArgs(argv) {
|
|
|
2928
3181
|
scope: normalizeCodexScope(scope),
|
|
2929
3182
|
profile,
|
|
2930
3183
|
profileRetailer,
|
|
3184
|
+
profilesFile,
|
|
3185
|
+
discoverProfiles: discoverProfilesFlag,
|
|
2931
3186
|
command: rest[0],
|
|
2932
3187
|
commandArgs: rest.slice(1),
|
|
2933
3188
|
groupArgs: rest.slice(1).filter((v) => !v.startsWith("--")).map((v) => v.toLowerCase()),
|
|
@@ -2954,7 +3209,7 @@ function main() {
|
|
|
2954
3209
|
process.exit(1);
|
|
2955
3210
|
}
|
|
2956
3211
|
|
|
2957
|
-
const { projectRoot, target, scope, profile, profileRetailer, command, commandArgs, groupArgs } = parsed;
|
|
3212
|
+
const { projectRoot, target, scope, profile, profileRetailer, profilesFile, discoverProfiles, command, commandArgs, groupArgs } = parsed;
|
|
2958
3213
|
|
|
2959
3214
|
try {
|
|
2960
3215
|
setProjectRoot(resolveProjectRoot(projectRoot));
|
|
@@ -2981,18 +3236,25 @@ function main() {
|
|
|
2981
3236
|
logOk(`knowledge: ${knowledgeCount} file(s) → knowledge/`);
|
|
2982
3237
|
}
|
|
2983
3238
|
|
|
3239
|
+
// Generate starter CLAUDE.md if not present (never overwrites)
|
|
3240
|
+
if (generateStarterClaudeMd(profile, profileRetailer)) {
|
|
3241
|
+
logOk("CLAUDE.md: starter workspace instructions created");
|
|
3242
|
+
}
|
|
3243
|
+
|
|
2984
3244
|
log("");
|
|
2985
3245
|
log(`Done. Groups: ${selected.map((g) => g.name).join(", ")}`);
|
|
2986
3246
|
|
|
2987
|
-
// Auto-configure MCP when --profile is provided
|
|
2988
|
-
if (profile) {
|
|
3247
|
+
// Auto-configure MCP when --profile or --discover-profiles or --profiles-file is provided
|
|
3248
|
+
if (profile || discoverProfiles || profilesFile) {
|
|
2989
3249
|
log("");
|
|
2990
3250
|
log("Configuring MCP servers...");
|
|
2991
3251
|
log("==========================");
|
|
2992
3252
|
try {
|
|
2993
3253
|
const mcpOptions = parseMcpSetupArgs([
|
|
2994
|
-
"--profile", profile,
|
|
3254
|
+
...(profile ? ["--profile", profile] : []),
|
|
2995
3255
|
...(profileRetailer ? ["--profile-retailer", profileRetailer] : []),
|
|
3256
|
+
...(profilesFile ? ["--profiles-file", profilesFile] : []),
|
|
3257
|
+
...(discoverProfiles ? ["--discover-profiles"] : []),
|
|
2996
3258
|
]);
|
|
2997
3259
|
if (target === "codex" && scope === "user") {
|
|
2998
3260
|
setupCodexGlobalMcp(mcpOptions);
|
|
@@ -3061,7 +3323,7 @@ function main() {
|
|
|
3061
3323
|
case "mcp-setup":
|
|
3062
3324
|
case "setup-mcp":
|
|
3063
3325
|
case "init-mcp": {
|
|
3064
|
-
// Re-inject
|
|
3326
|
+
// Re-inject top-level args if not already in command-specific args
|
|
3065
3327
|
const mcpArgs = [...commandArgs];
|
|
3066
3328
|
if (profile && !mcpArgs.includes("--profile") && !mcpArgs.includes("-p")) {
|
|
3067
3329
|
mcpArgs.push("--profile", profile);
|
|
@@ -3069,6 +3331,12 @@ function main() {
|
|
|
3069
3331
|
if (profileRetailer && !mcpArgs.includes("--profile-retailer")) {
|
|
3070
3332
|
mcpArgs.push("--profile-retailer", profileRetailer);
|
|
3071
3333
|
}
|
|
3334
|
+
if (profilesFile && !mcpArgs.includes("--profiles-file")) {
|
|
3335
|
+
mcpArgs.push("--profiles-file", profilesFile);
|
|
3336
|
+
}
|
|
3337
|
+
if (discoverProfiles && !mcpArgs.includes("--discover-profiles")) {
|
|
3338
|
+
mcpArgs.push("--discover-profiles");
|
|
3339
|
+
}
|
|
3072
3340
|
const options = parseMcpSetupArgs(mcpArgs);
|
|
3073
3341
|
if (target === "codex" && scope === "user") {
|
|
3074
3342
|
setupCodexGlobalMcp(options);
|
|
@@ -97,7 +97,8 @@ jobs:
|
|
|
97
97
|
with: { node-version: 20 }
|
|
98
98
|
|
|
99
99
|
- name: Install Fluent CLI
|
|
100
|
-
|
|
100
|
+
# Install method: https://docs.fluentcommerce.com/building-blocks/fluent-cli-package
|
|
101
|
+
run: echo "Replace with your org's Fluent CLI install step"
|
|
101
102
|
|
|
102
103
|
- name: Create profile
|
|
103
104
|
run: |
|
|
@@ -134,7 +135,8 @@ fluent-deploy:
|
|
|
134
135
|
only:
|
|
135
136
|
changes: [plugins/**, resources/**]
|
|
136
137
|
before_script:
|
|
137
|
-
|
|
138
|
+
# Install method: https://docs.fluentcommerce.com/building-blocks/fluent-cli-package
|
|
139
|
+
- echo "Replace with your org's Fluent CLI install step"
|
|
138
140
|
- apt-get update && apt-get install -y maven
|
|
139
141
|
script:
|
|
140
142
|
- fluent profile create deploy-target --id $FLUENT_ACCOUNT_ID --base-url $FLUENT_BASE_URL --username $FLUENT_USERNAME --password $FLUENT_PASSWORD --client-secret $FLUENT_CLIENT_SECRET
|
|
@@ -167,7 +169,8 @@ jobs:
|
|
|
167
169
|
- uses: actions/checkout@v4
|
|
168
170
|
- uses: actions/setup-node@v4
|
|
169
171
|
with: { node-version: '20' }
|
|
170
|
-
|
|
172
|
+
# Install method: https://docs.fluentcommerce.com/building-blocks/fluent-cli-package
|
|
173
|
+
- run: echo "Replace with your org's Fluent CLI install step"
|
|
171
174
|
- name: Validate
|
|
172
175
|
run: fluent module validate --path ${{ github.workspace }}/modules/$MODULE_NAME
|
|
173
176
|
- name: Pre-deploy check
|