@fluentcommerce/ai-skills 0.1.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/LICENSE +21 -0
- package/README.md +622 -0
- package/bin/cli.mjs +1973 -0
- package/content/cli/agents/fluent-cli/agent.json +149 -0
- package/content/cli/agents/fluent-cli.md +132 -0
- package/content/cli/skills/fluent-bootstrap/SKILL.md +181 -0
- package/content/cli/skills/fluent-cli-index/SKILL.md +63 -0
- package/content/cli/skills/fluent-cli-mcp-cicd/SKILL.md +77 -0
- package/content/cli/skills/fluent-cli-reference/SKILL.md +1031 -0
- package/content/cli/skills/fluent-cli-retailer/SKILL.md +85 -0
- package/content/cli/skills/fluent-cli-settings/SKILL.md +106 -0
- package/content/cli/skills/fluent-connect/SKILL.md +886 -0
- package/content/cli/skills/fluent-module-deploy/SKILL.md +349 -0
- package/content/cli/skills/fluent-profile/SKILL.md +180 -0
- package/content/cli/skills/fluent-workflow/SKILL.md +310 -0
- package/content/dev/agents/fluent-dev/agent.json +88 -0
- package/content/dev/agents/fluent-dev.md +525 -0
- package/content/dev/reference-modules/catalog.json +4754 -0
- package/content/dev/skills/fluent-build/SKILL.md +192 -0
- package/content/dev/skills/fluent-connection-analysis/SKILL.md +386 -0
- package/content/dev/skills/fluent-custom-code/SKILL.md +895 -0
- package/content/dev/skills/fluent-data-module-scaffold/SKILL.md +714 -0
- package/content/dev/skills/fluent-e2e-test/SKILL.md +394 -0
- package/content/dev/skills/fluent-event-api/SKILL.md +945 -0
- package/content/dev/skills/fluent-feature-explain/SKILL.md +603 -0
- package/content/dev/skills/fluent-feature-plan/PLAN_TEMPLATE.md +695 -0
- package/content/dev/skills/fluent-feature-plan/SKILL.md +227 -0
- package/content/dev/skills/fluent-job-batch/SKILL.md +138 -0
- package/content/dev/skills/fluent-mermaid-validate/SKILL.md +86 -0
- package/content/dev/skills/fluent-module-scaffold/SKILL.md +1928 -0
- package/content/dev/skills/fluent-module-validate/SKILL.md +775 -0
- package/content/dev/skills/fluent-pre-deploy-check/SKILL.md +1108 -0
- package/content/dev/skills/fluent-retailer-config/SKILL.md +1111 -0
- package/content/dev/skills/fluent-rule-scaffold/SKILL.md +385 -0
- package/content/dev/skills/fluent-scope-decompose/SKILL.md +1021 -0
- package/content/dev/skills/fluent-session-audit-export/SKILL.md +632 -0
- package/content/dev/skills/fluent-session-summary/SKILL.md +195 -0
- package/content/dev/skills/fluent-settings/SKILL.md +1058 -0
- package/content/dev/skills/fluent-source-onboard/SKILL.md +632 -0
- package/content/dev/skills/fluent-system-monitoring/SKILL.md +767 -0
- package/content/dev/skills/fluent-test-data/SKILL.md +513 -0
- package/content/dev/skills/fluent-trace/SKILL.md +1143 -0
- package/content/dev/skills/fluent-transition-api/SKILL.md +346 -0
- package/content/dev/skills/fluent-version-manage/SKILL.md +744 -0
- package/content/dev/skills/fluent-workflow-analyzer/SKILL.md +959 -0
- package/content/dev/skills/fluent-workflow-builder/SKILL.md +319 -0
- package/content/dev/skills/fluent-workflow-deploy/SKILL.md +267 -0
- package/content/mcp-extn/agents/fluent-mcp.md +69 -0
- package/content/mcp-extn/skills/fluent-mcp-tools/SKILL.md +461 -0
- package/content/mcp-official/agents/fluent-mcp-core.md +91 -0
- package/content/mcp-official/skills/fluent-mcp-core/SKILL.md +94 -0
- package/content/rfl/agents/fluent-rfl.md +56 -0
- package/content/rfl/skills/fluent-rfl-assess/SKILL.md +172 -0
- package/docs/CAPABILITY_MAP.md +77 -0
- package/docs/CLI_COVERAGE.md +47 -0
- package/docs/DEV_WORKFLOW.md +802 -0
- package/docs/FLOW_RUN.md +142 -0
- package/docs/USE_CASES.md +404 -0
- package/metadata.json +156 -0
- package/package.json +51 -0
|
@@ -0,0 +1,886 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fluent-connect
|
|
3
|
+
description: Guided onboarding wizard to connect to an existing Fluent Commerce account. Discovers CLI profiles, selects retailer, wires MCP servers, prepares workspace, downloads workflows, decompiles JARs, and reports readiness with cached state. Triggers on "connect account", "switch account", "onboard", "wire up", "get started", "setup environment", "connect to fluent", "change account", "setup workspace", "initialize workspace", "discover profiles".
|
|
4
|
+
user-invocable: true
|
|
5
|
+
allowed-tools: Bash, Read, Write, Edit, Glob, Grep
|
|
6
|
+
argument-hint: [--profile <name>] [--retailer <ref>] [--force]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Fluent Account Connect
|
|
10
|
+
|
|
11
|
+
Guided wizard to connect this workspace to an existing Fluent Commerce account. Discovers CLI profiles, selects a retailer target, wires MCP servers, prepares workspace directories, downloads workflows, decompiles JARs, validates connectivity, and persists cached state so subsequent runs are instant.
|
|
12
|
+
|
|
13
|
+
## Ownership Boundary
|
|
14
|
+
|
|
15
|
+
This skill owns the "connect to existing account" workflow: profile discovery, retailer selection, MCP wiring, workspace directory setup, JAR decompilation, state caching, and readiness reporting.
|
|
16
|
+
|
|
17
|
+
- Profile creation from scratch is owned by `/fluent-profile`.
|
|
18
|
+
- Full new-account bootstrap is owned by `/fluent-bootstrap`.
|
|
19
|
+
- MCP tool reference is owned by `/fluent-mcp-tools`.
|
|
20
|
+
- Workflow analysis is owned by `/fluent-workflow-analyzer`.
|
|
21
|
+
- Source code analysis is owned by `/fluent-custom-code`.
|
|
22
|
+
- Module validation is owned by `/fluent-module-validate`.
|
|
23
|
+
|
|
24
|
+
## When to Use
|
|
25
|
+
|
|
26
|
+
- "Connect me to an existing Fluent account"
|
|
27
|
+
- "Switch to a different account / retailer"
|
|
28
|
+
- "Set up my workspace for this profile"
|
|
29
|
+
- "Get me ready to work on [account]"
|
|
30
|
+
- "Onboard me" / "get started"
|
|
31
|
+
- "Setup workspace" / "initialize workspace"
|
|
32
|
+
- Re-running to validate an already-connected workspace
|
|
33
|
+
|
|
34
|
+
## Inputs
|
|
35
|
+
|
|
36
|
+
| Parameter | Required | Source | Description |
|
|
37
|
+
|-----------|----------|--------|-------------|
|
|
38
|
+
| `--profile <name>` | No | Argument or interactive | CLI profile name. If omitted, wizard discovers and asks. |
|
|
39
|
+
| `--retailer <ref>` | No | Argument or interactive | Retailer ref within the profile. If omitted, wizard discovers and asks. |
|
|
40
|
+
| `--force` | No | Argument | Ignore cached state, re-run full discovery even if nothing changed. |
|
|
41
|
+
|
|
42
|
+
If both `--profile` and `--retailer` are provided, skip the interactive selection phases and proceed directly to wiring and validation.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Phase 0: Cache Check
|
|
47
|
+
|
|
48
|
+
Before doing any work, check if workspace state is already current.
|
|
49
|
+
|
|
50
|
+
### Steps
|
|
51
|
+
|
|
52
|
+
1. Read `accounts/<PROFILE>/workspace-state.json` — if missing, proceed to Phase 1.
|
|
53
|
+
2. Compute a content hash (see Content Hash section) and compare with `contentHash` in the stored state.
|
|
54
|
+
3. If hashes match and `--force` is NOT set:
|
|
55
|
+
- Print the stored summary (profile, retailer, workflow count, source repo count, entity counts).
|
|
56
|
+
- Print "Workspace state is current. Use --force to re-run."
|
|
57
|
+
- **Stop here.**
|
|
58
|
+
4. If hashes differ or `--force` is set: continue to Phase 1.
|
|
59
|
+
|
|
60
|
+
If `--profile` was not given, skip cache check and go to Phase 1 (need to discover profiles first).
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Phase 1: Profile Discovery
|
|
65
|
+
|
|
66
|
+
### Step 1.1: List CLI profiles
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
fluent profile list
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Also scan the filesystem for profile directories:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
ls ~/.fluentcommerce/
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```powershell
|
|
79
|
+
# PowerShell
|
|
80
|
+
Get-ChildItem "$env:USERPROFILE\.fluentcommerce"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Each subdirectory (excluding `.sessions`, `config.json`) is a potential profile. Each contains `profile.json` with `id`, `baseUrl`, `clientSecret`, `user`.
|
|
84
|
+
|
|
85
|
+
### Step 1.2: Present profiles to user
|
|
86
|
+
|
|
87
|
+
Read each `~/.fluentcommerce/<PROFILE>/profile.json` and build a summary table:
|
|
88
|
+
|
|
89
|
+
| # | Profile | Account | Environment | Base URL |
|
|
90
|
+
|---|---------|---------|-------------|----------|
|
|
91
|
+
| 1 | PROFILE_A | acme | sandbox | acme.sandbox.api.fluentretail.com |
|
|
92
|
+
| 2 | PROFILE_B | globex | test | globex.test.api.fluentretail.com |
|
|
93
|
+
|
|
94
|
+
**Account identification from base URL:**
|
|
95
|
+
- Pattern: `https://<account>[.<environment>].api.fluentretail.com`
|
|
96
|
+
- `.test.` = test environment
|
|
97
|
+
- `.sandbox.` = sandbox environment
|
|
98
|
+
- No qualifier = **production** (flag with warning)
|
|
99
|
+
|
|
100
|
+
### Step 1.3: Select profile
|
|
101
|
+
|
|
102
|
+
If `--profile` was provided, validate it exists in the list. If not, **ask the user** to pick from the discovered profiles.
|
|
103
|
+
|
|
104
|
+
**If no profiles exist at all:**
|
|
105
|
+
|
|
106
|
+
> No CLI profiles found. You need to create one first.
|
|
107
|
+
> Use `/fluent-profile` to create a profile, or `/fluent-bootstrap` for a complete new account setup.
|
|
108
|
+
|
|
109
|
+
Stop and delegate.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Phase 2: Retailer Selection
|
|
114
|
+
|
|
115
|
+
### Step 2.1: Discover retailers for selected profile
|
|
116
|
+
|
|
117
|
+
Read retailer files from the profile directory:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
ls ~/.fluentcommerce/<PROFILE>/retailer.*.json
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
```powershell
|
|
124
|
+
# PowerShell
|
|
125
|
+
Get-ChildItem "$env:USERPROFILE\.fluentcommerce\<PROFILE>\retailer.*.json"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Each file is named `retailer.<REF>.json` and contains:
|
|
129
|
+
```json
|
|
130
|
+
{ "id": "<retailer_id>", "ref": "<ref>", "user": "<username>" }
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Step 2.2: Present retailers to user
|
|
134
|
+
|
|
135
|
+
| # | Retailer Ref | Retailer ID | User |
|
|
136
|
+
|---|-------------|-------------|------|
|
|
137
|
+
| 1 | MY_RETAILER | 5 | retailer_admin |
|
|
138
|
+
| 2 | OTHER_RETAILER | 3 | other_admin |
|
|
139
|
+
|
|
140
|
+
### Step 2.3: Select retailer
|
|
141
|
+
|
|
142
|
+
If `--retailer` was provided, validate it matches a known retailer file. If not, **ask the user** to pick.
|
|
143
|
+
|
|
144
|
+
**If no retailers are configured:**
|
|
145
|
+
|
|
146
|
+
> No retailers found for profile `<PROFILE>`. You can:
|
|
147
|
+
> 1. Register an existing retailer: `fluent profile update <PROFILE> --retailer <REF> --id <ID>`
|
|
148
|
+
> 2. Create a new retailer: use `/fluent-cli-retailer`
|
|
149
|
+
> 3. Full account setup: use `/fluent-bootstrap`
|
|
150
|
+
|
|
151
|
+
### Step 2.4: Confirm target
|
|
152
|
+
|
|
153
|
+
Display the confirmed target before proceeding:
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
Target environment:
|
|
157
|
+
Profile: <PROFILE>
|
|
158
|
+
Account: <account>
|
|
159
|
+
Environment: <tier>
|
|
160
|
+
Base URL: https://<account>.<tier>.api.fluentretail.com
|
|
161
|
+
Retailer: <RETAILER_REF> (ID: <RETAILER_ID>)
|
|
162
|
+
User: <username>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
> **WARNING: PRODUCTION ENVIRONMENT** — If the base URL has no `.test.` or `.sandbox.` qualifier, display a prominent warning. All operations may affect live data. Ask for explicit confirmation before continuing.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Phase 3: MCP Wiring
|
|
170
|
+
|
|
171
|
+
### Step 3.1: Check current configuration
|
|
172
|
+
|
|
173
|
+
Read `.mcp.json` in the workspace root. Check if it already targets the selected profile and retailer:
|
|
174
|
+
|
|
175
|
+
- `mcpServers["fluent-mcp"].env.FLUENT_PROFILE` matches selected profile?
|
|
176
|
+
- `mcpServers["fluent-mcp-extn"].env.FLUENT_PROFILE` matches selected profile?
|
|
177
|
+
- `mcpServers["fluent-mcp-extn"].env.FLUENT_PROFILE_RETAILER` matches selected retailer ref?
|
|
178
|
+
|
|
179
|
+
**If already configured correctly:** Report "Already connected to <PROFILE>/<RETAILER>. Validating connectivity..." and skip to Step 3.4.
|
|
180
|
+
|
|
181
|
+
**If switching from a different profile:** Warn the user: "Currently connected to <OLD_PROFILE>. Switching to <NEW_PROFILE>."
|
|
182
|
+
|
|
183
|
+
### Step 3.2: Update .mcp.json
|
|
184
|
+
|
|
185
|
+
Run the existing mcp-setup command:
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
npx @fluentcommerce/ai-skills mcp-setup --profile <PROFILE> --profile-retailer <RETAILER_REF>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
This updates `.mcp.json` with:
|
|
192
|
+
- `fluent-mcp` server: `FLUENT_PROFILE=<PROFILE>`
|
|
193
|
+
- `fluent-mcp-extn` server: `FLUENT_PROFILE=<PROFILE>`, `FLUENT_PROFILE_RETAILER=<RETAILER_REF>`
|
|
194
|
+
|
|
195
|
+
The command uses merge semantics — it preserves existing non-conflicting env vars.
|
|
196
|
+
|
|
197
|
+
### Step 3.3: Read and verify .mcp.json
|
|
198
|
+
|
|
199
|
+
After mcp-setup completes, read `.mcp.json` and verify the three env vars from Step 3.1 are set correctly. Display the verified config to the user.
|
|
200
|
+
|
|
201
|
+
### Step 3.4: Prompt IDE reload
|
|
202
|
+
|
|
203
|
+
> **ACTION REQUIRED:** The MCP servers read environment variables at startup.
|
|
204
|
+
> You must reload the MCP servers for the new configuration to take effect.
|
|
205
|
+
>
|
|
206
|
+
> - **VS Code:** Restart the extension host or reload window
|
|
207
|
+
> - **Claude Code CLI:** Restart the session
|
|
208
|
+
> - **Cursor:** Cmd+Shift+P -> "MCP: Restart Servers"
|
|
209
|
+
>
|
|
210
|
+
> After reloading, confirm you are back and I will validate connectivity.
|
|
211
|
+
|
|
212
|
+
**WAIT for user to confirm they have reloaded before proceeding.**
|
|
213
|
+
|
|
214
|
+
### Step 3.5: Validate connectivity
|
|
215
|
+
|
|
216
|
+
After user confirms reload:
|
|
217
|
+
|
|
218
|
+
1. Run `config.validate` (MCP tool) — verify auth strategy is "profile" and no errors
|
|
219
|
+
2. Run `connection.test` (MCP tool) — verify authenticated user, retailer ID, and retailer ref match expectations
|
|
220
|
+
|
|
221
|
+
**If config.validate returns errors:**
|
|
222
|
+
- Profile load failure: check `~/.fluentcommerce/<PROFILE>/profile.json` exists and is valid JSON
|
|
223
|
+
- Auth not configured: check `.mcp.json` env vars are correct
|
|
224
|
+
- Missing retailer scope: check `FLUENT_PROFILE_RETAILER` is set
|
|
225
|
+
|
|
226
|
+
**If connection.test fails:**
|
|
227
|
+
- Auth error: credentials may be expired. Suggest `fluent profile update <PROFILE> --username <user> --password <pass>`
|
|
228
|
+
- Network error: check base URL and connectivity
|
|
229
|
+
|
|
230
|
+
Report the connection status:
|
|
231
|
+
|
|
232
|
+
```
|
|
233
|
+
MCP Connectivity: OK
|
|
234
|
+
Auth strategy: profile
|
|
235
|
+
User: <username>
|
|
236
|
+
Retailer: <RETAILER_REF> (ID: <RETAILER_ID>)
|
|
237
|
+
Base URL: https://<account>.<tier>.api.fluentretail.com
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Phase 4: Workspace Readiness
|
|
243
|
+
|
|
244
|
+
### Step 4.1: Ensure workspace directories exist
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
mkdir -p accounts/<PROFILE>/SOURCE
|
|
248
|
+
mkdir -p accounts/<PROFILE>/workflows/<RETAILER_REF>
|
|
249
|
+
mkdir -p accounts/<PROFILE>/analysis
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
```powershell
|
|
253
|
+
# PowerShell
|
|
254
|
+
New-Item -ItemType Directory -Force -Path "accounts\<PROFILE>\SOURCE", "accounts\<PROFILE>\workflows\<RETAILER_REF>", "accounts\<PROFILE>\analysis"
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Directory structure:
|
|
258
|
+
|
|
259
|
+
```
|
|
260
|
+
accounts/
|
|
261
|
+
<PROFILE>/
|
|
262
|
+
SOURCE/ <- account-level, shared across retailers
|
|
263
|
+
<repo-name>/
|
|
264
|
+
.decompiled/<jar-basename>/
|
|
265
|
+
workflows/ <- retailer-scoped workflow JSONs
|
|
266
|
+
<RETAILER_REF>/
|
|
267
|
+
ORDER__HD.json
|
|
268
|
+
analysis/ <- generated reusable artifacts
|
|
269
|
+
workspace-state.json
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
SOURCE is at the profile level because plugin code is deployed per-account (shared across retailers). Workflows are scoped by retailer ref inside the `workflows/` directory because they can differ per retailer.
|
|
273
|
+
|
|
274
|
+
These are idempotent. On Windows with Git Bash, forward slashes and `mkdir -p` work correctly.
|
|
275
|
+
|
|
276
|
+
### Step 4.2: Check and download workflows
|
|
277
|
+
|
|
278
|
+
Check if workflows directory has content:
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
ls accounts/<PROFILE>/workflows/<RETAILER_REF>/*.json 2>/dev/null | wc -l
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
```powershell
|
|
285
|
+
# PowerShell
|
|
286
|
+
(Get-ChildItem "accounts\<PROFILE>\workflows\<RETAILER_REF>\*.json" -ErrorAction SilentlyContinue).Count
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
**If empty (count is 0):**
|
|
290
|
+
|
|
291
|
+
**Preferred: MCP-based download (cross-platform, avoids `::` filename issue):**
|
|
292
|
+
|
|
293
|
+
```
|
|
294
|
+
1. workflow.list(profile: "<PROFILE>", retailer: "<RETAILER_REF>")
|
|
295
|
+
→ get all workflow names (e.g., ORDER::HD, FULFILMENT::HD_WH)
|
|
296
|
+
|
|
297
|
+
2. For each workflow name:
|
|
298
|
+
a. workflow.download(profile: "<PROFILE>", retailer: "<RETAILER_REF>", workflow: "<NAME>")
|
|
299
|
+
→ returns full JSON content in response (no file written)
|
|
300
|
+
b. Sanitize filename: replace :: with __ (e.g., ORDER::HD → ORDER__HD.json)
|
|
301
|
+
c. Write JSON content to accounts/<PROFILE>/workflows/<RETAILER_REF>/<SANITIZED_NAME>.json
|
|
302
|
+
|
|
303
|
+
3. Write workflow-file-map.json mapping original names to sanitized filenames:
|
|
304
|
+
{ "ORDER::HD": "ORDER__HD.json", "FULFILMENT::HD_WH": "FULFILMENT__HD_WH.json" }
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
This approach works identically on Windows, macOS, and Linux because `::` never appears in a filename.
|
|
308
|
+
|
|
309
|
+
**Fallback: CLI download (if MCP servers not yet connected):**
|
|
310
|
+
|
|
311
|
+
On macOS/Linux (`::` is valid in filenames):
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
fluent workflow list -p <PROFILE> -r <RETAILER_REF>
|
|
315
|
+
fluent workflow download -p <PROFILE> -r <RETAILER_REF> -w all -o accounts/<PROFILE>/workflows/<RETAILER_REF>/
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
On Windows (both `-w <name>` and `-w all` fail because the CLI writes `ORDER::HD.json` and `:` is reserved):
|
|
319
|
+
|
|
320
|
+
```bash
|
|
321
|
+
fluent workflow download -p <PROFILE> -r <RETAILER_REF> -w all --json > accounts/<PROFILE>/workflows/<RETAILER_REF>/workflows-raw.json
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
Then split into one file per workflow with sanitized names (replace `::` with `__`) and persist `workflow-file-map.json` mapping original workflow name to filename.
|
|
325
|
+
|
|
326
|
+
Write/update workflow context:
|
|
327
|
+
|
|
328
|
+
`accounts/<PROFILE>/workflows/<RETAILER_REF>/workflow-context.json`
|
|
329
|
+
|
|
330
|
+
```json
|
|
331
|
+
{
|
|
332
|
+
"profile": "<PROFILE>",
|
|
333
|
+
"retailerRef": "<RETAILER_REF>",
|
|
334
|
+
"retailerId": "<RETAILER_ID>",
|
|
335
|
+
"downloadedAt": "<ISO-8601>"
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
Note: `-r` expects retailer **ref** (e.g., `MY_RETAILER`), not retailer ID.
|
|
340
|
+
|
|
341
|
+
**If workflows already exist:**
|
|
342
|
+
|
|
343
|
+
Report count and freshness. If most recent file is older than 7 days, suggest re-downloading:
|
|
344
|
+
|
|
345
|
+
```bash
|
|
346
|
+
ls -lt accounts/<PROFILE>/workflows/<RETAILER_REF>/*.json | head -5
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
```powershell
|
|
350
|
+
# PowerShell
|
|
351
|
+
Get-ChildItem "accounts\<PROFILE>\workflows\<RETAILER_REF>\*.json" | Sort-Object LastWriteTime -Descending | Select-Object -First 5
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
If `workflow-context.json` exists, verify `profile` + `retailerRef` match the active target. If mismatched, re-download workflows into the correct retailer folder and overwrite context.
|
|
355
|
+
|
|
356
|
+
### Step 4.3: Check source code
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
ls accounts/<PROFILE>/SOURCE/ 2>/dev/null
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
```powershell
|
|
363
|
+
# PowerShell
|
|
364
|
+
Get-ChildItem "accounts\<PROFILE>\SOURCE" -ErrorAction SilentlyContinue
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
**If repos with Java source found:**
|
|
368
|
+
|
|
369
|
+
Report discovered repos. Validate each has expected structure (`module.json`, `pom.xml`, or `src/main/java/`).
|
|
370
|
+
|
|
371
|
+
**Extract module identity (version + symbolic name):**
|
|
372
|
+
|
|
373
|
+
For each discovered repo, extract identity using this precedence:
|
|
374
|
+
|
|
375
|
+
`symbolicName`:
|
|
376
|
+
1. `resources/module.json` → `name` field (preferred)
|
|
377
|
+
2. JAR `META-INF/MANIFEST.MF` → `Bundle-SymbolicName` (if present)
|
|
378
|
+
3. POM fallback → `<groupId>/<artifactId>` (or `<artifactId>` alone if `groupId` missing)
|
|
379
|
+
|
|
380
|
+
`version`:
|
|
381
|
+
1. `resources/module.json` → `version` field (preferred)
|
|
382
|
+
2. POM → `<project><version>` (fallback to `<project><parent><version>` if module version is omitted or inherited)
|
|
383
|
+
3. JAR manifest → `Implementation-Version` or `Bundle-Version`
|
|
384
|
+
|
|
385
|
+
POM extraction examples:
|
|
386
|
+
|
|
387
|
+
```xml
|
|
388
|
+
<!-- Direct version -->
|
|
389
|
+
<project>
|
|
390
|
+
<groupId>com.fluentcommerce</groupId>
|
|
391
|
+
<artifactId>fc-module-extensions</artifactId>
|
|
392
|
+
<version>1.2.3</version>
|
|
393
|
+
<name>FC Module Extensions</name>
|
|
394
|
+
</project>
|
|
395
|
+
|
|
396
|
+
<!-- Inherited version (no <version> at project level) -->
|
|
397
|
+
<project>
|
|
398
|
+
<parent>
|
|
399
|
+
<version>1.2.3</version>
|
|
400
|
+
</parent>
|
|
401
|
+
<artifactId>fc-module-extensions</artifactId>
|
|
402
|
+
</project>
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
Record where each value came from (e.g., `versionSource: "module.json"` or `versionSource: "pom.parent.version"`) for traceability.
|
|
406
|
+
|
|
407
|
+
Report format (classify each by type):
|
|
408
|
+
|
|
409
|
+
```
|
|
410
|
+
Source code:
|
|
411
|
+
Custom Extension (editable, buildable):
|
|
412
|
+
- <repo-name-1>/ <symbolic-name> v<X.Y.Z> (N rules, Maven)
|
|
413
|
+
Configuration-Only (editable, not buildable):
|
|
414
|
+
- <repo-name-2>/ <symbolic-name> v<X.Y.Z> (workflows + settings, no rules)
|
|
415
|
+
Reference Modules (read-only):
|
|
416
|
+
- <module-name>/ <symbolic-name> v<X.Y.Z> (N OOTB rules, JAR)
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
**Handle double-nested git clone directories:**
|
|
420
|
+
If a directory under SOURCE contains only one subdirectory with a similar name (e.g., `<repo>/<repo>/`), treat the inner directory as the actual module root. This is a common git clone artifact.
|
|
421
|
+
|
|
422
|
+
**If reference module packages found (module.json + JAR):**
|
|
423
|
+
|
|
424
|
+
Reference modules have both `module.json` (with full rule metadata) and compiled JARs under `assets/rules/`. Read rule names, descriptions, and version from `module.json` directly — no decompilation needed for metadata. Only decompile if deep analysis of rule implementation logic is requested.
|
|
425
|
+
|
|
426
|
+
**If only standalone JAR files found (no module.json alongside):**
|
|
427
|
+
|
|
428
|
+
When a module is deployed but the original source code is not available, look for `.jar` files under `SOURCE/`. If a JAR is found, decompile it to produce browsable source for analysis:
|
|
429
|
+
|
|
430
|
+
1. **Locate JARs:**
|
|
431
|
+
|
|
432
|
+
Use `Glob` with pattern `accounts/<PROFILE>/SOURCE/**/*.jar` for cross-platform file discovery. Exclude `target/dependency/` results.
|
|
433
|
+
|
|
434
|
+
```bash
|
|
435
|
+
find accounts/<PROFILE>/SOURCE/ -name "*.jar" -not -path "*/target/dependency/*" 2>/dev/null
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
```powershell
|
|
439
|
+
# PowerShell
|
|
440
|
+
Get-ChildItem "accounts\<PROFILE>\SOURCE" -Recurse -Filter "*.jar" | Where-Object { $_.FullName -notlike "*\target\dependency\*" }
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
2. **Auto-download CFR decompiler if not present, then decompile:**
|
|
444
|
+
|
|
445
|
+
> **Cross-platform note:** The decompilation commands below use bash syntax (`mkdir -p`, `curl`). On Windows, use Git Bash, WSL, or the PowerShell equivalents shown where available. The `java -jar` and `jar tf` commands work identically on all platforms.
|
|
446
|
+
|
|
447
|
+
```bash
|
|
448
|
+
# Auto-download CFR (~2MB single JAR, no installation needed)
|
|
449
|
+
if [ ! -f tools/cfr.jar ]; then
|
|
450
|
+
mkdir -p tools
|
|
451
|
+
curl -L -o tools/cfr.jar "https://github.com/leibnitz27/cfr/releases/download/0.152/cfr-0.152.jar"
|
|
452
|
+
fi
|
|
453
|
+
|
|
454
|
+
# Create deterministic decompiled output directory
|
|
455
|
+
mkdir -p accounts/<PROFILE>/SOURCE/.decompiled/<jar-basename>
|
|
456
|
+
|
|
457
|
+
# Option A: CFR with --jarfilter to extract only rule classes (preferred)
|
|
458
|
+
java -jar tools/cfr.jar "<jar-file>.jar" \
|
|
459
|
+
--outputdir "accounts/<PROFILE>/SOURCE/.decompiled/<jar-basename>" \
|
|
460
|
+
--jarfilter "com.fluentcommerce.rule"
|
|
461
|
+
|
|
462
|
+
# Option B: CFR full decompilation (all classes)
|
|
463
|
+
java -jar tools/cfr.jar "<jar-file>.jar" \
|
|
464
|
+
--outputdir "accounts/<PROFILE>/SOURCE/.decompiled/<jar-basename>"
|
|
465
|
+
|
|
466
|
+
# Option C: Fernflower (IntelliJ's built-in decompiler)
|
|
467
|
+
java -jar fernflower.jar <jar-file>.jar accounts/<PROFILE>/SOURCE/.decompiled/<jar-basename>
|
|
468
|
+
|
|
469
|
+
# Option D: If neither is available, use javap for class listing
|
|
470
|
+
jar tf <jar-file>.jar | grep "\.class$"
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
```powershell
|
|
474
|
+
# PowerShell — auto-download CFR
|
|
475
|
+
if (-not (Test-Path "tools\cfr.jar")) {
|
|
476
|
+
New-Item -ItemType Directory -Force -Path "tools"
|
|
477
|
+
Invoke-WebRequest -Uri "https://github.com/leibnitz27/cfr/releases/download/0.152/cfr-0.152.jar" -OutFile "tools\cfr.jar"
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
# CFR with --jarfilter
|
|
481
|
+
java -jar tools/cfr.jar "<jar-file>.jar" --outputdir "accounts\<PROFILE>\SOURCE\.decompiled\<jar-basename>" --jarfilter "com.fluentcommerce.rule"
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
The `--jarfilter` flag restricts decompilation to classes matching the package prefix, keeping output focused on rule logic. If no decompiler is available and `curl`/Java is missing, log a warning and skip decompilation. Record JAR paths for later.
|
|
485
|
+
|
|
486
|
+
3. **Extract module.json from the JAR** (if present):
|
|
487
|
+
|
|
488
|
+
```bash
|
|
489
|
+
unzip -p <jar-file>.jar module.json > accounts/<PROFILE>/SOURCE/.decompiled/<jar-basename>/module.json
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
```powershell
|
|
493
|
+
# PowerShell
|
|
494
|
+
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
|
495
|
+
$jar = [System.IO.Compression.ZipFile]::OpenRead("<jar-file>.jar")
|
|
496
|
+
$entry = $jar.GetEntry("module.json")
|
|
497
|
+
if ($entry) {
|
|
498
|
+
$stream = $entry.Open()
|
|
499
|
+
$reader = New-Object System.IO.StreamReader($stream)
|
|
500
|
+
$reader.ReadToEnd() | Set-Content "accounts\<PROFILE>\SOURCE\.decompiled\<jar-basename>\module.json"
|
|
501
|
+
$reader.Close(); $stream.Close()
|
|
502
|
+
}
|
|
503
|
+
$jar.Dispose()
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
4. **Create a `DECOMPILED.md` marker file** in the decompiled output directory:
|
|
507
|
+
|
|
508
|
+
```markdown
|
|
509
|
+
# Decompiled Source
|
|
510
|
+
|
|
511
|
+
- **Source JAR:** <jar-filename>.jar
|
|
512
|
+
- **Decompiled on:** <date>
|
|
513
|
+
- **Decompiler:** CFR / Fernflower / javap
|
|
514
|
+
- **Note:** This is decompiled bytecode, not original source. Variable names may be synthetic. Comments and annotations may be incomplete.
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
After decompilation, `/fluent-custom-code` can analyze the decompiled classes for rule discovery, workflow-rule mapping, and behavior explanation.
|
|
518
|
+
|
|
519
|
+
> **Decompilation limitations:**
|
|
520
|
+
> - Local variable names may be replaced with synthetic names (`var1`, `var2`)
|
|
521
|
+
> - Comments, Javadoc, and some annotations may be lost
|
|
522
|
+
> - Generic type information may be partially erased
|
|
523
|
+
> - Confidence label should be "low-medium" for decompiled source vs "high" for original
|
|
524
|
+
|
|
525
|
+
**If neither source nor JAR found:**
|
|
526
|
+
|
|
527
|
+
> No custom source code or JAR files found under `accounts/<PROFILE>/SOURCE/`.
|
|
528
|
+
> This is not blocking — it means no custom plugins are available for analysis.
|
|
529
|
+
>
|
|
530
|
+
> Options:
|
|
531
|
+
> 1. Clone source repos: `git clone <repo-url>` into `accounts/<PROFILE>/SOURCE/`
|
|
532
|
+
> 2. Copy module JARs: place `.jar` files in `accounts/<PROFILE>/SOURCE/` for decompilation
|
|
533
|
+
> 3. Download from Fluent: if the module is deployed, the JAR may be retrievable from the build artifacts
|
|
534
|
+
|
|
535
|
+
### Step 4.4: Build deployed rule inventory
|
|
536
|
+
|
|
537
|
+
Query the live environment for the complete picture of what's deployed.
|
|
538
|
+
|
|
539
|
+
**4.4a: Query deployed custom rules**
|
|
540
|
+
|
|
541
|
+
Use the MCP `plugin.list` tool to get all registered orchestration rules. Filter for account-specific rules (prefixed with the account context, not `FLUENTRETAIL.*`):
|
|
542
|
+
|
|
543
|
+
```
|
|
544
|
+
plugin.list → N total rules
|
|
545
|
+
- FLUENTRETAIL.* → platform rules (standard, no source needed)
|
|
546
|
+
- <ACCOUNT>.* → custom rules (these need source or JARs)
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
**4.4b: Cross-reference deployed vs local**
|
|
550
|
+
|
|
551
|
+
For each custom rule discovered in the live registry:
|
|
552
|
+
|
|
553
|
+
| Deployed Rule | Local Source? | Local JAR? | Status |
|
|
554
|
+
|---------------|--------------|------------|--------|
|
|
555
|
+
| `<ACCOUNT>.<module>.<RuleName>` | `SOURCE/<repo>/...RuleName.java` | - | Full source |
|
|
556
|
+
| `<ACCOUNT>.<module>.<OtherRule>` | - | `SOURCE/<module>.jar` | Decompiled |
|
|
557
|
+
| `<ACCOUNT>.<module>.<UnknownRule>` | - | - | **Missing** |
|
|
558
|
+
|
|
559
|
+
**4.4c: Report the inventory**
|
|
560
|
+
|
|
561
|
+
```
|
|
562
|
+
Deployed Rule Inventory:
|
|
563
|
+
Total custom rules deployed: N
|
|
564
|
+
With full source code: X (modifiable)
|
|
565
|
+
With decompiled source (JAR): Y (read-only, can analyze)
|
|
566
|
+
Missing (no source or JAR): Z (cannot analyze)
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
**4.4d: Recommendations based on inventory**
|
|
570
|
+
|
|
571
|
+
- **Full source** modules: ready for analysis, modification, and redeployment. Use `/fluent-custom-code` for deep analysis, `/fluent-rule-scaffold` to add new rules, `/fluent-build` to compile.
|
|
572
|
+
- **JAR-only** modules: can analyze behavior via decompiled source. Cannot modify directly. Recommend cloning original source or scaffolding a new extension module.
|
|
573
|
+
- **Missing** modules: flag as a gap. Ask the user to provide the source or JAR.
|
|
574
|
+
|
|
575
|
+
> **Important:** JAR-decompiled source is read-only for analysis. Never suggest editing decompiled files.
|
|
576
|
+
|
|
577
|
+
### Step 4.5: Entity count queries
|
|
578
|
+
|
|
579
|
+
Run lightweight discovery queries to understand what's configured:
|
|
580
|
+
|
|
581
|
+
```graphql
|
|
582
|
+
{ locations(first: 1) { edges { node { id } } pageInfo { hasNextPage } } }
|
|
583
|
+
{ networks(first: 1) { edges { node { id } } pageInfo { hasNextPage } } }
|
|
584
|
+
{ inventoryCatalogues(first: 1) { edges { node { id } } pageInfo { hasNextPage } } }
|
|
585
|
+
{ productCatalogues(first: 1) { edges { node { id } } pageInfo { hasNextPage } } }
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
Record presence/absence and approximate counts.
|
|
589
|
+
|
|
590
|
+
### Step 4.6: Check analysis artifacts
|
|
591
|
+
|
|
592
|
+
```bash
|
|
593
|
+
ls accounts/<PROFILE>/analysis/ 2>/dev/null
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
```powershell
|
|
597
|
+
# PowerShell
|
|
598
|
+
Get-ChildItem "accounts\<PROFILE>\analysis" -ErrorAction SilentlyContinue
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
If artifacts exist (e.g., `custom-code/source-map.json`, `module-validate/*.report.json`), report their age and freshness. If no artifacts exist, note it as a future step.
|
|
602
|
+
|
|
603
|
+
If the user explicitly asked for source analysis/readiness artifacts, run `/fluent-custom-code <PROFILE> --retailer <RETAILER_REF>` now instead of deferring.
|
|
604
|
+
|
|
605
|
+
---
|
|
606
|
+
|
|
607
|
+
## Phase 5: Persist State and Report
|
|
608
|
+
|
|
609
|
+
### Step 5.1: Write per-profile state
|
|
610
|
+
|
|
611
|
+
Write `accounts/<PROFILE>/workspace-state.json`:
|
|
612
|
+
|
|
613
|
+
```json
|
|
614
|
+
{
|
|
615
|
+
"schema": "workspace-state-v1",
|
|
616
|
+
"profile": "<PROFILE>",
|
|
617
|
+
"contentHash": "<sha256-hex>",
|
|
618
|
+
"createdAt": "<ISO-8601>",
|
|
619
|
+
"updatedAt": "<ISO-8601>",
|
|
620
|
+
"environment": {
|
|
621
|
+
"account": "<account-name>",
|
|
622
|
+
"tier": "<test|sandbox|production>",
|
|
623
|
+
"baseUrl": "<base-url>",
|
|
624
|
+
"retailerRef": "<RETAILER_REF>",
|
|
625
|
+
"retailerId": "<RETAILER_ID>"
|
|
626
|
+
},
|
|
627
|
+
"discovery": {
|
|
628
|
+
"workflows": { "count": 0, "downloaded": true, "path": "accounts/<PROFILE>/workflows/<RETAILER_REF>" },
|
|
629
|
+
"modules": { "installed": [], "count": 0 },
|
|
630
|
+
"sourceRepos": [
|
|
631
|
+
{ "name": "<repo-name>", "symbolicName": "<symbolic-name>", "version": "<X.Y.Z>", "versionSource": "<module.json|pom|pom.parent>", "hasModuleJson": true, "ruleCount": 0 }
|
|
632
|
+
],
|
|
633
|
+
"decompiledRepos": [],
|
|
634
|
+
"entities": { "locations": 0, "networks": 0, "inventoryCatalogues": 0, "productCatalogues": 0 },
|
|
635
|
+
"ruleInventory": { "total": 0, "withSource": 0, "withJar": 0, "missing": 0 },
|
|
636
|
+
"connectivity": { "status": "OK", "user": "<username>", "retailer": "<tradingName>" }
|
|
637
|
+
},
|
|
638
|
+
"mcpConfig": { "exists": true, "hasOfficialServer": true, "hasExtensionServer": true, "profileMatch": true },
|
|
639
|
+
"nextSteps": []
|
|
640
|
+
}
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
### Step 5.2: Write/merge workspace index
|
|
644
|
+
|
|
645
|
+
Write or merge into `accounts/workspace-index.json`:
|
|
646
|
+
|
|
647
|
+
```json
|
|
648
|
+
{
|
|
649
|
+
"schema": "workspace-index-v1",
|
|
650
|
+
"updatedAt": "<ISO-8601>",
|
|
651
|
+
"profiles": {
|
|
652
|
+
"<PROFILE>": {
|
|
653
|
+
"status": "READY",
|
|
654
|
+
"retailer": "<RETAILER_REF>",
|
|
655
|
+
"account": "<account-name>",
|
|
656
|
+
"tier": "<tier>",
|
|
657
|
+
"stateHash": "<sha256-hex>"
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
If the index already exists, read it first and merge the new profile entry. Do not overwrite other profiles.
|
|
664
|
+
|
|
665
|
+
### Step 5.3: Readiness report
|
|
666
|
+
|
|
667
|
+
Present a comprehensive summary:
|
|
668
|
+
|
|
669
|
+
```
|
|
670
|
+
================================================================
|
|
671
|
+
FLUENT CONNECT: Readiness Report
|
|
672
|
+
================================================================
|
|
673
|
+
|
|
674
|
+
Profile: <PROFILE>
|
|
675
|
+
Account: <account> (<tier>)
|
|
676
|
+
Retailer: <RETAILER_REF> (ID: <RETAILER_ID>)
|
|
677
|
+
User: <username>
|
|
678
|
+
|
|
679
|
+
MCP Status:
|
|
680
|
+
fluent-mcp [OK] Profile auth
|
|
681
|
+
fluent-mcp-extn [OK] Profile auth + retailer scope
|
|
682
|
+
|
|
683
|
+
Workspace:
|
|
684
|
+
Workflows [OK] N files
|
|
685
|
+
Source code [OK] X repos (Y rules with full source)
|
|
686
|
+
JARs [OK] Z decompiled (W rules, read-only)
|
|
687
|
+
Analysis [--] No artifacts yet
|
|
688
|
+
|
|
689
|
+
Modules:
|
|
690
|
+
<symbolic-name-1> v<X.Y.Z> (N rules, source)
|
|
691
|
+
<symbolic-name-2> v<X.Y.Z> (M rules, decompiled)
|
|
692
|
+
|
|
693
|
+
Deployed Rule Inventory:
|
|
694
|
+
Custom rules deployed: N
|
|
695
|
+
With full source: X [modifiable]
|
|
696
|
+
With decompiled JAR: Y [analyzable, read-only]
|
|
697
|
+
Missing source: Z [blind spot]
|
|
698
|
+
|
|
699
|
+
Entities:
|
|
700
|
+
Locations: N
|
|
701
|
+
Networks: N
|
|
702
|
+
Catalogues: N (inventory) / N (product)
|
|
703
|
+
|
|
704
|
+
Suggested Next Steps:
|
|
705
|
+
1. Full analysis: /fluent-custom-code
|
|
706
|
+
2. Workflow deep-dive: /fluent-workflow-analyzer
|
|
707
|
+
3. Create test data: /fluent-test-data
|
|
708
|
+
4. Run E2E tests: /fluent-e2e-test
|
|
709
|
+
5. RFL assessment: /fluent-rfl-assess
|
|
710
|
+
|
|
711
|
+
Workspace: accounts/<PROFILE>/ (source shared, retailer content under <RETAILER_REF>/)
|
|
712
|
+
State saved to: accounts/<PROFILE>/workspace-state.json
|
|
713
|
+
================================================================
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
### Capability Matrix
|
|
717
|
+
|
|
718
|
+
| Capability | Requires | Status Logic |
|
|
719
|
+
|-----------|----------|-------------|
|
|
720
|
+
| GraphQL operations | MCP connected | `connection.test` OK |
|
|
721
|
+
| Event dispatch | MCP connected + retailer scope | connection OK + retailerId present |
|
|
722
|
+
| Workflow analysis | Workflows downloaded | workflow JSON count > 0 |
|
|
723
|
+
| Full code analysis | Source repos present | `SOURCE/` has repos with `src/main/java/` |
|
|
724
|
+
| JAR-based analysis | Decompiled JARs present | `SOURCE/.decompiled/*/` exists |
|
|
725
|
+
| Code + workflow cross-ref | Workflows + any source | workflows + (source or decompiled) |
|
|
726
|
+
| Rule modification | Full source available | repo has original Java + pom.xml |
|
|
727
|
+
| Analysis reuse | Artifacts exist + fresh | `analysis/` has files and not stale |
|
|
728
|
+
| Complete rule coverage | All deployed rules have source | no "missing" in inventory |
|
|
729
|
+
|
|
730
|
+
### Blocked Capabilities
|
|
731
|
+
|
|
732
|
+
If any capability is blocked, explain what's needed and how to fix it.
|
|
733
|
+
|
|
734
|
+
---
|
|
735
|
+
|
|
736
|
+
## Content Hash
|
|
737
|
+
|
|
738
|
+
The content hash determines whether workspace state is current. Recompute on every run and compare with the stored hash.
|
|
739
|
+
|
|
740
|
+
### What to hash
|
|
741
|
+
|
|
742
|
+
1. **Profile config:** `~/.fluentcommerce/<PROFILE>/profile.json`
|
|
743
|
+
2. **Retailer configs:** all `~/.fluentcommerce/<PROFILE>/retailer.*.json` files
|
|
744
|
+
3. **Source repo listing:** sorted list of directory names under `accounts/<PROFILE>/SOURCE/`
|
|
745
|
+
4. **Workflow file listing:** sorted list of `.json` filenames in `accounts/<PROFILE>/workflows/<RETAILER_REF>/`
|
|
746
|
+
5. **JAR/ZIP listing:** sorted list of `.jar` and `.zip` files under `accounts/<PROFILE>/SOURCE/`
|
|
747
|
+
|
|
748
|
+
### How to compute
|
|
749
|
+
|
|
750
|
+
Use Node.js (always available):
|
|
751
|
+
|
|
752
|
+
```bash
|
|
753
|
+
node -e "
|
|
754
|
+
const crypto = require('crypto');
|
|
755
|
+
const fs = require('fs');
|
|
756
|
+
const path = require('path');
|
|
757
|
+
const h = crypto.createHash('sha256');
|
|
758
|
+
const profile = process.argv[1];
|
|
759
|
+
const home = process.env.HOME || process.env.USERPROFILE;
|
|
760
|
+
|
|
761
|
+
// 1. Profile config
|
|
762
|
+
const profFile = path.join(home, '.fluentcommerce', profile, 'profile.json');
|
|
763
|
+
if (fs.existsSync(profFile)) h.update(fs.readFileSync(profFile));
|
|
764
|
+
|
|
765
|
+
// 2. Retailer configs
|
|
766
|
+
const profDir = path.join(home, '.fluentcommerce', profile);
|
|
767
|
+
if (fs.existsSync(profDir)) {
|
|
768
|
+
fs.readdirSync(profDir).filter(f => f.startsWith('retailer.') && f.endsWith('.json')).sort()
|
|
769
|
+
.forEach(f => h.update(fs.readFileSync(path.join(profDir, f))));
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
// 3. Source repo listing
|
|
773
|
+
const srcDir = path.join('accounts', profile, 'SOURCE');
|
|
774
|
+
if (fs.existsSync(srcDir)) {
|
|
775
|
+
fs.readdirSync(srcDir, {withFileTypes:true}).filter(e => e.isDirectory()).map(e => e.name).sort()
|
|
776
|
+
.forEach(n => h.update('src:' + n));
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
// 4. Workflow file listing (retailer-scoped)
|
|
780
|
+
const retailer = process.argv[2];
|
|
781
|
+
const wfDir = path.join('accounts', profile, 'workflows', retailer);
|
|
782
|
+
if (fs.existsSync(wfDir)) {
|
|
783
|
+
fs.readdirSync(wfDir).filter(f => f.endsWith('.json')).sort()
|
|
784
|
+
.forEach(f => h.update('wf:' + f));
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
// 5. JAR/ZIP listing
|
|
788
|
+
if (fs.existsSync(srcDir)) {
|
|
789
|
+
const jars = [];
|
|
790
|
+
function findJars(d) {
|
|
791
|
+
for (const e of fs.readdirSync(d, {withFileTypes:true})) {
|
|
792
|
+
if (['target','dist','node_modules','.git'].includes(e.name)) continue;
|
|
793
|
+
const f = path.join(d, e.name);
|
|
794
|
+
if (e.isDirectory()) findJars(f);
|
|
795
|
+
else if (e.name.endsWith('.jar') || e.name.endsWith('.zip')) jars.push(f.replace(/\\\\/g,'/'));
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
findJars(srcDir);
|
|
799
|
+
jars.sort().forEach(j => h.update('jar:' + j));
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
console.log(h.digest('hex'));
|
|
803
|
+
" <PROFILE> <RETAILER_REF>
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
Any change (new workflow download, new repo clone, profile update, new JAR file) produces a new hash and triggers a re-run.
|
|
807
|
+
|
|
808
|
+
---
|
|
809
|
+
|
|
810
|
+
## Idempotency
|
|
811
|
+
|
|
812
|
+
This skill is designed to be run multiple times safely:
|
|
813
|
+
|
|
814
|
+
1. **Cached state matches:** If content hash hasn't changed, print summary and stop immediately.
|
|
815
|
+
2. **Already configured:** If `.mcp.json` already targets the correct profile/retailer, skip mcp-setup. Still validate connectivity.
|
|
816
|
+
3. **Directories exist:** `mkdir -p` is idempotent.
|
|
817
|
+
4. **Workflows downloaded:** Report count and freshness. Do not re-download unless user requests or `--force` is used.
|
|
818
|
+
5. **Source cloned:** Report repos found. Do not modify.
|
|
819
|
+
6. **Artifacts exist:** Report age. Do not regenerate.
|
|
820
|
+
|
|
821
|
+
### Switching Accounts
|
|
822
|
+
|
|
823
|
+
When the user runs `/fluent-connect` with a different profile than currently configured:
|
|
824
|
+
|
|
825
|
+
1. Detect the mismatch by reading `.mcp.json` first
|
|
826
|
+
2. Warn: "Currently connected to <OLD_PROFILE>. Switching to <NEW_PROFILE>."
|
|
827
|
+
3. Run mcp-setup with the new profile
|
|
828
|
+
4. Require IDE reload
|
|
829
|
+
5. Validate the new connection
|
|
830
|
+
6. Persist new workspace state
|
|
831
|
+
7. Report readiness for the new account
|
|
832
|
+
|
|
833
|
+
---
|
|
834
|
+
|
|
835
|
+
## Error Handling
|
|
836
|
+
|
|
837
|
+
| Phase | Error | Resolution |
|
|
838
|
+
|-------|-------|-----------|
|
|
839
|
+
| 0 | workspace-state.json corrupted | Delete and re-run full discovery |
|
|
840
|
+
| 1 | No profiles exist | Delegate to `/fluent-profile` |
|
|
841
|
+
| 1 | `fluent` CLI not found | Install: `npm i -g @fluentcommerce/cli` |
|
|
842
|
+
| 2 | No retailers for profile | Register via `fluent profile update` or `/fluent-cli-retailer` |
|
|
843
|
+
| 3 | mcp-setup fails | Check `npx @fluentcommerce/ai-skills --help` works and retry mcp-setup |
|
|
844
|
+
| 3 | connection.test auth failure | Update credentials: `fluent profile update <PROFILE> --username <user> --password <pass>` |
|
|
845
|
+
| 3 | connection.test network error | Verify base URL and network access |
|
|
846
|
+
| 4 | Workflow download fails | Check profile/retailer context. May need `fluent profile use <PROFILE> --retailer <REF>` first |
|
|
847
|
+
| 4 | Decompiler not found | Log warning with install instructions. Skip decompilation, record JAR paths for later. |
|
|
848
|
+
| 4 | Permission error on mkdir | Check workspace write permissions |
|
|
849
|
+
|
|
850
|
+
## Delegation Table
|
|
851
|
+
|
|
852
|
+
| Situation | Delegate To |
|
|
853
|
+
|-----------|------------|
|
|
854
|
+
| No profiles exist | `/fluent-profile` |
|
|
855
|
+
| Need to create new account | `/fluent-bootstrap` |
|
|
856
|
+
| Need to create retailer | `/fluent-cli-retailer` |
|
|
857
|
+
| MCP tool reference | `/fluent-mcp-tools` |
|
|
858
|
+
| Workflow deep analysis | `/fluent-workflow-analyzer` |
|
|
859
|
+
| Source code analysis | `/fluent-custom-code` |
|
|
860
|
+
| Settings management | `/fluent-settings` |
|
|
861
|
+
| Test data creation | `/fluent-test-data` |
|
|
862
|
+
|
|
863
|
+
## Cross-Platform Compatibility
|
|
864
|
+
|
|
865
|
+
All commands in this skill are shown in both **Bash** (macOS/Linux/Git Bash on Windows) and **PowerShell** (native Windows) where they differ. Commands that are identical on all platforms (e.g., `fluent profile list`, `node -e`, `npx`) are shown once.
|
|
866
|
+
|
|
867
|
+
**Shell detection:** AI agents should check `process.platform` (Node.js) or `$PSVersionTable` (PowerShell) to pick the right variant. In Claude Code on Windows, the shell is Git Bash so POSIX syntax works.
|
|
868
|
+
|
|
869
|
+
### Path reference
|
|
870
|
+
|
|
871
|
+
| Bash | PowerShell | Notes |
|
|
872
|
+
|------|-----------|-------|
|
|
873
|
+
| `~/.fluentcommerce/` | `$env:USERPROFILE\.fluentcommerce\` | Home directory |
|
|
874
|
+
| `2>/dev/null` | `-ErrorAction SilentlyContinue` | Suppress errors |
|
|
875
|
+
| `mkdir -p <path>` | `New-Item -ItemType Directory -Force -Path <path>` | Create nested dirs |
|
|
876
|
+
| `ls <path>` | `Get-ChildItem <path>` | List directory |
|
|
877
|
+
| `ls <path> \| wc -l` | `(Get-ChildItem <path>).Count` | Count files |
|
|
878
|
+
| `ls -lt <path> \| head -5` | `Get-ChildItem <path> \| Sort-Object LastWriteTime -Descending \| Select-Object -First 5` | Most recent files |
|
|
879
|
+
| `find <path> -name "*.jar"` | `Get-ChildItem <path> -Recurse -Filter "*.jar"` | Recursive file search |
|
|
880
|
+
| `unzip -p file.jar entry` | `[System.IO.Compression.ZipFile]::OpenRead(...)` | Extract from JAR/ZIP |
|
|
881
|
+
|
|
882
|
+
### Windows-specific notes
|
|
883
|
+
|
|
884
|
+
- The `fluent` CLI must be in PATH.
|
|
885
|
+
- Workflow filenames may fail on Windows when names include reserved characters (for example `::`); use `--json` export + filename normalization fallback.
|
|
886
|
+
- `java`, `mvn`, and `jar` commands work identically on all platforms if installed and in PATH.
|