@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.
Files changed (60) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +622 -0
  3. package/bin/cli.mjs +1973 -0
  4. package/content/cli/agents/fluent-cli/agent.json +149 -0
  5. package/content/cli/agents/fluent-cli.md +132 -0
  6. package/content/cli/skills/fluent-bootstrap/SKILL.md +181 -0
  7. package/content/cli/skills/fluent-cli-index/SKILL.md +63 -0
  8. package/content/cli/skills/fluent-cli-mcp-cicd/SKILL.md +77 -0
  9. package/content/cli/skills/fluent-cli-reference/SKILL.md +1031 -0
  10. package/content/cli/skills/fluent-cli-retailer/SKILL.md +85 -0
  11. package/content/cli/skills/fluent-cli-settings/SKILL.md +106 -0
  12. package/content/cli/skills/fluent-connect/SKILL.md +886 -0
  13. package/content/cli/skills/fluent-module-deploy/SKILL.md +349 -0
  14. package/content/cli/skills/fluent-profile/SKILL.md +180 -0
  15. package/content/cli/skills/fluent-workflow/SKILL.md +310 -0
  16. package/content/dev/agents/fluent-dev/agent.json +88 -0
  17. package/content/dev/agents/fluent-dev.md +525 -0
  18. package/content/dev/reference-modules/catalog.json +4754 -0
  19. package/content/dev/skills/fluent-build/SKILL.md +192 -0
  20. package/content/dev/skills/fluent-connection-analysis/SKILL.md +386 -0
  21. package/content/dev/skills/fluent-custom-code/SKILL.md +895 -0
  22. package/content/dev/skills/fluent-data-module-scaffold/SKILL.md +714 -0
  23. package/content/dev/skills/fluent-e2e-test/SKILL.md +394 -0
  24. package/content/dev/skills/fluent-event-api/SKILL.md +945 -0
  25. package/content/dev/skills/fluent-feature-explain/SKILL.md +603 -0
  26. package/content/dev/skills/fluent-feature-plan/PLAN_TEMPLATE.md +695 -0
  27. package/content/dev/skills/fluent-feature-plan/SKILL.md +227 -0
  28. package/content/dev/skills/fluent-job-batch/SKILL.md +138 -0
  29. package/content/dev/skills/fluent-mermaid-validate/SKILL.md +86 -0
  30. package/content/dev/skills/fluent-module-scaffold/SKILL.md +1928 -0
  31. package/content/dev/skills/fluent-module-validate/SKILL.md +775 -0
  32. package/content/dev/skills/fluent-pre-deploy-check/SKILL.md +1108 -0
  33. package/content/dev/skills/fluent-retailer-config/SKILL.md +1111 -0
  34. package/content/dev/skills/fluent-rule-scaffold/SKILL.md +385 -0
  35. package/content/dev/skills/fluent-scope-decompose/SKILL.md +1021 -0
  36. package/content/dev/skills/fluent-session-audit-export/SKILL.md +632 -0
  37. package/content/dev/skills/fluent-session-summary/SKILL.md +195 -0
  38. package/content/dev/skills/fluent-settings/SKILL.md +1058 -0
  39. package/content/dev/skills/fluent-source-onboard/SKILL.md +632 -0
  40. package/content/dev/skills/fluent-system-monitoring/SKILL.md +767 -0
  41. package/content/dev/skills/fluent-test-data/SKILL.md +513 -0
  42. package/content/dev/skills/fluent-trace/SKILL.md +1143 -0
  43. package/content/dev/skills/fluent-transition-api/SKILL.md +346 -0
  44. package/content/dev/skills/fluent-version-manage/SKILL.md +744 -0
  45. package/content/dev/skills/fluent-workflow-analyzer/SKILL.md +959 -0
  46. package/content/dev/skills/fluent-workflow-builder/SKILL.md +319 -0
  47. package/content/dev/skills/fluent-workflow-deploy/SKILL.md +267 -0
  48. package/content/mcp-extn/agents/fluent-mcp.md +69 -0
  49. package/content/mcp-extn/skills/fluent-mcp-tools/SKILL.md +461 -0
  50. package/content/mcp-official/agents/fluent-mcp-core.md +91 -0
  51. package/content/mcp-official/skills/fluent-mcp-core/SKILL.md +94 -0
  52. package/content/rfl/agents/fluent-rfl.md +56 -0
  53. package/content/rfl/skills/fluent-rfl-assess/SKILL.md +172 -0
  54. package/docs/CAPABILITY_MAP.md +77 -0
  55. package/docs/CLI_COVERAGE.md +47 -0
  56. package/docs/DEV_WORKFLOW.md +802 -0
  57. package/docs/FLOW_RUN.md +142 -0
  58. package/docs/USE_CASES.md +404 -0
  59. package/metadata.json +156 -0
  60. package/package.json +51 -0
