Sistema de códigos jerárquicos 2-niveles + asignación determinista post-IA
- hierarchy.ts: Spike (S) agregado, buildHierarchyPath genera [E01-F04] (2 niveles)
Legacy [E05-F04-U01] preservado (regex opcional 3er segmento)
- hierarchy-generator.ts (nuevo): analyzeExisting() computa contadores por épica+tipo
assignEpicCodes() asigna E{max+1} secuencial
assignItemCodes() asigna {epic}-{tipo}{n+1} a cada HU dentro de su épica
- project-analyzer.ts: post-procesa épicas y HUs con generador de códigos
saveEpicDrafts usa epicCode en metadata y título con [E01]
- prompts-db.ts: prompt FASE 2 instruye a la IA a no generar códigos
- workitems.ts: EnrichedEpic._epicCode, EnrichedUserStory._epicCode/_itemCode
- DashboardView: muestra códigos en drafts y tabla de épicas
This commit is contained in:
+13
-15
@@ -1,10 +1,9 @@
|
||||
export type ItemType = 'E' | 'F' | 'U' | 'T' | 'B'
|
||||
export type ItemType = 'E' | 'F' | 'U' | 'T' | 'B' | 'S'
|
||||
|
||||
export interface HierarchyInfo {
|
||||
fullPath: string
|
||||
items: { type: ItemType; number: number }[]
|
||||
epicCode: string | null
|
||||
featureCode: string | null
|
||||
itemCode: string | null
|
||||
}
|
||||
|
||||
@@ -14,6 +13,7 @@ const TYPE_LABELS: Record<ItemType, string> = {
|
||||
U: 'HU',
|
||||
T: 'Tarea',
|
||||
B: 'Bug',
|
||||
S: 'Spike',
|
||||
}
|
||||
|
||||
const TYPE_COLORS: Record<ItemType, string> = {
|
||||
@@ -22,6 +22,7 @@ const TYPE_COLORS: Record<ItemType, string> = {
|
||||
U: 'bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400',
|
||||
T: 'bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400',
|
||||
B: 'bg-rose-100 text-rose-700 dark:bg-rose-900/30 dark:text-rose-400',
|
||||
S: 'bg-cyan-100 text-cyan-700 dark:bg-cyan-900/30 dark:text-cyan-400',
|
||||
}
|
||||
|
||||
const TYPE_ICONS: Record<ItemType, string> = {
|
||||
@@ -30,6 +31,7 @@ const TYPE_ICONS: Record<ItemType, string> = {
|
||||
U: '📋',
|
||||
T: '⚙️',
|
||||
B: '🐛',
|
||||
S: '🔬',
|
||||
}
|
||||
|
||||
export function getTypeLabel(type: ItemType): string {
|
||||
@@ -44,7 +46,7 @@ export function getTypeIcon(type: ItemType): string {
|
||||
return TYPE_ICONS[type] || '📄'
|
||||
}
|
||||
|
||||
const HIERARCHY_REGEX = /\[(([EFUTB]\d+)(?:-([EFUTB]\d+))?(?:-([EFUTB]\d+))?)\]/i
|
||||
const HIERARCHY_REGEX = /\[(([EFUTBS]\d+)(?:-([EFUTBS]\d+))?(?:-([EFUTBS]\d+))?)\]/i
|
||||
|
||||
export function parseHierarchy(title: string): HierarchyInfo | null {
|
||||
const match = title.match(HIERARCHY_REGEX)
|
||||
@@ -61,15 +63,12 @@ export function parseHierarchy(title: string): HierarchyInfo | null {
|
||||
}))
|
||||
|
||||
const epic = items.find(i => i.type === 'E')
|
||||
const feature = items.find(i => i.type === 'F')
|
||||
const item = items[items.length - 1]
|
||||
|
||||
return {
|
||||
fullPath,
|
||||
items,
|
||||
epicCode: epic ? `E${String(epic.number).padStart(2, '0')}` : null,
|
||||
featureCode: feature ? `F${String(feature.number).padStart(2, '0')}` : null,
|
||||
itemCode: item ? `${item.type}${String(item.number).padStart(2, '0')}` : null,
|
||||
itemCode: items.length > 1 ? `${items[1].type}${String(items[1].number).padStart(2, '0')}` : null,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,25 +84,24 @@ export function getItemType(title: string): ItemType {
|
||||
|
||||
export function buildHierarchyPath(
|
||||
epicNum?: number,
|
||||
featureNum?: number,
|
||||
itemType?: ItemType,
|
||||
itemNum?: number,
|
||||
): string {
|
||||
const parts: string[] = []
|
||||
if (epicNum !== undefined) parts.push(`E${String(epicNum).padStart(2, '0')}`)
|
||||
if (featureNum !== undefined) parts.push(`F${String(featureNum).padStart(2, '0')}`)
|
||||
if (itemType && itemNum !== undefined) parts.push(`${itemType}${String(itemNum).padStart(2, '0')}`)
|
||||
return parts.length ? `[${parts.join('-')}]` : ''
|
||||
if (epicNum === undefined) return ''
|
||||
const parts: string[] = [`E${String(epicNum).padStart(2, '0')}`]
|
||||
if (itemType && itemNum !== undefined) {
|
||||
parts.push(`${itemType}${String(itemNum).padStart(2, '0')}`)
|
||||
}
|
||||
return `[${parts.join('-')}]`
|
||||
}
|
||||
|
||||
export function buildFullTitle(
|
||||
name: string,
|
||||
epicNum?: number,
|
||||
featureNum?: number,
|
||||
itemType?: ItemType,
|
||||
itemNum?: number,
|
||||
): string {
|
||||
const path = buildHierarchyPath(epicNum, featureNum, itemType, itemNum)
|
||||
const path = buildHierarchyPath(epicNum, itemType, itemNum)
|
||||
return path ? `${path} ${name}` : name
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user