@smartmemory/compose 0.1.14-beta → 0.1.15-beta

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smartmemory/compose",
3
- "version": "0.1.14-beta",
3
+ "version": "0.1.15-beta",
4
4
  "description": "Structured AI dev pipeline — goal-to-product orchestration with gates, iteration loops, and feature lifecycle management.",
5
5
  "author": "SmartMemory",
6
6
  "license": "MIT",
@@ -20,13 +20,20 @@ function slugify(title) {
20
20
  return title.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
21
21
  }
22
22
 
23
- const PREFIX_RE = /^([A-Z]+\d*(?:-[A-Z]+\d*)*)(?=-\d|$)/;
23
+ const CODE_PREFIX_RE = /^([A-Z][A-Z0-9-]*)/;
24
+ // Take first 2 hyphen-separated tokens after stripping any trailing numeric
25
+ // suffix segments (-2, -2-1-1). This collapses sibling families:
26
+ // COMP-WORKSPACE-HTTP, COMP-WORKSPACE-ID, COMP-WORKSPACE-WATCHERS → COMP-WORKSPACE
27
+ // COMP-MCP-COMPLETION, COMP-MCP-PUBLISH, COMP-MCP-MIGRATION-2-1-1 → COMP-MCP
28
+ // STRAT-REV, STRAT-REV-7 → STRAT-REV
29
+ // COMP-DESIGN (only 2 tokens already) → COMP-DESIGN
24
30
  function deriveGroup(title, featureCode) {
25
- const titleMatch = (title || '').match(PREFIX_RE);
26
- if (titleMatch) return titleMatch[1];
27
- const fcMatch = (featureCode || '').match(PREFIX_RE);
28
- if (fcMatch) return fcMatch[1];
29
- return null;
31
+ const candidate = featureCode || (title || '').match(CODE_PREFIX_RE)?.[1];
32
+ if (!candidate) return null;
33
+ const stripped = candidate.replace(/(?:-\d+)+$/, '');
34
+ const tokens = stripped.split('-').filter(Boolean);
35
+ if (tokens.length === 0) return null;
36
+ return tokens.slice(0, 2).join('-');
30
37
  }
31
38
 
32
39
  export class VisionStore {
@@ -70,9 +77,16 @@ export class VisionStore {
70
77
  }
71
78
  if (!item.slug && item.title) item.slug = slugify(item.title);
72
79
  if (!item.files) item.files = [];
73
- if (!item.group) {
74
- item.group = deriveGroup(item.title, item.featureCode || item.lifecycle?.featureCode);
75
- if (item.group) migrated = true;
80
+ // Always re-derive group on load — the rule has evolved (singletons →
81
+ // first-2-tokens) and existing items need the new shape. Custom
82
+ // user-set groups are not a use case here; group is derived metadata.
83
+ const newGroup = deriveGroup(item.title, item.featureCode || item.lifecycle?.featureCode);
84
+ if (newGroup && newGroup !== item.group) {
85
+ item.group = newGroup;
86
+ migrated = true;
87
+ } else if (!item.group && newGroup) {
88
+ item.group = newGroup;
89
+ migrated = true;
76
90
  }
77
91
  this.items.set(item.id, item);
78
92
  }