@fluentcommerce/ai-skills 0.13.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -12
- package/bin/cli.mjs +219 -43
- package/content/cli/skills/fluent-bootstrap/SKILL.md +1 -1
- package/content/cli/skills/fluent-cli-mcp-cicd/SKILL.md +1 -1
- package/content/cli/skills/fluent-cli-reference/SKILL.md +1 -1
- package/content/cli/skills/fluent-cli-retailer/SKILL.md +1 -1
- package/content/cli/skills/fluent-connect/SKILL.md +58 -3
- package/content/cli/skills/fluent-profile/SKILL.md +35 -5
- package/content/cli/skills/fluent-workflow/SKILL.md +2 -1
- package/content/dev/agents/fluent-backend-dev.md +2 -2
- package/content/dev/agents/fluent-dev.md +1 -1
- package/content/dev/agents/fluent-frontend-dev.md +1 -1
- package/content/dev/skills/fluent-account-snapshot/SKILL.md +1 -1
- package/content/dev/skills/fluent-archive/SKILL.md +2 -1
- package/content/dev/skills/fluent-build/SKILL.md +2 -2
- package/content/dev/skills/fluent-connection-analysis/SKILL.md +2 -1
- package/content/dev/skills/fluent-custom-code/SKILL.md +3 -2
- package/content/dev/skills/fluent-data-module-scaffold/SKILL.md +7 -6
- package/content/dev/skills/fluent-e2e-test/SKILL.md +1 -1
- package/content/dev/skills/fluent-entity-flow-diagnose/SKILL.md +2 -1
- package/content/dev/skills/fluent-event-api/SKILL.md +3 -2
- package/content/dev/skills/fluent-feature-explain/SKILL.md +2 -1
- package/content/dev/skills/fluent-feature-plan/SKILL.md +2 -1
- package/content/dev/skills/fluent-feature-status/SKILL.md +1 -1
- package/content/dev/skills/fluent-frontend-build/SKILL.md +1 -1
- package/content/dev/skills/fluent-frontend-readme/SKILL.md +2 -1
- package/content/dev/skills/fluent-frontend-review/SKILL.md +2 -1
- package/content/dev/skills/fluent-goal/SKILL.md +1 -1
- package/content/dev/skills/fluent-implementation-map/SKILL.md +1 -1
- package/content/dev/skills/fluent-inventory-catalog/SKILL.md +2 -2
- package/content/dev/skills/fluent-job-batch/SKILL.md +6 -3
- package/content/dev/skills/fluent-knowledge-init/SKILL.md +1 -1
- package/content/dev/skills/{fluent-source-onboard → fluent-module-convert}/SKILL.md +223 -24
- package/content/dev/skills/fluent-module-scaffold/SKILL.md +2 -1
- package/content/dev/skills/fluent-module-validate/SKILL.md +8 -7
- package/content/dev/skills/fluent-mystique-assess/SKILL.md +22 -6
- package/content/dev/skills/fluent-mystique-builder/SKILL.md +33 -2
- package/content/dev/skills/fluent-mystique-component/SKILL.md +1 -1
- package/content/dev/skills/fluent-mystique-diff/SKILL.md +1 -1
- package/content/dev/skills/fluent-mystique-preview/SKILL.md +19 -2
- package/content/dev/skills/fluent-mystique-scaffold/SDK_REFERENCE.md +2 -2
- package/content/dev/skills/fluent-mystique-scaffold/SKILL.md +13 -2
- package/content/dev/skills/fluent-mystique-scaffold/TEMPLATES.md +1 -1
- package/content/dev/skills/fluent-mystique-sdk-reference/SKILL.md +2 -1
- package/content/dev/skills/fluent-pre-deploy-check/SKILL.md +3 -3
- package/content/dev/skills/fluent-retailer-config/SKILL.md +3 -3
- package/content/dev/skills/fluent-rollback/SKILL.md +1 -1
- package/content/dev/skills/fluent-rule-lookup/SKILL.md +2 -1
- package/content/dev/skills/fluent-rule-scaffold/SKILL.md +7 -6
- package/content/dev/skills/fluent-rule-test/SKILL.md +2 -1
- package/content/dev/skills/fluent-scope-plan/SKILL.md +2 -2
- package/content/dev/skills/fluent-session/SKILL.md +1 -1
- package/content/dev/skills/fluent-settings/SKILL.md +2 -2
- package/content/dev/skills/fluent-skill-observability/SKILL.md +1 -1
- package/content/dev/skills/fluent-sourcing/SKILL.md +38 -13
- package/content/dev/skills/fluent-system-monitoring/SKILL.md +1 -1
- package/content/dev/skills/fluent-test-data/SKILL.md +1 -1
- package/content/dev/skills/fluent-trace/SKILL.md +3 -2
- package/content/dev/skills/fluent-transition-api/SKILL.md +3 -2
- package/content/dev/skills/fluent-ui-record/SKILL.md +1 -1
- package/content/dev/skills/fluent-ui-test/SKILL.md +9 -8
- package/content/dev/skills/fluent-use-case-discover/SKILL.md +2 -2
- package/content/dev/skills/fluent-workflow-analyzer/SKILL.md +3 -2
- package/content/dev/skills/fluent-workspace-tree/SKILL.md +4 -3
- package/content/knowledge/index.md +3 -3
- package/content/knowledge/platform/domain-model.md +1 -0
- package/content/knowledge/platform/module-structure.md +5 -5
- package/content/knowledge/platform/mystique-routing.md +6 -3
- package/content/knowledge/platform/permissions-and-contexts.md +2 -2
- package/content/knowledge/platform/rule-test-patterns.md +1 -1
- package/content/knowledge/platform/workflow-json-structure.md +1 -1
- package/content/mcp-extn/skills/fluent-mcp-core/SKILL.md +2 -1
- package/content/mcp-extn/skills/fluent-mcp-tools/SKILL.md +3 -2
- package/content/rfl/skills/fluent-rfl-assess/SKILL.md +1 -1
- package/docs/01-first-session.md +175 -0
- package/docs/02-prompt-guide.md +246 -0
- package/docs/03-use-cases.md +1181 -0
- package/docs/04-onboarding-plan.md +355 -0
- package/docs/05-getting-started.md +262 -0
- package/docs/06-dev-workflow.md +1040 -0
- package/docs/INDEX.md +40 -0
- package/docs/agents-and-skills-guide.md +199 -0
- package/docs/capability-map.md +165 -0
- package/docs/chrome-devtools-mcp-reference.md +401 -0
- package/docs/fluent-ai-skills-reference.md +1351 -0
- package/docs/manifest-safety.md +79 -0
- package/docs/mcp-servers.md +209 -0
- package/docs/workflow-reference.md +167 -0
- package/lib/fluent-brand.css +55 -0
- package/metadata.json +7 -6
- package/package.json +17 -3
- package/scripts/postinstall.mjs +38 -0
- package/{content/dev/skills/fluent-trace/scripts/analyze-event-capture.mjs → tools/event-capture-analyzer.mjs} +3 -3
- package/tools/{generate-feature-dashboard.mjs → feature-dashboard.mjs} +2 -2
- package/tools/manifest-diff.mjs +1 -1
- package/{content/dev/skills/fluent-mystique-assess/validator.mjs → tools/manifest-validator.mjs} +2 -2
- package/tools/workflow-explainer.mjs +1021 -0
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
> - **No warranty** — provided as-is for experimentation and internal evaluation only
|
|
13
13
|
> - **Do NOT use in production** without thorough review and explicit sign-off from your team
|
|
14
14
|
>
|
|
15
|
-
> Pin to an exact version (`@0.
|
|
15
|
+
> Pin to an exact version (`@0.13.0`) if you depend on current behavior.
|
|
16
16
|
|
|
17
17
|
Teach your AI assistant to work with [Fluent Commerce](https://fluentcommerce.com) (distributed order management) — analyze workflows, scaffold rules, debug events, build manifests, and deploy — all through natural language.
|
|
18
18
|
|
|
@@ -106,6 +106,9 @@ This downloads workflows, scans your account, and sets up the workspace. After t
|
|
|
106
106
|
>
|
|
107
107
|
> **How to verify:** `npx @fluentcommerce/ai-skills doctor` checks everything (skills, MCP, knowledge, docs, profile connectivity). `npx @fluentcommerce/ai-skills status` checks just the skill installation.
|
|
108
108
|
|
|
109
|
+
> [!IMPORTANT]
|
|
110
|
+
> **`knowledge/` and `docs/` are merge-safe.** The installer copies platform knowledge and reference docs into your workspace but **never deletes your own files**. Only files originally installed by the package are overwritten or removed on reinstall/uninstall. If you add custom notes, architecture docs, or team knowledge to these directories, they will be preserved across upgrades. A `.fluent-installed-files.json` manifest in each directory tracks which files are managed by the package.
|
|
111
|
+
|
|
109
112
|
---
|
|
110
113
|
|
|
111
114
|
## How It Works
|
|
@@ -382,7 +385,7 @@ You can have multiple workspaces (e.g., one per client) each with different prof
|
|
|
382
385
|
npx @fluentcommerce/ai-skills --version
|
|
383
386
|
```
|
|
384
387
|
|
|
385
|
-
This prints the exact package version `npx` resolves for this workspace, for example `fluent-ai-skills v0.
|
|
388
|
+
This prints the exact package version `npx` resolves for this workspace, for example `fluent-ai-skills v0.13.0`.
|
|
386
389
|
|
|
387
390
|
**Run `doctor` — it checks everything in one shot:**
|
|
388
391
|
|
|
@@ -390,7 +393,7 @@ This prints the exact package version `npx` resolves for this workspace, for exa
|
|
|
390
393
|
npx @fluentcommerce/ai-skills doctor
|
|
391
394
|
```
|
|
392
395
|
|
|
393
|
-
`doctor` validates: Node.js version, Fluent CLI installed, IDE detected (Claude Code, Codex, and/or Gemini CLI — warns if none found), skills installed, MCP config present with correct server config, local `knowledge/` and `docs/` present, workspace instruction files present, Fluent CLI profile exists and can authenticate, and MCP extension reachable. It also compares versions across four layers — running package, local knowledge, global knowledge (`~/.claude/fluent-knowledge/`), and npm registry — warning on any mismatches. Fix anything it flags before proceeding.
|
|
396
|
+
`doctor` validates: Node.js version, Fluent CLI installed, IDE detected (Claude Code, Codex, and/or Gemini CLI — warns if none found), skills installed, MCP config present with correct server config, local `knowledge/` and `docs/` present, workspace instruction files present, Fluent CLI profile exists and can authenticate, and MCP extension reachable. It also compares versions across four layers — running package, local knowledge, global knowledge (`~/.claude/fluent-knowledge/`), and npm registry — warning on any mismatches. Fix anything it flags before proceeding. Use `--fix` to auto-install the Fluent CLI if missing (requires Node >=20 and npm >=10.5).
|
|
394
397
|
|
|
395
398
|
**Quick status check (skills only):**
|
|
396
399
|
|
|
@@ -728,7 +731,7 @@ npx @fluentcommerce/ai-skills <command> [--profile <name>] [groups...]
|
|
|
728
731
|
| Command | Description |
|
|
729
732
|
|---|---|
|
|
730
733
|
| `install [groups...]` | Install skills + configure MCP (with `--profile`) |
|
|
731
|
-
| `doctor` | **Full setup health check** — Node, CLI, Claude Code, skills, MCP, profile, connectivity, versions |
|
|
734
|
+
| `doctor [--fix]` | **Full setup health check** — Node, CLI, Claude Code, skills, MCP, profile, connectivity, versions. `--fix` auto-installs Fluent CLI if missing |
|
|
732
735
|
| `status [groups...]` | Check what's installed |
|
|
733
736
|
| `uninstall [groups...]` | Remove installed skills (`--purge` also removes global knowledge) |
|
|
734
737
|
| `mcp-setup [options]` | Generate `.mcp.json` separately |
|
|
@@ -754,24 +757,26 @@ For server-by-server MCP details, auth notes, and optional hosting providers, se
|
|
|
754
757
|
|
|
755
758
|
## Eval Coverage
|
|
756
759
|
|
|
757
|
-
|
|
760
|
+
803 eval cases across 12 suites validate skill routing, execution quality, and knowledge grounding:
|
|
758
761
|
|
|
759
762
|
| Suite | Cases | What it tests |
|
|
760
763
|
|---|---:|---|
|
|
761
|
-
| Execution |
|
|
764
|
+
| Execution | 188 | All 63 skills produce correct output (plans, code, tool calls) |
|
|
762
765
|
| Routing | 115 | Prompt → skill selection accuracy (deterministic replay) |
|
|
763
|
-
| Routing-live |
|
|
764
|
-
| Knowledge-grounding |
|
|
766
|
+
| Routing-live | 175 | Live model routing against installed skills |
|
|
767
|
+
| Knowledge-grounding | 140 | Trap cases for common misconceptions and anti-patterns |
|
|
765
768
|
| Runtime-live | 54 | MCP tool integration (GraphQL, events, settings) |
|
|
766
769
|
| Skill-runtime | 51 | Skill execution contracts and output validation |
|
|
767
770
|
| Tool-behavior | 30 | Tool call contracts and argument validation |
|
|
768
|
-
| Chains |
|
|
769
|
-
| Adversarial |
|
|
771
|
+
| Chains | 19 | Multi-skill workflow execution sequences |
|
|
772
|
+
| Adversarial | 16 | Ambiguous, out-of-scope, and mixed-concern prompts |
|
|
770
773
|
| Agent-routing | 6 | Agent delegation accuracy (deterministic replay) |
|
|
771
774
|
| Agent-routing-live | 6 | Live model agent delegation |
|
|
772
775
|
| Runtime-live-sandbox | 3 | Sandbox-only profile context verification |
|
|
773
776
|
|
|
774
|
-
Run the test suites: `npm test` (
|
|
777
|
+
Run the test suites: `npm test` (smoke, pack, unit, and evals:core — replay-based eval cases included).
|
|
778
|
+
|
|
779
|
+
**Interactive prompt probing:** `npm run eval:playground` opens a browser UI at `http://localhost:3457` where you can type any prompt and see which skill gets picked, which knowledge docs are referenced, and the LLM's reasoning. Supports Claude Agent SDK (fastest — direct API, no subprocess), Claude Code CLI, and Codex executors. The SDK executor uses compact routing prompts (~4K tokens vs ~100K+), cost safety caps, and live SSE progress streaming. Requires `claude` or `codex` CLI to be installed and authenticated; the SDK executor inherits Bedrock SSO auth from environment variables.
|
|
775
780
|
|
|
776
781
|
---
|
|
777
782
|
|
|
@@ -779,7 +784,7 @@ Run the test suites: `npm test` (1,350 assertions across smoke, pack, and unit s
|
|
|
779
784
|
|
|
780
785
|
| Symptom | Fix |
|
|
781
786
|
|---|---|
|
|
782
|
-
| "Fluent CLI not found" |
|
|
787
|
+
| "Fluent CLI not found" | `npx @fluentcommerce/ai-skills doctor --fix` (auto-installs), or install manually from [docs.fluentcommerce.com](https://docs.fluentcommerce.com/building-blocks/fluent-cli-package) |
|
|
783
788
|
| "Profile directory not found" | `fluent profile create MY_PROFILE --id ... --username ... --password ... --client-secret ... --base-url ...` |
|
|
784
789
|
| `.mcp.json` not created | `npx @fluentcommerce/ai-skills mcp-setup --profile MY_PROFILE` |
|
|
785
790
|
| MCP tools return connection errors | Restart IDE, then `fluent profile retailers MY_PROFILE` to verify connectivity |
|
package/bin/cli.mjs
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
readFileSync,
|
|
10
10
|
writeFileSync,
|
|
11
11
|
statSync,
|
|
12
|
+
realpathSync,
|
|
12
13
|
} from "node:fs";
|
|
13
14
|
import { spawnSync } from "node:child_process";
|
|
14
15
|
import { join, dirname, basename, isAbsolute, resolve } from "node:path";
|
|
@@ -796,6 +797,159 @@ function removeEntry(path, type) {
|
|
|
796
797
|
}
|
|
797
798
|
}
|
|
798
799
|
|
|
800
|
+
// ---------------------------------------------------------------------------
|
|
801
|
+
// Merge-install: copy source files into a destination directory without
|
|
802
|
+
// removing client-added files. Tracks installed files in a manifest so
|
|
803
|
+
// uninstall and re-install can clean up precisely.
|
|
804
|
+
// ---------------------------------------------------------------------------
|
|
805
|
+
|
|
806
|
+
const DIR_MANIFEST_FILENAME = ".fluent-installed-files.json";
|
|
807
|
+
|
|
808
|
+
/**
|
|
809
|
+
* Recursively collect all relative file paths under `dir`.
|
|
810
|
+
*/
|
|
811
|
+
function collectRelativePaths(dir, base = dir) {
|
|
812
|
+
const paths = [];
|
|
813
|
+
if (!existsSync(dir)) return paths;
|
|
814
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
815
|
+
const full = join(dir, entry.name);
|
|
816
|
+
if (entry.isDirectory()) {
|
|
817
|
+
paths.push(...collectRelativePaths(full, base));
|
|
818
|
+
} else {
|
|
819
|
+
paths.push(full.slice(base.length + 1).replace(/\\/g, "/"));
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
return paths;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
/**
|
|
826
|
+
* Merge-install `src` into `dest`: copy every file from src (overwriting
|
|
827
|
+
* same-named files) but leave client-added files untouched. Writes a
|
|
828
|
+
* manifest of installed files so future installs and uninstalls know
|
|
829
|
+
* exactly which files are "ours".
|
|
830
|
+
*
|
|
831
|
+
* Also removes files that were in the previous manifest but are no longer
|
|
832
|
+
* in the source (renamed/deleted upstream), then prunes empty directories.
|
|
833
|
+
*
|
|
834
|
+
* @param {string} src - source directory (package content)
|
|
835
|
+
* @param {string} dest - target directory (workspace or global)
|
|
836
|
+
* @param {Object} [options]
|
|
837
|
+
* @param {string[]} [options.exclude] - relative paths to skip (e.g. [".claude-plugin"])
|
|
838
|
+
* @returns {number} count of files installed
|
|
839
|
+
*/
|
|
840
|
+
function mergeInstallDir(src, dest, options = {}) {
|
|
841
|
+
const excludePatterns = (options.exclude || []).map((p) => p.replace(/\\/g, "/"));
|
|
842
|
+
ensureDir(dest);
|
|
843
|
+
|
|
844
|
+
// Read previous manifest to detect removals
|
|
845
|
+
const manifestPath = join(dest, DIR_MANIFEST_FILENAME);
|
|
846
|
+
const oldManifest = readJson(manifestPath);
|
|
847
|
+
const previousFiles = new Set((oldManifest && oldManifest.files) || []);
|
|
848
|
+
|
|
849
|
+
// Collect and copy source files
|
|
850
|
+
const isExcluded = (rel) => excludePatterns.some((pat) =>
|
|
851
|
+
rel === pat || rel.includes(pat) || rel.split("/").some((seg) => seg === pat)
|
|
852
|
+
);
|
|
853
|
+
const srcFiles = collectRelativePaths(src).filter((rel) => !isExcluded(rel));
|
|
854
|
+
|
|
855
|
+
for (const rel of srcFiles) {
|
|
856
|
+
const destFile = join(dest, rel);
|
|
857
|
+
ensureDir(dirname(destFile));
|
|
858
|
+
cpSync(join(src, rel), destFile, { force: true });
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
const installedSet = new Set(srcFiles);
|
|
862
|
+
|
|
863
|
+
// Remove files from previous install that no longer exist in source
|
|
864
|
+
for (const rel of previousFiles) {
|
|
865
|
+
if (!installedSet.has(rel)) {
|
|
866
|
+
const fullPath = join(dest, rel);
|
|
867
|
+
if (existsSync(fullPath)) {
|
|
868
|
+
rmSync(fullPath, { force: true });
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
// Prune empty directories (bottom-up) — skip dest root so install always has a target
|
|
874
|
+
const pruneEmpty = (dir) => {
|
|
875
|
+
if (!existsSync(dir)) return;
|
|
876
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
877
|
+
if (entry.isDirectory()) pruneEmpty(join(dir, entry.name));
|
|
878
|
+
}
|
|
879
|
+
try {
|
|
880
|
+
const remaining = readdirSync(dir);
|
|
881
|
+
if (remaining.length === 0 && !isSamePath(dir, dest)) {
|
|
882
|
+
rmSync(dir, { recursive: true, force: true });
|
|
883
|
+
}
|
|
884
|
+
} catch { /* dir already gone */ }
|
|
885
|
+
};
|
|
886
|
+
pruneEmpty(dest);
|
|
887
|
+
|
|
888
|
+
// Write new manifest
|
|
889
|
+
const manifest = {
|
|
890
|
+
version: pkg.version,
|
|
891
|
+
installedAt: new Date().toISOString(),
|
|
892
|
+
files: srcFiles.sort(),
|
|
893
|
+
};
|
|
894
|
+
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
|
|
895
|
+
|
|
896
|
+
return srcFiles.length;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
/**
|
|
900
|
+
* Remove only the files we previously installed (per manifest) from `dest`.
|
|
901
|
+
* Prunes empty directories afterwards. If no manifest exists, falls back
|
|
902
|
+
* to removing the entire directory (legacy behavior).
|
|
903
|
+
*
|
|
904
|
+
* @param {string} dest - target directory to clean
|
|
905
|
+
* @returns {boolean} true if anything was removed
|
|
906
|
+
*/
|
|
907
|
+
function mergeUninstallDir(dest) {
|
|
908
|
+
if (!existsSync(dest)) return false;
|
|
909
|
+
|
|
910
|
+
const manifestPath = join(dest, DIR_MANIFEST_FILENAME);
|
|
911
|
+
const manifest = readJson(manifestPath);
|
|
912
|
+
|
|
913
|
+
if (!manifest || !manifest.files) {
|
|
914
|
+
// Legacy: no manifest — remove everything (matches old behavior)
|
|
915
|
+
rmSync(dest, { recursive: true, force: true });
|
|
916
|
+
return true;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
let removed = 0;
|
|
920
|
+
for (const rel of manifest.files) {
|
|
921
|
+
const fullPath = join(dest, rel);
|
|
922
|
+
if (existsSync(fullPath)) {
|
|
923
|
+
rmSync(fullPath, { force: true });
|
|
924
|
+
removed++;
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
// Remove the manifest itself
|
|
929
|
+
if (existsSync(manifestPath)) rmSync(manifestPath, { force: true });
|
|
930
|
+
|
|
931
|
+
// Remove .version stamp if present
|
|
932
|
+
const versionFile = join(dest, ".version");
|
|
933
|
+
if (existsSync(versionFile)) rmSync(versionFile, { force: true });
|
|
934
|
+
|
|
935
|
+
// Prune empty directories (bottom-up) — including dest root on uninstall
|
|
936
|
+
const pruneEmpty = (dir) => {
|
|
937
|
+
if (!existsSync(dir)) return;
|
|
938
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
939
|
+
if (entry.isDirectory()) pruneEmpty(join(dir, entry.name));
|
|
940
|
+
}
|
|
941
|
+
try {
|
|
942
|
+
const remaining = readdirSync(dir);
|
|
943
|
+
if (remaining.length === 0) {
|
|
944
|
+
rmSync(dir, { recursive: true, force: true });
|
|
945
|
+
}
|
|
946
|
+
} catch { /* dir already gone */ }
|
|
947
|
+
};
|
|
948
|
+
pruneEmpty(dest);
|
|
949
|
+
|
|
950
|
+
return removed > 0;
|
|
951
|
+
}
|
|
952
|
+
|
|
799
953
|
// ---------------------------------------------------------------------------
|
|
800
954
|
// Orphan cleanup: remove skills/agents from previous installs that are no
|
|
801
955
|
// longer in the current catalog. Uses a manifest file written after each
|
|
@@ -1231,10 +1385,12 @@ function installKnowledge() {
|
|
|
1231
1385
|
if (!existsSync(src)) return 0;
|
|
1232
1386
|
|
|
1233
1387
|
// 1. Local workspace copy (primary — supports account knowledge overrides)
|
|
1388
|
+
// Merge-install: overwrites our files, preserves client-added files.
|
|
1234
1389
|
const dest = join(getProjectRoot(), "knowledge");
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1390
|
+
let count = mergeInstallDir(src, dest, { exclude: [".claude-plugin"] });
|
|
1391
|
+
// Always clean up .claude-plugin directory if it leaked in
|
|
1392
|
+
const pluginDir = join(dest, ".claude-plugin");
|
|
1393
|
+
if (existsSync(pluginDir)) rmSync(pluginDir, { recursive: true, force: true });
|
|
1238
1394
|
// Stamp local copy with package version for doctor version comparison
|
|
1239
1395
|
writeFileSync(join(dest, ".version"), pkg.version, "utf-8");
|
|
1240
1396
|
|
|
@@ -1242,21 +1398,12 @@ function installKnowledge() {
|
|
|
1242
1398
|
const refModSrc = join(CONTENT_ROOT, "dev", "reference-modules");
|
|
1243
1399
|
if (existsSync(refModSrc)) {
|
|
1244
1400
|
const refModDest = join(dest, "reference-modules");
|
|
1245
|
-
|
|
1401
|
+
count += mergeInstallDir(refModSrc, refModDest);
|
|
1246
1402
|
}
|
|
1247
1403
|
|
|
1248
1404
|
// 3. Global fallback copy (so new workspaces can skip full install)
|
|
1249
1405
|
installGlobalKnowledge(src);
|
|
1250
1406
|
|
|
1251
|
-
// Count copied files for reporting
|
|
1252
|
-
let count = 0;
|
|
1253
|
-
const walk = (dir) => {
|
|
1254
|
-
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
1255
|
-
if (entry.isDirectory()) walk(join(dir, entry.name));
|
|
1256
|
-
else count++;
|
|
1257
|
-
}
|
|
1258
|
-
};
|
|
1259
|
-
walk(dest);
|
|
1260
1407
|
return count;
|
|
1261
1408
|
}
|
|
1262
1409
|
|
|
@@ -1268,15 +1415,12 @@ function installKnowledge() {
|
|
|
1268
1415
|
function installGlobalKnowledge(src) {
|
|
1269
1416
|
if (!src) src = join(CONTENT_ROOT, "knowledge");
|
|
1270
1417
|
if (!existsSync(src)) return 0;
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
cpSync(src, GLOBAL_KNOWLEDGE_DIR, { recursive: true, force: true });
|
|
1274
|
-
rmSync(join(GLOBAL_KNOWLEDGE_DIR, ".claude-plugin"), { recursive: true, force: true });
|
|
1418
|
+
// Global dir is fully managed (no client files) — merge-install for consistency
|
|
1419
|
+
mergeInstallDir(src, GLOBAL_KNOWLEDGE_DIR, { exclude: [".claude-plugin"] });
|
|
1275
1420
|
// Copy reference module catalog alongside global knowledge
|
|
1276
1421
|
const refModSrc = join(CONTENT_ROOT, "dev", "reference-modules");
|
|
1277
1422
|
if (existsSync(refModSrc)) {
|
|
1278
|
-
|
|
1279
|
-
cpSync(refModSrc, refModDest, { recursive: true, force: true });
|
|
1423
|
+
mergeInstallDir(refModSrc, join(GLOBAL_KNOWLEDGE_DIR, "reference-modules"));
|
|
1280
1424
|
}
|
|
1281
1425
|
// Stamp with package version so we can detect stale global knowledge
|
|
1282
1426
|
writeFileSync(join(GLOBAL_KNOWLEDGE_DIR, ".version"), pkg.version, "utf-8");
|
|
@@ -1301,19 +1445,10 @@ function installDocs() {
|
|
|
1301
1445
|
const src = join(dirname(fileURLToPath(import.meta.url)), "..", "docs");
|
|
1302
1446
|
if (!existsSync(src)) return 0;
|
|
1303
1447
|
const dest = join(getProjectRoot(), "docs");
|
|
1304
|
-
//
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
let count = 0;
|
|
1309
|
-
const walk = (dir) => {
|
|
1310
|
-
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
1311
|
-
if (entry.isDirectory()) walk(join(dir, entry.name));
|
|
1312
|
-
else count++;
|
|
1313
|
-
}
|
|
1314
|
-
};
|
|
1315
|
-
walk(dest);
|
|
1316
|
-
return count;
|
|
1448
|
+
// Guard: when running from the repo itself, src === dest — skip to avoid self-deletion.
|
|
1449
|
+
if (existsSync(dest) && realpathSync(src) === realpathSync(dest)) return 0;
|
|
1450
|
+
// Merge-install: overwrites our files, preserves client-added files.
|
|
1451
|
+
return mergeInstallDir(src, dest, { exclude: [".tmp."] });
|
|
1317
1452
|
}
|
|
1318
1453
|
|
|
1319
1454
|
function buildStarterWorkspaceInstructions(fileName, profile, retailer) {
|
|
@@ -1427,6 +1562,22 @@ Follow this lifecycle. Each stage has purpose-built skills:
|
|
|
1427
1562
|
| **Audit** | \`/fluent-rfl-assess\`, \`/fluent-session\`, \`/fluent-feature-status\`, \`/fluent-skill-observability\` | Go-live readiness, audit trail, status dashboard, skill quality |
|
|
1428
1563
|
<!-- /ai-skills:managed:sdlc-map -->
|
|
1429
1564
|
|
|
1565
|
+
<!-- ai-skills:managed:investigation-protocol -->
|
|
1566
|
+
## Investigation Protocol
|
|
1567
|
+
|
|
1568
|
+
**Tier 1 — Direct execute (no plan):** Single-tool lookups (entity status, setting value, retailer list) and prompts that map to a single skill with its own phases (e.g., fluent-trace, fluent-workflow-builder). Proceed directly — the skill handles its own execution plan. Optionally announce the skill in one line: "Using fluent-trace for this."
|
|
1569
|
+
|
|
1570
|
+
**Tier 2 — Micro-plan (multi-step, no approval wait):** When a question needs 2+ MCP tools and doesn't map cleanly to one skill (debugging, cross-entity tracing, analysis, "why is X broken"):
|
|
1571
|
+
|
|
1572
|
+
1. Print an **Approach** heading, then a numbered step list with the MCP tool or skill name per step
|
|
1573
|
+
2. End with summary lines: \`Tools:\`, \`Skills:\`, \`Est. calls:\`, \`Watch for:\` (one-line risk)
|
|
1574
|
+
3. Print "[executing...]" and start immediately — no approval wait
|
|
1575
|
+
4. If an earlier step resolves the question, **stop and report**. List skipped steps and why. The user can say "continue with steps X-Y" to resume.
|
|
1576
|
+
5. For follow-up additions ("also check permissions"), **append** steps to the existing plan rather than re-planning from scratch.
|
|
1577
|
+
|
|
1578
|
+
**Tier 3 — Full planning gate:** Deployments, scaffolding, and feature builds. Present structured plan and wait for approval. (Already enforced by skills with mandatory planning gates.)
|
|
1579
|
+
<!-- /ai-skills:managed:investigation-protocol -->
|
|
1580
|
+
|
|
1430
1581
|
## Quick Actions
|
|
1431
1582
|
|
|
1432
1583
|
| What you want | Say this |
|
|
@@ -1510,7 +1661,7 @@ function generateStarterWorkspaceDoc(fileName, profile, retailer) {
|
|
|
1510
1661
|
* Managed section IDs embedded in workspace instruction files.
|
|
1511
1662
|
* Content between markers is updated on every install; everything else is user-owned.
|
|
1512
1663
|
*/
|
|
1513
|
-
const MANAGED_SECTION_IDS = ["reference-docs", "routing-tripwires", "mcp-tools", "sdlc-map"];
|
|
1664
|
+
const MANAGED_SECTION_IDS = ["reference-docs", "routing-tripwires", "mcp-tools", "sdlc-map", "investigation-protocol"];
|
|
1514
1665
|
|
|
1515
1666
|
/**
|
|
1516
1667
|
* Heading patterns for each managed section — used to find and migrate
|
|
@@ -1522,6 +1673,7 @@ const MANAGED_SECTION_HEADINGS = {
|
|
|
1522
1673
|
"routing-tripwires": /^##\s+Routing\s+Tripwires?\b/im,
|
|
1523
1674
|
"mcp-tools": /^##\s+MCP\s+Tools?\b/im,
|
|
1524
1675
|
"sdlc-map": /^##\s+SDLC\s+Skill\s+Map\b/im,
|
|
1676
|
+
"investigation-protocol": /^##\s+Investigation\s+Protocol\b/im,
|
|
1525
1677
|
};
|
|
1526
1678
|
|
|
1527
1679
|
/**
|
|
@@ -1627,16 +1779,15 @@ function generateStarterGeminiMd(profile, retailer) {
|
|
|
1627
1779
|
|
|
1628
1780
|
function uninstallKnowledge() {
|
|
1629
1781
|
const dest = join(getProjectRoot(), "knowledge");
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1782
|
+
// Uninstall nested reference-modules first (has its own manifest)
|
|
1783
|
+
const refModDest = join(dest, "reference-modules");
|
|
1784
|
+
mergeUninstallDir(refModDest);
|
|
1785
|
+
return mergeUninstallDir(dest);
|
|
1633
1786
|
}
|
|
1634
1787
|
|
|
1635
1788
|
function uninstallDocs() {
|
|
1636
1789
|
const dest = join(getProjectRoot(), "docs");
|
|
1637
|
-
|
|
1638
|
-
rmSync(dest, { recursive: true, force: true });
|
|
1639
|
-
return true;
|
|
1790
|
+
return mergeUninstallDir(dest);
|
|
1640
1791
|
}
|
|
1641
1792
|
|
|
1642
1793
|
function uninstallClaude(groups) {
|
|
@@ -4123,6 +4274,27 @@ function listGroups(groups) {
|
|
|
4123
4274
|
log("");
|
|
4124
4275
|
}
|
|
4125
4276
|
|
|
4277
|
+
function showGetStarted() {
|
|
4278
|
+
log(`
|
|
4279
|
+
fluent-ai-skills v${pkg.version}
|
|
4280
|
+
|
|
4281
|
+
No skills installed yet. Get started:
|
|
4282
|
+
|
|
4283
|
+
${"\x1b[36m"}npx @fluentcommerce/ai-skills install${"\x1b[0m"}
|
|
4284
|
+
|
|
4285
|
+
First time? Add a Fluent CLI profile for full API access:
|
|
4286
|
+
|
|
4287
|
+
${"\x1b[36m"}npx @fluentcommerce/ai-skills install --profile MYPROFILE${"\x1b[0m"}
|
|
4288
|
+
|
|
4289
|
+
Other targets (Codex, Gemini):
|
|
4290
|
+
|
|
4291
|
+
npx @fluentcommerce/ai-skills install --target codex
|
|
4292
|
+
npx @fluentcommerce/ai-skills install --target gemini
|
|
4293
|
+
|
|
4294
|
+
Run ${"\x1b[36m"}npx @fluentcommerce/ai-skills --help${"\x1b[0m"} for all options.
|
|
4295
|
+
`);
|
|
4296
|
+
}
|
|
4297
|
+
|
|
4126
4298
|
function showHelp(groups) {
|
|
4127
4299
|
const groupNames = getInstallableGroups(groups).map((group) => group.name).join(", ");
|
|
4128
4300
|
log(`
|
|
@@ -4303,7 +4475,11 @@ function main() {
|
|
|
4303
4475
|
const args = process.argv.slice(2);
|
|
4304
4476
|
|
|
4305
4477
|
if (args.length === 0) {
|
|
4306
|
-
|
|
4478
|
+
if (!hasAnyInstallations(groups)) {
|
|
4479
|
+
showGetStarted();
|
|
4480
|
+
} else {
|
|
4481
|
+
showHelp(groups);
|
|
4482
|
+
}
|
|
4307
4483
|
process.exit(0);
|
|
4308
4484
|
}
|
|
4309
4485
|
|
|
@@ -4443,8 +4619,8 @@ function main() {
|
|
|
4443
4619
|
log("");
|
|
4444
4620
|
targetUninstall(target, selected, { scope });
|
|
4445
4621
|
if (!hasAnyInstallations(groups)) {
|
|
4446
|
-
if (uninstallKnowledge()) logOk("removed knowledge/");
|
|
4447
|
-
if (uninstallDocs()) logOk("removed docs/");
|
|
4622
|
+
if (uninstallKnowledge()) logOk("removed managed files from knowledge/");
|
|
4623
|
+
if (uninstallDocs()) logOk("removed managed files from docs/");
|
|
4448
4624
|
}
|
|
4449
4625
|
if (purge) {
|
|
4450
4626
|
if (existsSync(GLOBAL_KNOWLEDGE_DIR)) {
|
|
@@ -4542,7 +4718,7 @@ function main() {
|
|
|
4542
4718
|
break;
|
|
4543
4719
|
}
|
|
4544
4720
|
case "dashboard": {
|
|
4545
|
-
const dashboardScript = join(dirname(fileURLToPath(import.meta.url)), "..", "tools", "
|
|
4721
|
+
const dashboardScript = join(dirname(fileURLToPath(import.meta.url)), "..", "tools", "feature-dashboard.mjs");
|
|
4546
4722
|
const dashArgs = [...commandArgs];
|
|
4547
4723
|
if (profile && !dashArgs.includes("--profile") && !dashArgs.includes("-p")) {
|
|
4548
4724
|
dashArgs.push("--profile", profile);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: fluent-bootstrap
|
|
3
|
-
description: Complete Fluent Commerce account bootstrap wizard for greenfield environments. Use when setting up a brand-new account from scratch with no existing CLI profile or retailer
|
|
3
|
+
description: Complete Fluent Commerce account bootstrap wizard for greenfield environments. Use when setting up a brand-new account from scratch with no existing CLI profile or retailer.
|
|
4
4
|
user-invocable: true
|
|
5
5
|
allowed-tools: Bash, Read, Write, Edit, Glob, Grep
|
|
6
6
|
argument-hint: [profile-name] [retailer-ref]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: fluent-cli-mcp-cicd
|
|
3
|
-
description: Fluent CLI MCP and CI/CD operations guide
|
|
3
|
+
description: Fluent CLI MCP and CI/CD operations guide for MCP server configuration and safe module deployment in automation pipelines. Use for CI/CD pipeline setup or MCP connectivity validation.
|
|
4
4
|
user-invocable: true
|
|
5
5
|
allowed-tools: Bash, Read, Write, Edit, Glob, Grep
|
|
6
6
|
argument-hint: [mcp|cicd] [--profile name] [--retailer ref]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: fluent-cli-reference
|
|
3
|
-
description: Complete Fluent Commerce CLI v2 command reference
|
|
3
|
+
description: Complete Fluent Commerce CLI v2 command reference with every command, flag, and output format. Use for any CLI question or to find the right specialist skill.
|
|
4
4
|
user-invocable: true
|
|
5
5
|
allowed-tools: Bash, Read, Write, Edit, Glob, Grep
|
|
6
6
|
argument-hint: [command] [subcommand]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: fluent-cli-retailer
|
|
3
|
-
description: Manage Fluent retailer lifecycle via CLI
|
|
3
|
+
description: Manage Fluent retailer lifecycle via CLI including creation, listing, profile context validation, and retailer admin access. Use for retailer CRUD and deployment context setup.
|
|
4
4
|
user-invocable: true
|
|
5
5
|
allowed-tools: Bash, Read, Write, Edit, Glob, Grep
|
|
6
6
|
argument-hint: <create|list> [retailer-ref] [--profile name]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: fluent-connect
|
|
3
|
-
description: Guided onboarding wizard to connect this workspace to an existing Fluent Commerce account
|
|
3
|
+
description: Guided onboarding wizard to connect this workspace to an existing Fluent Commerce account. Discovers profiles, wires MCP, downloads workflows. Use when connecting to an existing account.
|
|
4
4
|
user-invocable: true
|
|
5
5
|
allowed-tools: Bash, Read, Write, Edit, Glob, Grep
|
|
6
6
|
argument-hint: [--profile <name>] [--retailer <ref>] [--force]
|
|
@@ -93,7 +93,18 @@ ls ~/.fluentcommerce/
|
|
|
93
93
|
Get-ChildItem "$env:USERPROFILE\.fluentcommerce"
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
-
Each subdirectory (excluding `.sessions`, `config.json`) is a potential profile. Each contains `profile.json
|
|
96
|
+
Each subdirectory (excluding `.sessions`, `config.json`) is a potential profile. Each contains `profile.json`:
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"id": "<account-id>",
|
|
101
|
+
"baseUrl": "https://<account>.<tier>.api.fluentretail.com",
|
|
102
|
+
"clientSecret": "<uuid>",
|
|
103
|
+
"user": "<username>"
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
> **IMPORTANT:** The `user` field is a **string** (username reference), NOT an object with credentials. Credentials are stored in a separate `user.<username>.json` file. If `user` is an object like `{ "username": "...", "password": "..." }`, the profile was created manually in the wrong format — fix it with `fluent profile create`.
|
|
97
108
|
|
|
98
109
|
### Step 1.2: Present profiles to user
|
|
99
110
|
|
|
@@ -143,6 +154,50 @@ Each file is named `retailer.<REF>.json` and contains:
|
|
|
143
154
|
{ "id": "<retailer_id>", "ref": "<ref>", "user": "<username>" }
|
|
144
155
|
```
|
|
145
156
|
|
|
157
|
+
### Step 2.1b: Validate retailer file format
|
|
158
|
+
|
|
159
|
+
For each `retailer.*.json` file discovered, validate it matches the canonical CLI format. Non-canonical formats can cause silent MCP auth failures and confusing connectivity errors.
|
|
160
|
+
|
|
161
|
+
**Canonical format** (written by `fluent profile update`):
|
|
162
|
+
```json
|
|
163
|
+
{ "id": "<retailer-numeric-id>", "ref": "<retailer-ref>", "user": "<username-string>" }
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Known bad formats to detect:**
|
|
167
|
+
|
|
168
|
+
| Pattern | Problem | Likely Cause |
|
|
169
|
+
|---------|---------|-------------|
|
|
170
|
+
| `{ "retailerId": ..., "username": ..., "password": ... }` | Inlined credentials, wrong field names | Manual creation or old skill version |
|
|
171
|
+
| `{ "id": ..., "ref": ..., "user": { "username": ..., "password": ... } }` | `user` is object instead of string | AI wrote file directly instead of using CLI |
|
|
172
|
+
| Missing `ref` field | Incomplete record | Partial manual edit |
|
|
173
|
+
| Missing `user` field | No user binding | Partial creation |
|
|
174
|
+
|
|
175
|
+
**Validation logic:** For each retailer file, check:
|
|
176
|
+
|
|
177
|
+
1. Has `id` field (string or number)
|
|
178
|
+
2. Has `ref` field (string)
|
|
179
|
+
3. Has `user` field that is a **string** (not an object)
|
|
180
|
+
4. Does NOT have `retailerId`, `username`, or `password` as top-level keys
|
|
181
|
+
|
|
182
|
+
**If any file fails validation:**
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
⚠ Non-canonical retailer file detected:
|
|
186
|
+
File: ~/.fluentcommerce/<PROFILE>/retailer.<REF>.json
|
|
187
|
+
Issue: <description of what's wrong>
|
|
188
|
+
Risk: MCP extension may fail to resolve retailer context
|
|
189
|
+
|
|
190
|
+
Fix: Re-register this retailer using the CLI:
|
|
191
|
+
fluent profile update <PROFILE> --retailer <REF> --id <ID> --username <USER> --password <PASS>
|
|
192
|
+
|
|
193
|
+
This will overwrite the file with the correct canonical format.
|
|
194
|
+
Proceed with current file anyway? [yes/NO]
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Wait for user confirmation. If they choose to fix, guide them through the `fluent profile update` command (they must supply their password). If they proceed anyway, log the issue in the feedback record at the end of execution.
|
|
198
|
+
|
|
199
|
+
**IMPORTANT — Never write retailer or profile JSON files directly.** Always delegate to `fluent profile create` or `fluent profile update` which handle format, encryption, and storage correctly. This applies even if you "know" the correct format — the CLI may add fields or change structure across versions.
|
|
200
|
+
|
|
146
201
|
### Step 2.2: Present retailers to user
|
|
147
202
|
|
|
148
203
|
| # | Retailer Ref | Retailer ID | User |
|
|
@@ -346,7 +401,7 @@ const base = path.join('accounts', profile);
|
|
|
346
401
|
const placeholders = {
|
|
347
402
|
'SOURCE/backend': {
|
|
348
403
|
title: 'Backend Source Code',
|
|
349
|
-
content: 'Clone Java Maven plugin repos here. Each subdirectory should be one git repo with pom.xml + src/main/java/.\n\nExample:\n git clone https://your-org/fc-plugin-custom.git\n\nStandalone JARs (no source): place .jar files here — auto-decompiled to .decompiled/\n\nPopulated by: git clone or manual copy\nAnalyzed by: /fluent-custom-code, /fluent-
|
|
404
|
+
content: 'Clone Java Maven plugin repos here. Each subdirectory should be one git repo with pom.xml + src/main/java/.\n\nExample:\n git clone https://your-org/fc-plugin-custom.git\n\nStandalone JARs (no source): place .jar files here — auto-decompiled to .decompiled/\n\nPopulated by: git clone or manual copy\nAnalyzed by: /fluent-custom-code, /fluent-module-convert'
|
|
350
405
|
},
|
|
351
406
|
'SOURCE/frontend': {
|
|
352
407
|
title: 'Frontend Source Code',
|
|
@@ -68,8 +68,8 @@ fluent profile create cli-b2c \
|
|
|
68
68
|
--id ABC123 \
|
|
69
69
|
--base-url https://abc123.sandbox.api.fluentretail.com \
|
|
70
70
|
--username admin_user \
|
|
71
|
-
--password
|
|
72
|
-
--client-secret
|
|
71
|
+
--password '<your-password>' \
|
|
72
|
+
--client-secret '<your-client-secret>'
|
|
73
73
|
```
|
|
74
74
|
|
|
75
75
|
### 2. List Profiles
|
|
@@ -180,13 +180,43 @@ Profiles stored in: `~/.fluentcommerce/<profile-name>/`
|
|
|
180
180
|
```
|
|
181
181
|
~/.fluentcommerce/
|
|
182
182
|
├── cli-b2c/
|
|
183
|
-
│ ├── profile.json
|
|
184
|
-
│ ├── user.admin_user.json
|
|
185
|
-
│ └── retailer.b2c.json
|
|
183
|
+
│ ├── profile.json # { "accountId", "baseUrl", "clientSecret", ... }
|
|
184
|
+
│ ├── user.admin_user.json # { "username", "password" }
|
|
185
|
+
│ └── retailer.b2c.json # { "id", "ref", "user": "<username-string>" }
|
|
186
186
|
└── .sessions/
|
|
187
187
|
└── <session-files>
|
|
188
188
|
```
|
|
189
189
|
|
|
190
|
+
### Canonical Retailer File Format
|
|
191
|
+
|
|
192
|
+
The `retailer.<ref>.json` file MUST follow this schema (written by `fluent profile update`):
|
|
193
|
+
|
|
194
|
+
```json
|
|
195
|
+
{ "id": "<retailer-numeric-id>", "ref": "<retailer-ref>", "user": "<username-string>" }
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
The `user` field is a **string** referencing a `user.<name>.json` file in the same directory — NOT an object with inlined credentials.
|
|
199
|
+
|
|
200
|
+
### CRITICAL — Never Write Profile Files Directly
|
|
201
|
+
|
|
202
|
+
**Always use CLI commands** (`fluent profile create`, `fluent profile update`) to create or modify profile, user, and retailer JSON files. Never use `Write`, `Edit`, or shell redirection (`echo >`, `cat <<EOF >`) to create or modify files under `~/.fluentcommerce/`.
|
|
203
|
+
|
|
204
|
+
**Why:** The CLI handles format versioning, credential storage, field normalization, and session management. Writing files directly risks:
|
|
205
|
+
- Wrong field names (`retailerId` vs `id`, `username` vs `user`)
|
|
206
|
+
- Wrong value types (`user` as object instead of string reference)
|
|
207
|
+
- Missing cross-references (retailer `user` must match a `user.<name>.json` filename)
|
|
208
|
+
- Breaking future CLI versions that expect new fields
|
|
209
|
+
|
|
210
|
+
**If you encounter a malformed profile/retailer file**, guide the user to fix it with CLI commands:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
# Fix a malformed retailer file
|
|
214
|
+
fluent profile update <PROFILE> --retailer <REF> --id <ID> --username <USER> --password <PASS>
|
|
215
|
+
|
|
216
|
+
# Fix a malformed profile
|
|
217
|
+
fluent profile create <PROFILE> --id <ACCT> --base-url <URL> --username <USER> --password <PASS> --client-secret <SECRET>
|
|
218
|
+
```
|
|
219
|
+
|
|
190
220
|
## Error Handling
|
|
191
221
|
|
|
192
222
|
| Error | Solution |
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: fluent-workflow
|
|
3
|
-
description:
|
|
3
|
+
description: List, download, merge fragments, and track workflow modifications via Fluent CLI. Use for workflow retrieval, export, merging customizations, or viewing logs.
|
|
4
4
|
user-invocable: true
|
|
5
5
|
allowed-tools: Bash, Read, Write, Edit, Glob, Grep
|
|
6
6
|
argument-hint: <operation> [workflow-name]
|
|
7
7
|
cursor-tier: auto
|
|
8
8
|
---
|
|
9
|
+
<!-- routing-notes: HARD NEGATIVE — if the user wants to validate, review, lint, or analyze a workflow after download, route to fluent-workflow-analyzer; this skill owns retrieval and operational manipulation, not validation. -->
|
|
9
10
|
|
|
10
11
|
# Workflow Management
|
|
11
12
|
|