specweave 0.13.6 → 0.14.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/CLAUDE.md +189 -0
- package/dist/cli/commands/init.js +1 -1
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/status-line.d.ts +14 -0
- package/dist/cli/commands/status-line.d.ts.map +1 -0
- package/dist/cli/commands/status-line.js +75 -0
- package/dist/cli/commands/status-line.js.map +1 -0
- package/dist/core/status-line/status-line-manager.d.ts +62 -0
- package/dist/core/status-line/status-line-manager.d.ts.map +1 -0
- package/dist/core/status-line/status-line-manager.js +169 -0
- package/dist/core/status-line/status-line-manager.js.map +1 -0
- package/dist/core/status-line/types.d.ts +50 -0
- package/dist/core/status-line/types.d.ts.map +1 -0
- package/dist/core/status-line/types.js +17 -0
- package/dist/core/status-line/types.js.map +1 -0
- package/dist/utils/project-mapper.d.ts +74 -0
- package/dist/utils/project-mapper.d.ts.map +1 -0
- package/dist/utils/project-mapper.js +273 -0
- package/dist/utils/project-mapper.js.map +1 -0
- package/dist/utils/spec-splitter.d.ts +68 -0
- package/dist/utils/spec-splitter.d.ts.map +1 -0
- package/dist/utils/spec-splitter.js +314 -0
- package/dist/utils/spec-splitter.js.map +1 -0
- package/package.json +1 -1
- package/plugins/specweave/hooks/lib/update-status-line.sh +138 -0
- package/plugins/specweave/hooks/post-task-completion.sh +10 -0
- package/plugins/specweave/skills/multi-project-spec-mapper/SKILL.md +399 -0
- package/plugins/specweave-ado/lib/ado-multi-project-sync.js +453 -0
- package/plugins/specweave-ado/lib/ado-multi-project-sync.ts +633 -0
- package/plugins/specweave-docs/skills/docusaurus/SKILL.md +17 -3
- package/plugins/specweave-docs-preview/commands/preview.md +29 -4
- package/plugins/specweave-github/lib/github-multi-project-sync.js +340 -0
- package/plugins/specweave-github/lib/github-multi-project-sync.ts +461 -0
- package/plugins/specweave-jira/lib/jira-multi-project-sync.js +244 -0
- package/plugins/specweave-jira/lib/jira-multi-project-sync.ts +358 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Status Line Manager
|
|
3
|
+
*
|
|
4
|
+
* Ultra-fast status line rendering with intelligent caching.
|
|
5
|
+
* Target: <1ms render time for 99% of requests.
|
|
6
|
+
*
|
|
7
|
+
* Architecture:
|
|
8
|
+
* - Hook pre-computes cache (async, 10-50ms)
|
|
9
|
+
* - Renderer reads cache (sync, <1ms)
|
|
10
|
+
* - mtime-based invalidation (handles external edits)
|
|
11
|
+
*/
|
|
12
|
+
import * as fs from 'fs';
|
|
13
|
+
import * as path from 'path';
|
|
14
|
+
import { DEFAULT_STATUS_LINE_CONFIG, } from './types.js';
|
|
15
|
+
export class StatusLineManager {
|
|
16
|
+
constructor(rootDir = process.cwd(), config = {}) {
|
|
17
|
+
this.rootDir = rootDir;
|
|
18
|
+
this.cacheFile = path.join(rootDir, '.specweave/state/status-line.json');
|
|
19
|
+
this.config = { ...DEFAULT_STATUS_LINE_CONFIG, ...config };
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Render status line (FAST PATH: <1ms)
|
|
23
|
+
*
|
|
24
|
+
* Returns formatted status line string or null if no active increment.
|
|
25
|
+
*/
|
|
26
|
+
render() {
|
|
27
|
+
if (!this.config.enabled) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
const cache = this.getCache();
|
|
31
|
+
if (!cache) {
|
|
32
|
+
return null; // No active increment or cache stale
|
|
33
|
+
}
|
|
34
|
+
return this.formatStatusLine(cache);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get cache with freshness validation (0.5-1ms)
|
|
38
|
+
*
|
|
39
|
+
* Returns null if:
|
|
40
|
+
* - Cache file missing
|
|
41
|
+
* - Cache too old (>maxCacheAge)
|
|
42
|
+
* - tasks.md modified since cache update
|
|
43
|
+
*/
|
|
44
|
+
getCache() {
|
|
45
|
+
try {
|
|
46
|
+
// Step 1: Read cache file (0.3ms)
|
|
47
|
+
if (!fs.existsSync(this.cacheFile)) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
const content = fs.readFileSync(this.cacheFile, 'utf8');
|
|
51
|
+
const cache = JSON.parse(content);
|
|
52
|
+
// Step 2: Validate cache has required fields
|
|
53
|
+
if (!cache.incrementId || cache.totalTasks === undefined) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
// Step 3: Check freshness (0.2-0.5ms)
|
|
57
|
+
if (!this.isCacheFresh(cache)) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
return cache;
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
// Cache read/parse error = treat as cache miss
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Check if cache is fresh (0.2-0.5ms)
|
|
69
|
+
*
|
|
70
|
+
* Two-level check:
|
|
71
|
+
* 1. Age check (ultra-fast, no I/O)
|
|
72
|
+
* 2. mtime check (fast, single stat() call)
|
|
73
|
+
*/
|
|
74
|
+
isCacheFresh(cache) {
|
|
75
|
+
// Check 1: Recent update? (no I/O, ultra-fast)
|
|
76
|
+
const age = Date.now() - new Date(cache.lastUpdate).getTime();
|
|
77
|
+
if (age < this.config.maxCacheAge) {
|
|
78
|
+
return true; // Cache is fresh (<5s old)
|
|
79
|
+
}
|
|
80
|
+
// Check 2: Has tasks.md changed? (single stat() call)
|
|
81
|
+
try {
|
|
82
|
+
const tasksFile = path.join(this.rootDir, '.specweave/increments', cache.incrementId, 'tasks.md');
|
|
83
|
+
const stats = fs.statSync(tasksFile);
|
|
84
|
+
const currentMtime = Math.floor(stats.mtimeMs / 1000);
|
|
85
|
+
return currentMtime === cache.lastModified;
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
// File missing or stat() failed = invalidate cache
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Format status line from cache (0.1ms)
|
|
94
|
+
*/
|
|
95
|
+
formatStatusLine(cache) {
|
|
96
|
+
const parts = [];
|
|
97
|
+
// Increment name (truncated)
|
|
98
|
+
const name = this.truncate(cache.incrementName, this.config.maxIncrementNameLength);
|
|
99
|
+
parts.push(`[${name}]`);
|
|
100
|
+
// Progress bar
|
|
101
|
+
if (this.config.showProgressBar) {
|
|
102
|
+
const bar = this.renderProgressBar(cache.completedTasks, cache.totalTasks);
|
|
103
|
+
parts.push(bar);
|
|
104
|
+
}
|
|
105
|
+
// Tasks count and percentage
|
|
106
|
+
if (this.config.showPercentage) {
|
|
107
|
+
parts.push(`${cache.completedTasks}/${cache.totalTasks} (${cache.percentage}%)`);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
parts.push(`${cache.completedTasks}/${cache.totalTasks}`);
|
|
111
|
+
}
|
|
112
|
+
// Current task
|
|
113
|
+
if (this.config.showCurrentTask && cache.currentTask) {
|
|
114
|
+
const taskTitle = this.truncate(cache.currentTask.title, this.config.maxTaskTitleLength);
|
|
115
|
+
parts.push(`• ${cache.currentTask.id}: ${taskTitle}`);
|
|
116
|
+
}
|
|
117
|
+
return parts.join(' ');
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Render ASCII progress bar (0.05ms)
|
|
121
|
+
*/
|
|
122
|
+
renderProgressBar(completed, total) {
|
|
123
|
+
if (total === 0) {
|
|
124
|
+
return '░'.repeat(this.config.progressBarWidth);
|
|
125
|
+
}
|
|
126
|
+
const percentage = completed / total;
|
|
127
|
+
const filled = Math.floor(percentage * this.config.progressBarWidth);
|
|
128
|
+
const empty = this.config.progressBarWidth - filled;
|
|
129
|
+
return '█'.repeat(filled) + '░'.repeat(empty);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Truncate string with ellipsis (0.01ms)
|
|
133
|
+
*/
|
|
134
|
+
truncate(str, maxLength) {
|
|
135
|
+
if (str.length <= maxLength) {
|
|
136
|
+
return str;
|
|
137
|
+
}
|
|
138
|
+
return str.substring(0, maxLength - 1) + '…';
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Get raw cache data (for testing/debugging)
|
|
142
|
+
*/
|
|
143
|
+
getCacheData() {
|
|
144
|
+
try {
|
|
145
|
+
if (!fs.existsSync(this.cacheFile)) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
const content = fs.readFileSync(this.cacheFile, 'utf8');
|
|
149
|
+
return JSON.parse(content);
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Clear cache (for testing/manual reset)
|
|
157
|
+
*/
|
|
158
|
+
clearCache() {
|
|
159
|
+
try {
|
|
160
|
+
if (fs.existsSync(this.cacheFile)) {
|
|
161
|
+
fs.unlinkSync(this.cacheFile);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
// Ignore errors
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=status-line-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-line-manager.js","sourceRoot":"","sources":["../../../src/core/status-line/status-line-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Status Line Types
|
|
3
|
+
*
|
|
4
|
+
* Type definitions for the fast status line caching system.
|
|
5
|
+
* Supports <1ms rendering with intelligent cache invalidation.
|
|
6
|
+
*/
|
|
7
|
+
export interface StatusLineCache {
|
|
8
|
+
/** Active increment ID (e.g., "0017-sync-architecture-fix") */
|
|
9
|
+
incrementId: string;
|
|
10
|
+
/** Short increment name (e.g., "sync-architecture-fix") */
|
|
11
|
+
incrementName: string;
|
|
12
|
+
/** Total number of tasks in tasks.md */
|
|
13
|
+
totalTasks: number;
|
|
14
|
+
/** Number of completed tasks ([x]) */
|
|
15
|
+
completedTasks: number;
|
|
16
|
+
/** Completion percentage (0-100) */
|
|
17
|
+
percentage: number;
|
|
18
|
+
/** Current task being worked on */
|
|
19
|
+
currentTask: TaskInfo | null;
|
|
20
|
+
/** ISO timestamp of last cache update */
|
|
21
|
+
lastUpdate: string;
|
|
22
|
+
/** Unix timestamp of tasks.md mtime (for invalidation) */
|
|
23
|
+
lastModified: number;
|
|
24
|
+
}
|
|
25
|
+
export interface TaskInfo {
|
|
26
|
+
/** Task ID (e.g., "T-016") */
|
|
27
|
+
id: string;
|
|
28
|
+
/** Task title (e.g., "Update documentation") */
|
|
29
|
+
title: string;
|
|
30
|
+
}
|
|
31
|
+
export interface StatusLineConfig {
|
|
32
|
+
/** Enable status line rendering */
|
|
33
|
+
enabled: boolean;
|
|
34
|
+
/** Maximum age of cache before forcing refresh (ms) */
|
|
35
|
+
maxCacheAge: number;
|
|
36
|
+
/** Width of progress bar (characters) */
|
|
37
|
+
progressBarWidth: number;
|
|
38
|
+
/** Maximum length for increment name */
|
|
39
|
+
maxIncrementNameLength: number;
|
|
40
|
+
/** Maximum length for task title */
|
|
41
|
+
maxTaskTitleLength: number;
|
|
42
|
+
/** Show progress bar */
|
|
43
|
+
showProgressBar: boolean;
|
|
44
|
+
/** Show percentage */
|
|
45
|
+
showPercentage: boolean;
|
|
46
|
+
/** Show current task */
|
|
47
|
+
showCurrentTask: boolean;
|
|
48
|
+
}
|
|
49
|
+
export declare const DEFAULT_STATUS_LINE_CONFIG: StatusLineConfig;
|
|
50
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/status-line/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,eAAe;IAC9B,+DAA+D;IAC/D,WAAW,EAAE,MAAM,CAAC;IAEpB,2DAA2D;IAC3D,aAAa,EAAE,MAAM,CAAC;IAEtB,wCAAwC;IACxC,UAAU,EAAE,MAAM,CAAC;IAEnB,sCAAsC;IACtC,cAAc,EAAE,MAAM,CAAC;IAEvB,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAC;IAEnB,mCAAmC;IACnC,WAAW,EAAE,QAAQ,GAAG,IAAI,CAAC;IAE7B,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;IAEnB,0DAA0D;IAC1D,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,8BAA8B;IAC9B,EAAE,EAAE,MAAM,CAAC;IAEX,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,mCAAmC;IACnC,OAAO,EAAE,OAAO,CAAC;IAEjB,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IAEpB,yCAAyC;IACzC,gBAAgB,EAAE,MAAM,CAAC;IAEzB,wCAAwC;IACxC,sBAAsB,EAAE,MAAM,CAAC;IAE/B,oCAAoC;IACpC,kBAAkB,EAAE,MAAM,CAAC;IAE3B,wBAAwB;IACxB,eAAe,EAAE,OAAO,CAAC;IAEzB,sBAAsB;IACtB,cAAc,EAAE,OAAO,CAAC;IAExB,wBAAwB;IACxB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,eAAO,MAAM,0BAA0B,EAAE,gBASxC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Status Line Types
|
|
3
|
+
*
|
|
4
|
+
* Type definitions for the fast status line caching system.
|
|
5
|
+
* Supports <1ms rendering with intelligent cache invalidation.
|
|
6
|
+
*/
|
|
7
|
+
export const DEFAULT_STATUS_LINE_CONFIG = {
|
|
8
|
+
enabled: true,
|
|
9
|
+
maxCacheAge: 5000, // 5 seconds
|
|
10
|
+
progressBarWidth: 8,
|
|
11
|
+
maxIncrementNameLength: 20,
|
|
12
|
+
maxTaskTitleLength: 30,
|
|
13
|
+
showProgressBar: true,
|
|
14
|
+
showPercentage: true,
|
|
15
|
+
showCurrentTask: true,
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/status-line/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA8DH,MAAM,CAAC,MAAM,0BAA0B,GAAqB;IAC1D,OAAO,EAAE,IAAI;IACb,WAAW,EAAE,IAAI,EAAE,YAAY;IAC/B,gBAAgB,EAAE,CAAC;IACnB,sBAAsB,EAAE,EAAE;IAC1B,kBAAkB,EAAE,EAAE;IACtB,eAAe,EAAE,IAAI;IACrB,cAAc,EAAE,IAAI;IACpB,eAAe,EAAE,IAAI;CACtB,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Mapper - Intelligent User Story to Project Classification
|
|
3
|
+
*
|
|
4
|
+
* Analyzes user story content, tech stack mentions, and component architecture
|
|
5
|
+
* to intelligently map user stories to the correct projects (FE, BE, MOBILE, etc.)
|
|
6
|
+
*
|
|
7
|
+
* @module project-mapper
|
|
8
|
+
*/
|
|
9
|
+
export interface ProjectMapping {
|
|
10
|
+
projectId: string;
|
|
11
|
+
confidence: number;
|
|
12
|
+
reasoning: string[];
|
|
13
|
+
}
|
|
14
|
+
export interface UserStory {
|
|
15
|
+
id: string;
|
|
16
|
+
title: string;
|
|
17
|
+
description: string;
|
|
18
|
+
acceptanceCriteria: string[];
|
|
19
|
+
technicalContext?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface ProjectRule {
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
keywords: string[];
|
|
25
|
+
techStack: string[];
|
|
26
|
+
componentTypes: string[];
|
|
27
|
+
excludeKeywords?: string[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Default project mapping rules
|
|
31
|
+
* These can be customized via .specweave/config.json
|
|
32
|
+
*/
|
|
33
|
+
export declare const DEFAULT_PROJECT_RULES: ProjectRule[];
|
|
34
|
+
/**
|
|
35
|
+
* Analyze user story content and map to projects
|
|
36
|
+
*
|
|
37
|
+
* @param userStory User story to analyze
|
|
38
|
+
* @param projectRules Project mapping rules (defaults to DEFAULT_PROJECT_RULES)
|
|
39
|
+
* @returns Array of project mappings sorted by confidence (highest first)
|
|
40
|
+
*/
|
|
41
|
+
export declare function mapUserStoryToProjects(userStory: UserStory, projectRules?: ProjectRule[]): ProjectMapping[];
|
|
42
|
+
/**
|
|
43
|
+
* Determine primary project for a user story
|
|
44
|
+
* (highest confidence mapping)
|
|
45
|
+
*
|
|
46
|
+
* @param userStory User story to analyze
|
|
47
|
+
* @param projectRules Project mapping rules
|
|
48
|
+
* @returns Primary project mapping or null if no confident match
|
|
49
|
+
*/
|
|
50
|
+
export declare function getPrimaryProject(userStory: UserStory, projectRules?: ProjectRule[]): ProjectMapping | null;
|
|
51
|
+
/**
|
|
52
|
+
* Split spec into project-specific specs based on user story mappings
|
|
53
|
+
*
|
|
54
|
+
* @param userStories Array of user stories
|
|
55
|
+
* @param projectRules Project mapping rules
|
|
56
|
+
* @returns Map of projectId → user stories
|
|
57
|
+
*/
|
|
58
|
+
export declare function splitSpecByProject(userStories: UserStory[], projectRules?: ProjectRule[]): Map<string, UserStory[]>;
|
|
59
|
+
/**
|
|
60
|
+
* Suggest JIRA item type hierarchy based on user story scope
|
|
61
|
+
*
|
|
62
|
+
* @param userStory User story to analyze
|
|
63
|
+
* @returns Suggested JIRA item type (Epic, Story, Task, Subtask)
|
|
64
|
+
*/
|
|
65
|
+
export declare function suggestJiraItemType(userStory: UserStory): 'Epic' | 'Story' | 'Task' | 'Subtask';
|
|
66
|
+
/**
|
|
67
|
+
* Format project mapping report (for display to user)
|
|
68
|
+
*
|
|
69
|
+
* @param userStory User story
|
|
70
|
+
* @param mappings Project mappings
|
|
71
|
+
* @returns Formatted markdown report
|
|
72
|
+
*/
|
|
73
|
+
export declare function formatProjectMappingReport(userStory: UserStory, mappings: ProjectMapping[]): string;
|
|
74
|
+
//# sourceMappingURL=project-mapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-mapper.d.ts","sourceRoot":"","sources":["../../src/utils/project-mapper.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,WAAW,EAwF9C,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,SAAS,EACpB,YAAY,GAAE,WAAW,EAA0B,GAClD,cAAc,EAAE,CAiFlB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,SAAS,EACpB,YAAY,GAAE,WAAW,EAA0B,GAClD,cAAc,GAAG,IAAI,CAOvB;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,SAAS,EAAE,EACxB,YAAY,GAAE,WAAW,EAA0B,GAClD,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAmB1B;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAoB/F;AAeD;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,cAAc,EAAE,GACzB,MAAM,CA4BR"}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Mapper - Intelligent User Story to Project Classification
|
|
3
|
+
*
|
|
4
|
+
* Analyzes user story content, tech stack mentions, and component architecture
|
|
5
|
+
* to intelligently map user stories to the correct projects (FE, BE, MOBILE, etc.)
|
|
6
|
+
*
|
|
7
|
+
* @module project-mapper
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Default project mapping rules
|
|
11
|
+
* These can be customized via .specweave/config.json
|
|
12
|
+
*/
|
|
13
|
+
export const DEFAULT_PROJECT_RULES = [
|
|
14
|
+
{
|
|
15
|
+
id: 'FE',
|
|
16
|
+
name: 'Frontend (Web)',
|
|
17
|
+
keywords: [
|
|
18
|
+
'ui', 'ux', 'web', 'browser', 'chart', 'graph', 'visualization',
|
|
19
|
+
'dashboard', 'button', 'form', 'input', 'page', 'view', 'screen',
|
|
20
|
+
'modal', 'dropdown', 'navigation', 'menu', 'search', 'filter',
|
|
21
|
+
'responsive', 'desktop', 'tablet', 'css', 'styling', 'theme',
|
|
22
|
+
'dark mode', 'light mode', 'component', 'state management'
|
|
23
|
+
],
|
|
24
|
+
techStack: [
|
|
25
|
+
'react', 'vue', 'angular', 'next.js', 'gatsby', 'svelte',
|
|
26
|
+
'typescript', 'javascript', 'html', 'css', 'scss', 'tailwind',
|
|
27
|
+
'mui', 'material-ui', 'antd', 'chakra', 'redux', 'zustand',
|
|
28
|
+
'recharts', 'd3', 'chart.js', 'plotly'
|
|
29
|
+
],
|
|
30
|
+
componentTypes: [
|
|
31
|
+
'component', 'hook', 'context', 'provider', 'hoc', 'page',
|
|
32
|
+
'layout', 'template', 'widget'
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: 'BE',
|
|
37
|
+
name: 'Backend (API)',
|
|
38
|
+
keywords: [
|
|
39
|
+
'api', 'endpoint', 'rest', 'graphql', 'database', 'query',
|
|
40
|
+
'migration', 'schema', 'model', 'service', 'controller',
|
|
41
|
+
'authentication', 'authorization', 'jwt', 'session', 'token',
|
|
42
|
+
'validation', 'sanitization', 'rate limiting', 'caching',
|
|
43
|
+
'redis', 'queue', 'job', 'worker', 'webhook', 'integration',
|
|
44
|
+
'third-party', 'external api', 'data processing', 'batch',
|
|
45
|
+
'cron', 'scheduler', 'background'
|
|
46
|
+
],
|
|
47
|
+
techStack: [
|
|
48
|
+
'node.js', 'express', 'fastify', 'nestjs', 'koa',
|
|
49
|
+
'python', 'fastapi', 'django', 'flask',
|
|
50
|
+
'java', 'spring boot',
|
|
51
|
+
'.net', 'asp.net',
|
|
52
|
+
'go', 'gin',
|
|
53
|
+
'rust', 'actix',
|
|
54
|
+
'postgresql', 'mysql', 'mongodb', 'redis',
|
|
55
|
+
'prisma', 'typeorm', 'sequelize', 'sqlalchemy'
|
|
56
|
+
],
|
|
57
|
+
componentTypes: [
|
|
58
|
+
'controller', 'service', 'repository', 'middleware',
|
|
59
|
+
'route', 'handler', 'util', 'helper', 'validator'
|
|
60
|
+
]
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
id: 'MOBILE',
|
|
64
|
+
name: 'Mobile (iOS/Android)',
|
|
65
|
+
keywords: [
|
|
66
|
+
'mobile', 'ios', 'android', 'app', 'native', 'cross-platform',
|
|
67
|
+
'push notification', 'offline', 'sync', 'device', 'camera',
|
|
68
|
+
'gps', 'location', 'gesture', 'touch', 'swipe', 'navigation',
|
|
69
|
+
'tab bar', 'bottom sheet', 'drawer', 'stack', 'screen transition',
|
|
70
|
+
'deep linking', 'universal link', 'app store', 'play store'
|
|
71
|
+
],
|
|
72
|
+
techStack: [
|
|
73
|
+
'react native', 'expo', 'flutter', 'swift', 'swiftui',
|
|
74
|
+
'kotlin', 'jetpack compose', 'xamarin', 'cordova', 'ionic',
|
|
75
|
+
'react-navigation', 'react-native-reanimated', 'asyncstorage'
|
|
76
|
+
],
|
|
77
|
+
componentTypes: [
|
|
78
|
+
'screen', 'navigator', 'modal', 'bottom-sheet', 'drawer'
|
|
79
|
+
],
|
|
80
|
+
excludeKeywords: ['web']
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: 'INFRA',
|
|
84
|
+
name: 'Infrastructure',
|
|
85
|
+
keywords: [
|
|
86
|
+
'deployment', 'ci/cd', 'docker', 'kubernetes', 'helm',
|
|
87
|
+
'terraform', 'cloudformation', 'infrastructure', 'devops',
|
|
88
|
+
'monitoring', 'logging', 'metrics', 'alerting', 'slo', 'sli',
|
|
89
|
+
'scalability', 'load balancing', 'cdn', 'dns', 'ssl', 'tls',
|
|
90
|
+
'security', 'firewall', 'vpc', 'network', 'backup', 'disaster recovery'
|
|
91
|
+
],
|
|
92
|
+
techStack: [
|
|
93
|
+
'aws', 'azure', 'gcp', 'kubernetes', 'docker', 'terraform',
|
|
94
|
+
'ansible', 'jenkins', 'github actions', 'gitlab ci', 'circleci',
|
|
95
|
+
'prometheus', 'grafana', 'datadog', 'new relic', 'sentry'
|
|
96
|
+
],
|
|
97
|
+
componentTypes: [
|
|
98
|
+
'pipeline', 'manifest', 'helm chart', 'terraform module'
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
];
|
|
102
|
+
/**
|
|
103
|
+
* Analyze user story content and map to projects
|
|
104
|
+
*
|
|
105
|
+
* @param userStory User story to analyze
|
|
106
|
+
* @param projectRules Project mapping rules (defaults to DEFAULT_PROJECT_RULES)
|
|
107
|
+
* @returns Array of project mappings sorted by confidence (highest first)
|
|
108
|
+
*/
|
|
109
|
+
export function mapUserStoryToProjects(userStory, projectRules = DEFAULT_PROJECT_RULES) {
|
|
110
|
+
const mappings = [];
|
|
111
|
+
// Combine all user story text for analysis
|
|
112
|
+
const fullText = [
|
|
113
|
+
userStory.title,
|
|
114
|
+
userStory.description,
|
|
115
|
+
...userStory.acceptanceCriteria,
|
|
116
|
+
userStory.technicalContext || ''
|
|
117
|
+
].join(' ').toLowerCase();
|
|
118
|
+
for (const rule of projectRules) {
|
|
119
|
+
const reasoning = [];
|
|
120
|
+
let score = 0;
|
|
121
|
+
let maxScore = 0;
|
|
122
|
+
// Keyword matching (40% weight)
|
|
123
|
+
const keywordMatches = rule.keywords.filter(keyword => fullText.includes(keyword.toLowerCase()));
|
|
124
|
+
const keywordScore = keywordMatches.length * 0.4;
|
|
125
|
+
score += keywordScore;
|
|
126
|
+
maxScore += rule.keywords.length * 0.4;
|
|
127
|
+
if (keywordMatches.length > 0) {
|
|
128
|
+
reasoning.push(`Keywords: ${keywordMatches.slice(0, 5).join(', ')}`);
|
|
129
|
+
}
|
|
130
|
+
// Tech stack matching (40% weight)
|
|
131
|
+
const techStackMatches = rule.techStack.filter(tech => fullText.includes(tech.toLowerCase()));
|
|
132
|
+
const techScore = techStackMatches.length * 0.4;
|
|
133
|
+
score += techScore;
|
|
134
|
+
maxScore += rule.techStack.length * 0.4;
|
|
135
|
+
if (techStackMatches.length > 0) {
|
|
136
|
+
reasoning.push(`Tech stack: ${techStackMatches.slice(0, 5).join(', ')}`);
|
|
137
|
+
}
|
|
138
|
+
// Component type matching (20% weight)
|
|
139
|
+
const componentMatches = rule.componentTypes.filter(component => fullText.includes(component.toLowerCase()));
|
|
140
|
+
const componentScore = componentMatches.length * 0.2;
|
|
141
|
+
score += componentScore;
|
|
142
|
+
maxScore += rule.componentTypes.length * 0.2;
|
|
143
|
+
if (componentMatches.length > 0) {
|
|
144
|
+
reasoning.push(`Components: ${componentMatches.slice(0, 3).join(', ')}`);
|
|
145
|
+
}
|
|
146
|
+
// Exclude keywords (penalty)
|
|
147
|
+
if (rule.excludeKeywords) {
|
|
148
|
+
const excludeMatches = rule.excludeKeywords.filter(keyword => fullText.includes(keyword.toLowerCase()));
|
|
149
|
+
if (excludeMatches.length > 0) {
|
|
150
|
+
score *= 0.5; // 50% penalty
|
|
151
|
+
reasoning.push(`Penalty: ${excludeMatches.join(', ')} (not primary focus)`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// Normalize confidence (0.0-1.0)
|
|
155
|
+
const confidence = maxScore > 0 ? Math.min(score / (maxScore * 0.3), 1.0) : 0;
|
|
156
|
+
// Only include mappings with confidence > 0.1
|
|
157
|
+
if (confidence > 0.1) {
|
|
158
|
+
mappings.push({
|
|
159
|
+
projectId: rule.id,
|
|
160
|
+
confidence,
|
|
161
|
+
reasoning
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// Sort by confidence (highest first)
|
|
166
|
+
mappings.sort((a, b) => b.confidence - a.confidence);
|
|
167
|
+
return mappings;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Determine primary project for a user story
|
|
171
|
+
* (highest confidence mapping)
|
|
172
|
+
*
|
|
173
|
+
* @param userStory User story to analyze
|
|
174
|
+
* @param projectRules Project mapping rules
|
|
175
|
+
* @returns Primary project mapping or null if no confident match
|
|
176
|
+
*/
|
|
177
|
+
export function getPrimaryProject(userStory, projectRules = DEFAULT_PROJECT_RULES) {
|
|
178
|
+
const mappings = mapUserStoryToProjects(userStory, projectRules);
|
|
179
|
+
// Require at least 30% confidence for primary project
|
|
180
|
+
return mappings.length > 0 && mappings[0].confidence >= 0.3
|
|
181
|
+
? mappings[0]
|
|
182
|
+
: null;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Split spec into project-specific specs based on user story mappings
|
|
186
|
+
*
|
|
187
|
+
* @param userStories Array of user stories
|
|
188
|
+
* @param projectRules Project mapping rules
|
|
189
|
+
* @returns Map of projectId → user stories
|
|
190
|
+
*/
|
|
191
|
+
export function splitSpecByProject(userStories, projectRules = DEFAULT_PROJECT_RULES) {
|
|
192
|
+
const projectSpecs = new Map();
|
|
193
|
+
for (const userStory of userStories) {
|
|
194
|
+
const primaryProject = getPrimaryProject(userStory, projectRules);
|
|
195
|
+
if (primaryProject) {
|
|
196
|
+
const existing = projectSpecs.get(primaryProject.projectId) || [];
|
|
197
|
+
existing.push(userStory);
|
|
198
|
+
projectSpecs.set(primaryProject.projectId, existing);
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
// No confident match - assign to "SHARED" or primary project
|
|
202
|
+
const shared = projectSpecs.get('SHARED') || [];
|
|
203
|
+
shared.push(userStory);
|
|
204
|
+
projectSpecs.set('SHARED', shared);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return projectSpecs;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Suggest JIRA item type hierarchy based on user story scope
|
|
211
|
+
*
|
|
212
|
+
* @param userStory User story to analyze
|
|
213
|
+
* @returns Suggested JIRA item type (Epic, Story, Task, Subtask)
|
|
214
|
+
*/
|
|
215
|
+
export function suggestJiraItemType(userStory) {
|
|
216
|
+
const storyPoints = estimateStoryPoints(userStory);
|
|
217
|
+
// Epic: > 13 story points (large feature area)
|
|
218
|
+
if (storyPoints > 13) {
|
|
219
|
+
return 'Epic';
|
|
220
|
+
}
|
|
221
|
+
// Story: 3-13 story points (standard user story)
|
|
222
|
+
if (storyPoints >= 3) {
|
|
223
|
+
return 'Story';
|
|
224
|
+
}
|
|
225
|
+
// Task: 1-2 story points (small implementation task)
|
|
226
|
+
if (storyPoints >= 1) {
|
|
227
|
+
return 'Task';
|
|
228
|
+
}
|
|
229
|
+
// Subtask: < 1 story point (granular work)
|
|
230
|
+
return 'Subtask';
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Estimate story points based on acceptance criteria count and complexity
|
|
234
|
+
*
|
|
235
|
+
* @param userStory User story to estimate
|
|
236
|
+
* @returns Estimated story points (1-21)
|
|
237
|
+
*/
|
|
238
|
+
function estimateStoryPoints(userStory) {
|
|
239
|
+
const acCount = userStory.acceptanceCriteria.length;
|
|
240
|
+
// Simple heuristic: 1 AC ≈ 1 story point, max 21
|
|
241
|
+
return Math.min(acCount, 21);
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Format project mapping report (for display to user)
|
|
245
|
+
*
|
|
246
|
+
* @param userStory User story
|
|
247
|
+
* @param mappings Project mappings
|
|
248
|
+
* @returns Formatted markdown report
|
|
249
|
+
*/
|
|
250
|
+
export function formatProjectMappingReport(userStory, mappings) {
|
|
251
|
+
const lines = [];
|
|
252
|
+
lines.push(`## ${userStory.id}: ${userStory.title}`);
|
|
253
|
+
lines.push('');
|
|
254
|
+
if (mappings.length === 0) {
|
|
255
|
+
lines.push('❌ **No project match** (assign to SHARED)');
|
|
256
|
+
return lines.join('\n');
|
|
257
|
+
}
|
|
258
|
+
lines.push(`✅ **Primary Project**: ${mappings[0].projectId} (${(mappings[0].confidence * 100).toFixed(0)}% confidence)`);
|
|
259
|
+
lines.push('');
|
|
260
|
+
lines.push('**Reasoning**:');
|
|
261
|
+
for (const reason of mappings[0].reasoning) {
|
|
262
|
+
lines.push(`- ${reason}`);
|
|
263
|
+
}
|
|
264
|
+
if (mappings.length > 1) {
|
|
265
|
+
lines.push('');
|
|
266
|
+
lines.push('**Secondary Matches**:');
|
|
267
|
+
for (const mapping of mappings.slice(1, 3)) {
|
|
268
|
+
lines.push(`- ${mapping.projectId} (${(mapping.confidence * 100).toFixed(0)}%)`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return lines.join('\n');
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=project-mapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-mapper.js","sourceRoot":"","sources":["../../src/utils/project-mapper.ts"],"names":[],"mappings":"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"}
|