@@ -0,0 +1,744 @@
1
+ ---
2
+ name: fluent-version-manage
3
+ description: Manage Fluent Commerce module versions. Read, bump, sync, and tag versions across POM files, module.json, and CHANGELOG.md. Ensures all version references stay consistent. Triggers on "version status", "bump version", "tag release", "version sync", "what version", "prepare release".
4
+ user-invocable: true
5
+ allowed-tools: Bash, Read, Write, Edit, Glob, Grep
6
+ argument-hint: [status|bump|sync|tag] [--level patch|minor|major] [--module-path <path>] [--dry-run]
7
+ ---
8
+
9
+ # Version Management
10
+
11
+ Manage the full version lifecycle for Fluent Commerce extension modules: read current versions from all source-of-truth files, bump with semver policy, update CHANGELOG.md, synchronize mismatches, and create git release tags.
12
+
13
+ **ADD Phase:** Packaging & Versioning (Phase 5)
14
+
15
+ ## Planning Gate
16
+
17
+ **Before bumping versions, write a plan using the template from `PLAN_TEMPLATE.md` in the `fluent-feature-plan` skill.** `status` (read-only) and `sync --dry-run` are exempt.
18
+
19
+ **Version-manage specific emphasis — ensure these are covered:**
20
+
21
+ 1. **Business Context (Section 1)** — what change drives this release
22
+ 2. **Scope (Section 2)** — current version → new version, bump type (patch/minor/major) with rationale
23
+ 3. **Files (Section 6)** — all pom.xml, module.json, package.json, CHANGELOG.md to modify
24
+ 4. **Detailed Design (Section 5)** — CHANGELOG entries to move from [Unreleased] to new version heading
25
+ 5. **Impacted retailers (Section 4.8)** — which environments will receive this version
26
+
27
+ **Write the plan to:** `accounts/<PROFILE>/plans/<YYYY-MM-DD>-version-manage-<slug>.md`. Set `Status: PENDING`.
28
+
29
+ Present the full plan content to the user and wait for approval before modifying any version files. On approval, update the file to `Status: APPROVED`. If the user says "just do it", proceed directly (still write the file for audit trail).
30
+
31
+ ## Ownership Boundary
32
+
33
+ This skill owns:
34
+
35
+ - Reading version state across all module files
36
+ - Bumping versions with semver policy (patch / minor / major)
37
+ - Synchronizing version mismatches across POM files and module.json
38
+ - Updating CHANGELOG.md during version bumps (moving `[Unreleased]` to a dated heading)
39
+ - Creating annotated git tags for releases
40
+ - Git commit of version changes (optional)
41
+
42
+ This skill does **not** own:
43
+
44
+ - Maven builds or test execution -> `/fluent-build`
45
+ - Module deployment -> `/fluent-module-deploy`
46
+ - Structural validation -> `/fluent-module-validate`
47
+ - CHANGELOG content authoring -> developer responsibility (this skill only transforms headings)
48
+
49
+ ### Delegation from `/fluent-build`
50
+
51
+ The existing `/fluent-build` skill has a "Version Bump" section (step 1 of 4). This skill extracts and expands that functionality. After implementation, `/fluent-build` should delegate its version bump step here:
52
+
53
+ ```
54
+ /fluent-version-manage bump --level patch
55
+ ```
56
+
57
+ | Capability | `/fluent-build` (current) | `/fluent-version-manage` (this skill) |
58
+ |-----------|--------------------------|--------------------------------------|
59
+ | Read current version | Implicit (before bump) | Explicit `status` command with JSON output |
60
+ | Bump version | Patch only, inline | patch / minor / major with `--dry-run` |
61
+ | Sync check | None | `sync` command detects and fixes mismatches |
62
+ | CHANGELOG update | None | Moves `[Unreleased]` to dated version heading |
63
+ | Git tag | None | `tag` command with annotated tags |
64
+ | Git commit | None | Optional `--commit` flag |
65
+ | SNAPSHOT handling | None | Strips `-SNAPSHOT` suffix during bump |
66
+
67
+ ## When to Use
68
+
69
+ - "What version is this module?" -> `status`
70
+ - "Are all version files consistent?" -> `status`
71
+ - Module code changed and needs a new version before redeploy -> `bump`
72
+ - Version mismatch detected by `/fluent-module-validate` -> `sync`
73
+ - After code is finalized and ready for release -> `bump --commit --tag`
74
+ - Tag an already-bumped version for release -> `tag`
75
+ - Preparing a release candidate -> `bump --level minor --dry-run` (preview first)
76
+
77
+ ## Required Inputs
78
+
79
+ | Parameter | Required | Default | Description |
80
+ |-----------|----------|---------|-------------|
81
+ | `command` | Yes | -- | One of: `status`, `bump`, `sync`, `tag` |
82
+ | `--level` | For `bump` | `patch` | Semver level: `patch`, `minor`, `major` |
83
+ | `--module-path` | No | Auto-detect | Path to module root (directory containing `resources/module.json` and `plugins/`) |
84
+ | `--dry-run` | No | `false` | Show what would change without modifying files |
85
+ | `--changelog-entry` | For `bump` | Auto-generate | CHANGELOG entry text for the new version |
86
+ | `--commit` | No | `false` | Git commit the version changes after bump |
87
+ | `--tag` | No | `false` | Also create git tag after bump (implies version is final) |
88
+ | `--profile` | No | Active profile | For module path auto-detection under `accounts/<PROFILE>/SOURCE/` |
89
+
90
+ ## Version Source-of-Truth Files
91
+
92
+ Every Fluent extension module has up to 7+ files that must carry the same version string. The canonical source of truth is `resources/module.json` because that is what Fluent Commerce reads during module installation.
93
+
94
+ | # | File | Field / Location | Extraction Pattern |
95
+ |---|------|-----------------|-------------------|
96
+ | 1 | `resources/module.json` | `"version": "x.y.z"` | JSON parse -> `.version` |
97
+ | 2 | `plugins/pom.xml` | `<version>` under `<project>` | Regex: `<project>[^]*?<version>([^<]+)</version>` (first `<version>` after `<project>` that is NOT inside `<parent>`) |
98
+ | 3 | `plugins/rules/<alias>/pom.xml` | `<version>` under `<parent>` | Regex: `<parent>[^]*?<version>([^<]+)</version>` |
99
+ | 4 | `plugins/types/<alias>/pom.xml` | `<version>` under `<parent>` | Regex: `<parent>[^]*?<version>([^<]+)</version>` |
100
+ | 5 | `plugins/util/<alias>/pom.xml` | `<version>` under `<parent>` | Regex: `<parent>[^]*?<version>([^<]+)</version>` |
101
+ | 6 | `CHANGELOG.md` (if exists) | `## [x.y.z]` heading | Regex: `^## \[(\d+\.\d+\.\d+(?:-[a-zA-Z0-9.]+)?)\]` |
102
+ | 7 | `package.json` (if exists) | `"version": "x.y.z"` | JSON parse -> `.version` |
103
+
104
+ ### POM Version Extraction Details
105
+
106
+ POM files use XML without a full parser. Use these regex strategies:
107
+
108
+ **Parent POM (`plugins/pom.xml`) -- project-level version:**
109
+
110
+ The parent POM typically has this structure:
111
+
112
+ ```xml
113
+ <project ...>
114
+ <modelVersion>4.0.0</modelVersion>
115
+ <groupId>com.fluentcommerce</groupId>
116
+ <artifactId>fc-module-hm-extensions</artifactId>
117
+ <version>1.2.3</version> <!-- THIS is the project version -->
118
+ <packaging>pom</packaging>
119
+ ...
120
+ </project>
121
+ ```
122
+
123
+ Extraction: Read the file content. Find `<version>` that appears as a direct child of `<project>` but NOT inside a `<parent>` block.
124
+
125
+ ```bash
126
+ # Extract project version from parent POM (skip any <parent> block version)
127
+ node -e "
128
+ const fs = require('fs');
129
+ const xml = fs.readFileSync(process.argv[1], 'utf8');
130
+ // Remove parent block to avoid matching parent version
131
+ const noParent = xml.replace(/<parent>[\s\S]*?<\/parent>/, '');
132
+ const m = noParent.match(/<version>([^<]+)<\/version>/);
133
+ console.log(m ? m[1] : 'NOT_FOUND');
134
+ " "plugins/pom.xml"
135
+ ```
136
+
137
+ **Child POM (`plugins/rules/<alias>/pom.xml`) -- parent reference version:**
138
+
139
+ ```xml
140
+ <project ...>
141
+ <parent>
142
+ <groupId>com.fluentcommerce</groupId>
143
+ <artifactId>fc-module-hm-extensions</artifactId>
144
+ <version>1.2.3</version> <!-- THIS inherits from parent -->
145
+ </parent>
146
+ <artifactId>hm-extensions-rules</artifactId>
147
+ <!-- No <version> here = inherits from parent -->
148
+ </project>
149
+ ```
150
+
151
+ Extraction: Read the `<version>` inside the `<parent>` block.
152
+
153
+ ```bash
154
+ # Extract parent version from child POM
155
+ node -e "
156
+ const fs = require('fs');
157
+ const xml = fs.readFileSync(process.argv[1], 'utf8');
158
+ const parentBlock = xml.match(/<parent>([\s\S]*?)<\/parent>/);
159
+ if (!parentBlock) { console.log('NO_PARENT_BLOCK'); process.exit(0); }
160
+ const m = parentBlock[1].match(/<version>([^<]+)<\/version>/);
161
+ console.log(m ? m[1] : 'NOT_FOUND');
162
+ " "plugins/rules/hm-extensions/pom.xml"
163
+ ```
164
+
165
+ **Important:** Some child POMs also declare a project-level `<version>` that overrides parent inheritance. If present, both the parent reference AND the project version must be updated.
166
+
167
+ ### Discovering Child POM Aliases
168
+
169
+ The module alias (subdirectory name under `rules/`, `types/`, `util/`) varies per module. Discover dynamically:
170
+
171
+ ```bash
172
+ # List all child POMs under plugins/
173
+ node -e "
174
+ const fs = require('fs');
175
+ const path = require('path');
176
+ const root = process.argv[1];
177
+ const dirs = ['rules', 'types', 'util'];
178
+ const results = [];
179
+ for (const d of dirs) {
180
+ const dir = path.join(root, 'plugins', d);
181
+ if (!fs.existsSync(dir)) continue;
182
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
183
+ if (entry.isDirectory()) {
184
+ const pom = path.join(dir, entry.name, 'pom.xml');
185
+ if (fs.existsSync(pom)) results.push({ type: d, alias: entry.name, pom });
186
+ }
187
+ }
188
+ }
189
+ console.log(JSON.stringify(results, null, 2));
190
+ " "<MODULE_ROOT>"
191
+ ```
192
+
193
+ ---
194
+
195
+ ## Commands
196
+
197
+ ### 1. `status` -- Read Current Versions
198
+
199
+ Read version strings from every source-of-truth file, check consistency, and report CHANGELOG state.
200
+
201
+ **Algorithm:**
202
+
203
+ ```
204
+ 1. Locate module root (auto-detect or --module-path)
205
+ 2. Read resources/module.json -> extract "version"
206
+ 3. Read plugins/pom.xml -> extract project <version>
207
+ 4. Glob for plugins/{rules,types,util}/*/pom.xml -> extract parent <version> from each
208
+ 5. Check for CHANGELOG.md -> scan for [Unreleased] section and latest [x.y.z] heading
209
+ 6. Check for package.json -> extract "version" if present
210
+ 7. Compare all extracted versions
211
+ 8. Output structured report
212
+ ```
213
+
214
+ **Output schema:**
215
+
216
+ ```json
217
+ {
218
+ "command": "status",
219
+ "modulePath": "accounts/<PROFILE>/SOURCE/fluentcommerce-fc-module-hm-extensions",
220
+ "moduleName": "fluent-commerce/fc-module-hm-extensions",
221
+ "currentVersion": "1.2.3",
222
+ "consistent": true,
223
+ "files": {
224
+ "resources/module.json": { "version": "1.2.3", "field": "version" },
225
+ "plugins/pom.xml": { "version": "1.2.3", "field": "project.version" },
226
+ "plugins/rules/hm-extensions/pom.xml": { "version": "1.2.3", "field": "parent.version" },
227
+ "plugins/types/hm-extensions/pom.xml": { "version": "1.2.3", "field": "parent.version" },
228
+ "plugins/util/hm-extensions/pom.xml": { "version": "1.2.3", "field": "parent.version" }
229
+ },
230
+ "changelog": {
231
+ "exists": true,
232
+ "hasUnreleased": true,
233
+ "unreleasedEntries": 3,
234
+ "latestRelease": "1.2.2",
235
+ "latestReleaseDate": "2026-02-20"
236
+ },
237
+ "packageJson": {
238
+ "exists": false,
239
+ "version": null
240
+ },
241
+ "snapshot": false
242
+ }
243
+ ```
244
+
245
+ When `consistent` is `false`, `currentVersion` is set to the `resources/module.json` version (canonical) and a `mismatches` array is added:
246
+
247
+ ```json
248
+ {
249
+ "consistent": false,
250
+ "currentVersion": "1.2.3",
251
+ "mismatches": [
252
+ { "file": "plugins/rules/hm-extensions/pom.xml", "expected": "1.2.3", "actual": "1.2.2" }
253
+ ]
254
+ }
255
+ ```
256
+
257
+ **Console output format:**
258
+
259
+ ```
260
+ VERSION STATUS
261
+ ===========
262
+ Module: fluent-commerce/fc-module-hm-extensions
263
+ Path: accounts/HMDEV/SOURCE/fluentcommerce-fc-module-hm-extensions
264
+ Version: 1.2.3
265
+
266
+ FILES
267
+ -----
268
+ [OK] resources/module.json 1.2.3
269
+ [OK] plugins/pom.xml 1.2.3
270
+ [OK] plugins/rules/hm-extensions 1.2.3
271
+ [OK] plugins/types/hm-extensions 1.2.3
272
+ [OK] plugins/util/hm-extensions 1.2.3
273
+
274
+ CHANGELOG
275
+ ---------
276
+ [Unreleased]: 3 entries pending
277
+ Latest release: [1.2.2] - 2026-02-20
278
+
279
+ Result: ALL VERSIONS CONSISTENT
280
+ ```
281
+
282
+ ### 2. `bump` -- Increment Version
283
+
284
+ Increment the version across all source-of-truth files using semver policy.
285
+
286
+ **Algorithm:**
287
+
288
+ ```
289
+ 1. Run status internally to get current state
290
+ 2. If versions are inconsistent:
291
+ -> ABORT with error: "Version mismatch detected. Run /fluent-version-manage sync first."
292
+ 3. Parse current version: MAJOR.MINOR.PATCH[-SNAPSHOT]
293
+ 4. Strip -SNAPSHOT suffix if present
294
+ 5. Calculate new version based on --level:
295
+ - patch: MAJOR.MINOR.(PATCH+1)
296
+ - minor: MAJOR.(MINOR+1).0
297
+ - major: (MAJOR+1).0.0
298
+ 6. If --dry-run:
299
+ -> Print "Would update X.Y.Z -> A.B.C in N files" and STOP
300
+ 7. Update each file:
301
+ a. resources/module.json:
302
+ - Read JSON, set .version = newVersion, write back
303
+ b. plugins/pom.xml:
304
+ - Replace project <version>OLD</version> with <version>NEW</version>
305
+ - Avoid replacing <version> inside <parent> or <dependency> blocks
306
+ c. Each child POM (rules/types/util):
307
+ - Replace <version>OLD</version> inside <parent> block
308
+ - If child also has project-level <version>, replace that too
309
+ d. package.json (if exists):
310
+ - Read JSON, set .version = newVersion, write back
311
+ 8. Transform CHANGELOG.md (see CHANGELOG Transformation Rules below)
312
+ 9. Verify: re-run status to confirm all files now show new version
313
+ 10. If --commit:
314
+ -> git add <all changed files>
315
+ -> git commit -m "chore: bump version to <newVersion>"
316
+ 11. If --tag:
317
+ -> git tag -a "v<newVersion>" -m "Release <newVersion>"
318
+ 12. Report: list of files changed with old -> new version
319
+ ```
320
+
321
+ **POM update -- regex replacement:**
322
+
323
+ For the parent POM (`plugins/pom.xml`), the replacement must target only the project-level version:
324
+
325
+ ```bash
326
+ # Update parent POM project version
327
+ node -e "
328
+ const fs = require('fs');
329
+ const file = process.argv[1];
330
+ const oldVer = process.argv[2];
331
+ const newVer = process.argv[3];
332
+ let xml = fs.readFileSync(file, 'utf8');
333
+ // Replace version outside of <parent> block
334
+ // Strategy: split on <parent>...</parent>, replace in non-parent sections
335
+ const parts = xml.split(/(<parent>[\s\S]*?<\/parent>)/);
336
+ for (let i = 0; i < parts.length; i++) {
337
+ if (!parts[i].startsWith('<parent>')) {
338
+ parts[i] = parts[i].replace(
339
+ '<version>' + oldVer + '</version>',
340
+ '<version>' + newVer + '</version>'
341
+ );
342
+ }
343
+ }
344
+ fs.writeFileSync(file, parts.join(''));
345
+ console.log('Updated ' + file);
346
+ " "plugins/pom.xml" "1.2.3" "1.2.4"
347
+ ```
348
+
349
+ For child POMs, update the version inside the `<parent>` block:
350
+
351
+ ```bash
352
+ # Update child POM parent version reference
353
+ node -e "
354
+ const fs = require('fs');
355
+ const file = process.argv[1];
356
+ const oldVer = process.argv[2];
357
+ const newVer = process.argv[3];
358
+ let xml = fs.readFileSync(file, 'utf8');
359
+ xml = xml.replace(
360
+ /(<parent>[\s\S]*?<version>)(\Q${oldVer}\E)(<\/version>[\s\S]*?<\/parent>)/,
361
+ function(match, pre, ver, post) {
362
+ return pre + newVer + post;
363
+ }
364
+ );
365
+ // Also update project-level version if present (outside parent block)
366
+ const parts = xml.split(/(<parent>[\s\S]*?<\/parent>)/);
367
+ for (let i = 0; i < parts.length; i++) {
368
+ if (!parts[i].startsWith('<parent>')) {
369
+ parts[i] = parts[i].replace(
370
+ '<version>' + oldVer + '</version>',
371
+ '<version>' + newVer + '</version>'
372
+ );
373
+ }
374
+ }
375
+ fs.writeFileSync(file, parts.join(''));
376
+ console.log('Updated ' + file);
377
+ " "plugins/rules/hm-extensions/pom.xml" "1.2.3" "1.2.4"
378
+ ```
379
+
380
+ **Dry-run output example:**
381
+
382
+ ```
383
+ VERSION BUMP (DRY RUN)
384
+ ======================
385
+ Module: fluent-commerce/fc-module-hm-extensions
386
+ Current: 1.2.3
387
+ New: 1.2.4 (patch)
388
+
389
+ Files that would be updated:
390
+ resources/module.json 1.2.3 -> 1.2.4
391
+ plugins/pom.xml 1.2.3 -> 1.2.4
392
+ plugins/rules/hm-extensions/pom.xml 1.2.3 -> 1.2.4
393
+ plugins/types/hm-extensions/pom.xml 1.2.3 -> 1.2.4
394
+ plugins/util/hm-extensions/pom.xml 1.2.3 -> 1.2.4
395
+ CHANGELOG.md [Unreleased] -> [1.2.4] - 2026-02-23
396
+
397
+ No files were modified (dry run).
398
+ ```
399
+
400
+ ### 3. `sync` -- Fix Version Mismatches
401
+
402
+ Detect and repair version inconsistencies using `resources/module.json` as the canonical source.
403
+
404
+ **Algorithm:**
405
+
406
+ ```
407
+ 1. Run status internally
408
+ 2. If consistent: print "All versions already in sync at X.Y.Z" and STOP
409
+ 3. Determine canonical version:
410
+ a. If resources/module.json exists and has a version -> use it (preferred)
411
+ b. Else use the highest semver found across all files
412
+ 4. If --dry-run:
413
+ -> Print "Would sync N files to version X.Y.Z" and STOP
414
+ 5. Update every file that has a different version to the canonical version
415
+ (same update logic as bump, but only touching mismatched files)
416
+ 6. Re-run status to confirm consistency
417
+ 7. Report: files changed with old -> canonical version
418
+ ```
419
+
420
+ **Console output:**
421
+
422
+ ```
423
+ VERSION SYNC
424
+ ============
425
+ Canonical version: 1.2.3 (from resources/module.json)
426
+
427
+ Changes:
428
+ [FIXED] plugins/rules/hm-extensions/pom.xml 1.2.2 -> 1.2.3
429
+ [FIXED] plugins/util/hm-extensions/pom.xml 1.2.1 -> 1.2.3
430
+ [OK] resources/module.json 1.2.3 (canonical)
431
+ [OK] plugins/pom.xml 1.2.3
432
+ [OK] plugins/types/hm-extensions/pom.xml 1.2.3
433
+
434
+ Result: 2 files synced to 1.2.3
435
+ ```
436
+
437
+ ### 4. `tag` -- Create Git Release Tag
438
+
439
+ Create an annotated git tag for the current version.
440
+
441
+ **Algorithm:**
442
+
443
+ ```
444
+ 1. Run status internally to get current version
445
+ 2. If versions are inconsistent:
446
+ -> ABORT: "Version mismatch. Run /fluent-version-manage sync first."
447
+ 3. Construct tag name: "v" + currentVersion (e.g., "v1.2.3")
448
+ 4. Check if tag already exists:
449
+ -> git tag -l "v1.2.3"
450
+ -> If exists, ABORT: "Tag v1.2.3 already exists."
451
+ 5. If --dry-run:
452
+ -> Print "Would create tag v1.2.3" and STOP
453
+ 6. Check for uncommitted changes to version files:
454
+ -> git status --porcelain -- resources/module.json plugins/ CHANGELOG.md package.json
455
+ -> If dirty, WARN: "Uncommitted version file changes. Consider committing first."
456
+ 7. Create annotated tag:
457
+ -> git tag -a "v1.2.3" -m "Release 1.2.3"
458
+ 8. Report: tag name and instructions to push
459
+ ```
460
+
461
+ **Console output:**
462
+
463
+ ```
464
+ GIT TAG
465
+ =======
466
+ Module: fluent-commerce/fc-module-hm-extensions
467
+ Version: 1.2.3
468
+ Tag: v1.2.3
469
+
470
+ Tag created successfully.
471
+
472
+ To push the tag to remote:
473
+ git push origin v1.2.3
474
+ ```
475
+
476
+ ---
477
+
478
+ ## CHANGELOG Transformation Rules
479
+
480
+ The `bump` command transforms CHANGELOG.md by moving the `[Unreleased]` section contents under a new dated version heading.
481
+
482
+ ### Expected CHANGELOG Format (Keep a Changelog)
483
+
484
+ ```markdown
485
+ # Changelog
486
+
487
+ ## [Unreleased]
488
+
489
+ ### Added
490
+ - New CancelOrder rule for order cancellation workflow
491
+ - Webhook retry logic with exponential backoff
492
+
493
+ ### Fixed
494
+ - Status transition guard in FulfilmentComplete rule
495
+
496
+ ## [1.2.3] - 2026-02-20
497
+
498
+ ### Added
499
+ - Initial webhook support
500
+
501
+ ## [1.2.2] - 2026-02-15
502
+ ...
503
+ ```
504
+
505
+ ### Transformation Algorithm
506
+
507
+ ```
508
+ 1. Read CHANGELOG.md
509
+ 2. Find the [Unreleased] heading: regex ^## \[Unreleased\]\s*$
510
+ 3. Find the next version heading (or end of file):
511
+ regex ^## \[\d+\.\d+\.\d+
512
+ 4. Extract everything between [Unreleased] heading and next heading
513
+ 5. If extracted content is empty (only whitespace):
514
+ -> WARN: "No unreleased entries found. CHANGELOG heading will be empty."
515
+ 6. Replace:
516
+ BEFORE:
517
+ ## [Unreleased]
518
+ <entries>
519
+ ## [1.2.3] - 2026-02-20
520
+
521
+ AFTER:
522
+ ## [Unreleased]
523
+
524
+ ## [1.2.4] - 2026-02-23
525
+ <entries>
526
+ ## [1.2.3] - 2026-02-20
527
+ 7. The date format is YYYY-MM-DD (ISO 8601 date)
528
+ 8. Write updated CHANGELOG.md
529
+ ```
530
+
531
+ ### Before/After Example
532
+
533
+ **Before (`bump --level patch` on 2026-02-23):**
534
+
535
+ ```markdown
536
+ # Changelog
537
+
538
+ ## [Unreleased]
539
+
540
+ ### Added
541
+ - New CancelOrder rule for order cancellation workflow
542
+ - Webhook retry logic with exponential backoff
543
+
544
+ ### Fixed
545
+ - Status transition guard in FulfilmentComplete rule
546
+
547
+ ## [1.2.3] - 2026-02-20
548
+
549
+ ### Added
550
+ - Initial webhook support
551
+ ```
552
+
553
+ **After:**
554
+
555
+ ```markdown
556
+ # Changelog
557
+
558
+ ## [Unreleased]
559
+
560
+ ## [1.2.4] - 2026-02-23
561
+
562
+ ### Added
563
+ - New CancelOrder rule for order cancellation workflow
564
+ - Webhook retry logic with exponential backoff
565
+
566
+ ### Fixed
567
+ - Status transition guard in FulfilmentComplete rule
568
+
569
+ ## [1.2.3] - 2026-02-20
570
+
571
+ ### Added
572
+ - Initial webhook support
573
+ ```
574
+
575
+ ---
576
+
577
+ ## Validation Rules
578
+
579
+ | Rule | Enforcement | Recovery |
580
+ |------|------------|----------|
581
+ | Version must match semver: `^\d+\.\d+\.\d+(-SNAPSHOT)?$` | All commands | Report invalid format and the file containing it |
582
+ | SNAPSHOT suffix is stripped during bump | `bump` | `1.2.3-SNAPSHOT` becomes `1.2.4` (not `1.2.3-SNAPSHOT+1`) |
583
+ | Bump refuses on inconsistent versions | `bump` | Run `sync` first, then retry bump |
584
+ | Bump warns on uncommitted changes to version files | `bump` (without `--dry-run`) | Commit or stash first, or acknowledge the warning |
585
+ | Tag refuses if tag already exists | `tag` | Use a different version or delete the existing tag manually |
586
+ | Tag warns on uncommitted version file changes | `tag` | Commit first |
587
+ | Module.json must exist for any command | All commands | Cannot operate without a module manifest |
588
+
589
+ ### SNAPSHOT Handling
590
+
591
+ SNAPSHOT versions are common during active development in Maven-based projects:
592
+
593
+ | Scenario | Input | `--level patch` | `--level minor` | `--level major` |
594
+ |----------|-------|-----------------|-----------------|-----------------|
595
+ | Release version | `1.2.3` | `1.2.4` | `1.3.0` | `2.0.0` |
596
+ | SNAPSHOT version | `1.2.3-SNAPSHOT` | `1.2.3` | `1.3.0` | `2.0.0` |
597
+
598
+ For SNAPSHOT input, `patch` bumps to the release version (strips suffix without incrementing). This follows the convention that SNAPSHOT represents a pre-release of that version.
599
+
600
+ ---
601
+
602
+ ## Module Path Auto-Detection
603
+
604
+ When `--module-path` is not provided, search for the module root automatically:
605
+
606
+ ```
607
+ 1. Search accounts/<PROFILE>/SOURCE/ recursively for resources/module.json
608
+ 2. For each found module.json:
609
+ a. Verify plugins/ directory exists alongside it (or one level up)
610
+ b. Read module name for display
611
+ 3. If exactly 1 module found -> use it
612
+ 4. If multiple found -> list them and ask user to choose:
613
+ "Found N modules under accounts/<PROFILE>/SOURCE/:
614
+ [1] fluent-commerce/fc-module-hm-extensions (accounts/HMDEV/SOURCE/fluentcommerce-fc-module-hm-extensions)
615
+ [2] fluent-commerce/fc-module-hm-return (accounts/HMDEV/SOURCE/fluentcommerce-fc-module-hm-return)
616
+ Which module? Specify with --module-path <path>"
617
+ 5. If none found -> ERROR: "No module found. Provide --module-path explicitly."
618
+ ```
619
+
620
+ **Handle double-nested directories:** If a directory under SOURCE contains only one subdirectory with a similar name and no direct `module.json` at the outer level, check the inner directory. Record this for the user.
621
+
622
+ ---
623
+
624
+ ## Execution Flow (All Commands)
625
+
626
+ ```
627
+ 1. AUTO-DETECT module path:
628
+ a. If --module-path provided, verify it exists
629
+ b. Else search accounts/<PROFILE>/SOURCE/ for resources/module.json
630
+ c. Validate: resources/module.json must exist at resolved path
631
+
632
+ 2. DISCOVER version files:
633
+ a. Read resources/module.json for module name and version
634
+ b. Read plugins/pom.xml for project version
635
+ c. Glob plugins/{rules,types,util}/*/pom.xml for child POM versions
636
+ d. Check for CHANGELOG.md at module root
637
+ e. Check for package.json at module root
638
+
639
+ 3. EXECUTE command:
640
+ - status: collect and compare all versions, report
641
+ - bump: validate consistency, increment, update files, transform CHANGELOG
642
+ - sync: detect mismatches, update to canonical
643
+ - tag: validate consistency, check existing tags, create annotated tag
644
+
645
+ 4. VERIFY (for mutating commands):
646
+ Re-run the status check to confirm all files are now consistent
647
+
648
+ 5. REPORT:
649
+ Print structured output with all changes made
650
+ ```
651
+
652
+ ---
653
+
654
+ ## Integration with Other Skills
655
+
656
+ | Skill | Integration Point |
657
+ |-------|-------------------|
658
+ | `/fluent-build` | Delegates version bump to this skill. This skill's `status` output feeds build's pre-check. |
659
+ | `/fluent-module-validate` | Version consistency check (check ID `versions`) maps to this skill's `status` command. Validation report `summary.status: NEEDS_FIXES` with a version failure should trigger `sync`. |
660
+ | `/fluent-custom-code` | Reads module version from `source-map.json`. If version drift is detected, recommend `bump` or `sync`. |
661
+ | `/fluent-pre-deploy-check` | Gate 2.4 (Version bumped) calls `status` to compare local vs deployed version. |
662
+ | `/fluent-session-summary` | Version bumps and tags are tracked as session changes. |
663
+ | `/fluent-scope-decompose` | Task type `VERSION` maps to this skill. |
664
+
665
+ ### Consuming Cached Artifacts
666
+
667
+ Before running, check if `/fluent-custom-code` artifacts exist:
668
+
669
+ ```
670
+ accounts/<PROFILE>/analysis/custom-code/source-map.json
671
+ ```
672
+
673
+ If found, read `modules[].version` and `modules[].versionSource` to pre-populate version information without re-scanning POM files. Fall back to direct file reads if artifacts are missing or stale.
674
+
675
+ ---
676
+
677
+ ## Edge Cases
678
+
679
+ | Scenario | Behavior |
680
+ |----------|----------|
681
+ | **SNAPSHOT version** | `bump --level patch` strips SNAPSHOT without incrementing (1.2.3-SNAPSHOT -> 1.2.3). Minor and major still increment normally. |
682
+ | **Multiple modules found** | List all discovered modules and require `--module-path` to disambiguate. Never auto-select when ambiguous. |
683
+ | **No CHANGELOG.md** | `status` reports `changelog.exists: false`. `bump` skips CHANGELOG transformation with a warning: "No CHANGELOG.md found -- skipping changelog update." |
684
+ | **Empty [Unreleased] section** | `bump` still creates the version heading but warns: "No unreleased entries. Version heading will have no content." |
685
+ | **No [Unreleased] heading in CHANGELOG** | `bump` prepends a new version heading at the top of the changelog (after the `# Changelog` title) and warns: "No [Unreleased] section found -- added version heading at top." |
686
+ | **CHANGELOG has no title line** | Treat the entire file as changelog content. Insert `## [Unreleased]` and `## [x.y.z]` at the top. |
687
+ | **Windows path handling** | Use forward slashes in all POM `<module>` references and report paths. Use `path.join()` for filesystem operations but normalize to forward slashes for display. |
688
+ | **Child POM has both parent and project version** | Update BOTH the `<parent><version>` and the project-level `<version>` in the same file. |
689
+ | **module.json missing** | ABORT all commands. Module.json is required as the canonical version source. |
690
+ | **package.json version out of sync** | `sync` updates package.json to match module.json. `status` reports the mismatch. |
691
+ | **Git not initialized** | `--commit` and `--tag` fail gracefully: "Not a git repository. Skipping git operations." |
692
+ | **Tag already exists** | `tag` aborts with clear message. `bump --tag` also aborts the tag step (but version files are already updated). |
693
+ | **Uncommitted changes** | `bump` warns but proceeds (version bump is the intended commit). `tag` warns more strongly (tagging uncommitted state is risky). |
694
+ | **Read-only files** | Report which files could not be written and suggest checking file permissions or read-only flags. |
695
+
696
+ ---
697
+
698
+ ## Example: Full `bump` Walkthrough
699
+
700
+ **Starting state:**
701
+
702
+ ```
703
+ resources/module.json -> "version": "0.0.29"
704
+ plugins/pom.xml -> <version>0.0.29</version>
705
+ plugins/rules/hm/pom.xml -> <parent><version>0.0.29</version></parent>
706
+ plugins/types/hm/pom.xml -> <parent><version>0.0.29</version></parent>
707
+ plugins/util/hm/pom.xml -> <parent><version>0.0.29</version></parent>
708
+ CHANGELOG.md -> ## [Unreleased] with 2 entries
709
+ ```
710
+
711
+ **Command:** `/fluent-version-manage bump --level minor --commit`
712
+
713
+ **Steps executed:**
714
+
715
+ 1. Status check: all files at `0.0.29` -- consistent
716
+ 2. Calculate: `0.0.29` -> `0.1.0` (minor bump)
717
+ 3. Update `resources/module.json`: `"version": "0.1.0"`
718
+ 4. Update `plugins/pom.xml`: `<version>0.1.0</version>`
719
+ 5. Update 3 child POMs: `<parent><version>0.1.0</version></parent>`
720
+ 6. Transform CHANGELOG.md: `[Unreleased]` entries moved under `[0.1.0] - 2026-02-23`
721
+ 7. Verify: re-read all files, confirm `0.1.0` everywhere
722
+ 8. Git commit: `git add resources/module.json plugins/pom.xml plugins/rules/hm/pom.xml plugins/types/hm/pom.xml plugins/util/hm/pom.xml CHANGELOG.md && git commit -m "chore: bump version to 0.1.0"`
723
+
724
+ **Output:**
725
+
726
+ ```
727
+ VERSION BUMP
728
+ ============
729
+ Module: fluent-commerce/fc-module-hm-extensions
730
+ Old version: 0.0.29
731
+ New version: 0.1.0 (minor)
732
+
733
+ Updated files:
734
+ [OK] resources/module.json 0.0.29 -> 0.1.0
735
+ [OK] plugins/pom.xml 0.0.29 -> 0.1.0
736
+ [OK] plugins/rules/hm/pom.xml 0.0.29 -> 0.1.0
737
+ [OK] plugins/types/hm/pom.xml 0.0.29 -> 0.1.0
738
+ [OK] plugins/util/hm/pom.xml 0.0.29 -> 0.1.0
739
+ [OK] CHANGELOG.md [Unreleased] -> [0.1.0] - 2026-02-23
740
+
741
+ Verification: ALL CONSISTENT at 0.1.0
742
+
743
+ Git commit: abc1234 "chore: bump version to 0.1.0"
744
+ ```