specweave 0.7.0 → 0.8.1
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 +307 -11
- package/README.md +41 -3
- package/dist/cli/commands/import-docs.d.ts +21 -0
- package/dist/cli/commands/import-docs.d.ts.map +1 -0
- package/dist/cli/commands/import-docs.js +146 -0
- package/dist/cli/commands/import-docs.js.map +1 -0
- package/dist/cli/commands/init-multiproject.d.ts +11 -0
- package/dist/cli/commands/init-multiproject.d.ts.map +1 -0
- package/dist/cli/commands/init-multiproject.js +202 -0
- package/dist/cli/commands/init-multiproject.js.map +1 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +7 -3
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/migrate-to-multiproject.d.ts +37 -0
- package/dist/cli/commands/migrate-to-multiproject.d.ts.map +1 -0
- package/dist/cli/commands/migrate-to-multiproject.js +189 -0
- package/dist/cli/commands/migrate-to-multiproject.js.map +1 -0
- package/dist/cli/commands/migrate-to-profiles.d.ts +25 -0
- package/dist/cli/commands/migrate-to-profiles.d.ts.map +1 -0
- package/dist/cli/commands/migrate-to-profiles.js +350 -0
- package/dist/cli/commands/migrate-to-profiles.js.map +1 -0
- package/dist/cli/commands/switch-project.d.ts +13 -0
- package/dist/cli/commands/switch-project.d.ts.map +1 -0
- package/dist/cli/commands/switch-project.js +91 -0
- package/dist/cli/commands/switch-project.js.map +1 -0
- package/dist/cli/helpers/issue-tracker/index.js +4 -4
- package/dist/cli/helpers/issue-tracker/index.js.map +1 -1
- package/dist/cli/helpers/issue-tracker/utils.d.ts +6 -3
- package/dist/cli/helpers/issue-tracker/utils.d.ts.map +1 -1
- package/dist/cli/helpers/issue-tracker/utils.js +9 -7
- package/dist/cli/helpers/issue-tracker/utils.js.map +1 -1
- package/dist/core/brownfield/analyzer.d.ts +86 -0
- package/dist/core/brownfield/analyzer.d.ts.map +1 -0
- package/dist/core/brownfield/analyzer.js +365 -0
- package/dist/core/brownfield/analyzer.js.map +1 -0
- package/dist/core/brownfield/importer.d.ts +76 -0
- package/dist/core/brownfield/importer.d.ts.map +1 -0
- package/dist/core/brownfield/importer.js +287 -0
- package/dist/core/brownfield/importer.js.map +1 -0
- package/dist/core/config-manager.d.ts +47 -0
- package/dist/core/config-manager.d.ts.map +1 -0
- package/dist/core/config-manager.js +136 -0
- package/dist/core/config-manager.js.map +1 -0
- package/dist/core/project-manager.d.ts +127 -0
- package/dist/core/project-manager.d.ts.map +1 -0
- package/dist/core/project-manager.js +524 -0
- package/dist/core/project-manager.js.map +1 -0
- package/dist/core/sync/profile-manager.d.ts +72 -0
- package/dist/core/sync/profile-manager.d.ts.map +1 -0
- package/dist/core/sync/profile-manager.js +338 -0
- package/dist/core/sync/profile-manager.js.map +1 -0
- package/dist/core/sync/profile-selector.d.ts +52 -0
- package/dist/core/sync/profile-selector.d.ts.map +1 -0
- package/dist/core/sync/profile-selector.js +179 -0
- package/dist/core/sync/profile-selector.js.map +1 -0
- package/dist/core/sync/project-context.d.ts +81 -0
- package/dist/core/sync/project-context.d.ts.map +1 -0
- package/dist/core/sync/project-context.js +354 -0
- package/dist/core/sync/project-context.js.map +1 -0
- package/dist/core/sync/rate-limiter.d.ts +116 -0
- package/dist/core/sync/rate-limiter.d.ts.map +1 -0
- package/dist/core/sync/rate-limiter.js +308 -0
- package/dist/core/sync/rate-limiter.js.map +1 -0
- package/dist/core/sync/time-range-selector.d.ts +48 -0
- package/dist/core/sync/time-range-selector.d.ts.map +1 -0
- package/dist/core/sync/time-range-selector.js +224 -0
- package/dist/core/sync/time-range-selector.js.map +1 -0
- package/dist/core/types/config.d.ts +4 -0
- package/dist/core/types/config.d.ts.map +1 -1
- package/dist/core/types/config.js.map +1 -1
- package/dist/core/types/sync-profile.d.ts +205 -0
- package/dist/core/types/sync-profile.d.ts.map +1 -0
- package/dist/core/types/sync-profile.js +8 -0
- package/dist/core/types/sync-profile.js.map +1 -0
- package/dist/utils/project-detection.d.ts +141 -0
- package/dist/utils/project-detection.d.ts.map +1 -0
- package/dist/utils/project-detection.js +321 -0
- package/dist/utils/project-detection.js.map +1 -0
- package/package.json +2 -1
- package/plugins/specweave/agents/pm/AGENT.md +7 -4
- package/plugins/specweave/commands/specweave-abandon.md +17 -17
- package/plugins/specweave/commands/specweave-check-tests.md +14 -14
- package/plugins/specweave/commands/specweave-costs.md +1 -1
- package/plugins/specweave/commands/specweave-do.md +12 -12
- package/plugins/specweave/commands/specweave-done.md +28 -15
- package/plugins/specweave/commands/specweave-import-docs.md +212 -0
- package/plugins/specweave/commands/specweave-increment.md +10 -10
- package/plugins/specweave/commands/specweave-init-multiproject.md +146 -0
- package/plugins/specweave/commands/specweave-next.md +16 -16
- package/plugins/specweave/commands/specweave-pause.md +17 -17
- package/plugins/specweave/commands/specweave-progress.md +10 -10
- package/plugins/specweave/commands/specweave-qa.md +11 -11
- package/plugins/specweave/commands/specweave-resume.md +22 -22
- package/plugins/specweave/commands/specweave-status.md +18 -18
- package/plugins/specweave/commands/specweave-switch-project.md +168 -0
- package/plugins/specweave/commands/specweave-sync-docs.md +1 -1
- package/plugins/specweave/commands/specweave-sync-tasks.md +9 -9
- package/plugins/specweave/commands/specweave-tdd-cycle.md +7 -0
- package/plugins/specweave/commands/specweave-tdd-green.md +7 -0
- package/plugins/specweave/commands/specweave-tdd-red.md +7 -0
- package/plugins/specweave/commands/specweave-tdd-refactor.md +7 -0
- package/plugins/specweave/commands/specweave-translate.md +1 -1
- package/plugins/specweave/commands/specweave-update-scope.md +8 -8
- package/plugins/specweave/commands/specweave-validate.md +18 -20
- package/plugins/specweave/commands/specweave.md +5 -5
- package/plugins/specweave/skills/SKILLS-INDEX.md +1 -1
- package/plugins/specweave/skills/increment-planner/SKILL.md +40 -4
- package/plugins/specweave/skills/increment-quality-judge/SKILL.md +5 -5
- package/plugins/specweave/skills/increment-quality-judge-v2/SKILL.md +5 -5
- package/plugins/specweave/skills/specweave-detector/SKILL.md +3 -3
- package/plugins/specweave-ado/commands/{close-workitem.md → specweave-ado-close-workitem.md} +1 -1
- package/plugins/specweave-ado/commands/{create-workitem.md → specweave-ado-create-workitem.md} +1 -1
- package/plugins/specweave-ado/commands/{status.md → specweave-ado-status.md} +1 -1
- package/plugins/specweave-ado/commands/{sync.md → specweave-ado-sync.md} +1 -1
- package/plugins/specweave-ado/lib/ado-client-v2.ts +547 -0
- package/plugins/specweave-github/commands/{close-issue.md → specweave-github-close-issue.md} +1 -1
- package/plugins/specweave-github/commands/{create-issue.md → specweave-github-create-issue.md} +1 -1
- package/plugins/specweave-github/commands/{status.md → specweave-github-status.md} +1 -1
- package/plugins/specweave-github/commands/{sync-tasks.md → specweave-github-sync-tasks.md} +1 -1
- package/plugins/specweave-github/commands/specweave-github-sync.md +568 -0
- package/plugins/specweave-github/lib/github-client-v2.ts +555 -0
- package/plugins/specweave-infrastructure/commands/{monitor-setup.md → specweave-infrastructure-monitor-setup.md} +1 -1
- package/plugins/specweave-infrastructure/commands/{slo-implement.md → specweave-infrastructure-slo-implement.md} +1 -1
- package/plugins/specweave-jira/commands/{sync.md → specweave-jira-sync.md} +1 -1
- package/plugins/specweave-jira/lib/jira-client-v2.ts +529 -0
- package/plugins/specweave-ml/commands/{ml-deploy.md → specweave-ml-deploy.md} +1 -1
- package/plugins/specweave-ml/commands/{ml-evaluate.md → specweave-ml-evaluate.md} +1 -1
- package/plugins/specweave-ml/commands/{ml-explain.md → specweave-ml-explain.md} +1 -1
- package/plugins/specweave-ml/commands/{ml-pipeline.md → specweave-ml-pipeline.md} +1 -1
- package/src/templates/AGENTS.md.template +1 -0
- package/src/templates/CLAUDE.md.template +1 -0
- package/plugins/specweave-github/commands/sync.md +0 -443
- /package/plugins/specweave/{commands/README.md → COMMANDS.md} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-context.d.ts","sourceRoot":"","sources":["../../../src/core/sync/project-context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,iBAAiB,EAClB,MAAM,uBAAuB,CAAC;AAE/B,qBAAa,qBAAqB;IAChC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,MAAM,CAAkC;gBAEpC,WAAW,EAAE,MAAM;IAS/B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAqCxC;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAgC3B;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAK/D;;OAEG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAKnE;;OAEG;IACG,aAAa,CACjB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,GAClC,OAAO,CAAC,IAAI,CAAC;IA2ChB;;OAEG;IACG,aAAa,CACjB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC,GAC3C,OAAO,CAAC,IAAI,CAAC;IAkBhB;;OAEG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBnF;;;;;OAKG;IACG,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAiEzE;;OAEG;IACG,sBAAsB,CAC1B,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC;IAmBhB;;OAEG;IACG,0BAA0B,CAC9B,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC;IAkBhB;;OAEG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAIzC;;OAEG;IACG,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAY3D;;OAEG;IACG,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAyB3D;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA8B7B;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC;QACxB,aAAa,EAAE,MAAM,CAAC;QACtB,eAAe,EAAE,MAAM,CAAC;QACxB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACxC,CAAC;CAqBH"}
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Context Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages project contexts for multi-project sync.
|
|
5
|
+
* Handles project detection, specs folder organization, and project-increment mapping.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from 'fs-extra';
|
|
8
|
+
import * as path from 'path';
|
|
9
|
+
export class ProjectContextManager {
|
|
10
|
+
constructor(projectRoot) {
|
|
11
|
+
this.config = null;
|
|
12
|
+
this.projectRoot = projectRoot;
|
|
13
|
+
this.configPath = path.join(projectRoot, '.specweave', 'config.json');
|
|
14
|
+
}
|
|
15
|
+
// ==========================================================================
|
|
16
|
+
// Load/Save Operations
|
|
17
|
+
// ==========================================================================
|
|
18
|
+
/**
|
|
19
|
+
* Load sync configuration
|
|
20
|
+
*/
|
|
21
|
+
async load() {
|
|
22
|
+
if (this.config) {
|
|
23
|
+
return this.config;
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const content = await fs.readFile(this.configPath, 'utf-8');
|
|
27
|
+
const fullConfig = JSON.parse(content);
|
|
28
|
+
this.config = fullConfig.sync || {
|
|
29
|
+
profiles: {},
|
|
30
|
+
projects: {},
|
|
31
|
+
settings: {
|
|
32
|
+
autoDetectProject: true,
|
|
33
|
+
defaultTimeRange: '1M',
|
|
34
|
+
rateLimitProtection: true,
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
return this.config;
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
if (error.code === 'ENOENT') {
|
|
41
|
+
this.config = {
|
|
42
|
+
profiles: {},
|
|
43
|
+
projects: {},
|
|
44
|
+
settings: {
|
|
45
|
+
autoDetectProject: true,
|
|
46
|
+
defaultTimeRange: '1M',
|
|
47
|
+
rateLimitProtection: true,
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
return this.config;
|
|
51
|
+
}
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Save sync configuration
|
|
57
|
+
*/
|
|
58
|
+
async save() {
|
|
59
|
+
if (!this.config) {
|
|
60
|
+
throw new Error('No configuration loaded. Call load() first.');
|
|
61
|
+
}
|
|
62
|
+
// Read full config
|
|
63
|
+
let fullConfig = {};
|
|
64
|
+
try {
|
|
65
|
+
const content = await fs.readFile(this.configPath, 'utf-8');
|
|
66
|
+
fullConfig = JSON.parse(content);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
if (error.code !== 'ENOENT') {
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Merge sync section
|
|
74
|
+
fullConfig.sync = this.config;
|
|
75
|
+
// Write back
|
|
76
|
+
await fs.ensureDir(path.dirname(this.configPath));
|
|
77
|
+
await fs.writeFile(this.configPath, JSON.stringify(fullConfig, null, 2), 'utf-8');
|
|
78
|
+
}
|
|
79
|
+
// ==========================================================================
|
|
80
|
+
// Project CRUD Operations
|
|
81
|
+
// ==========================================================================
|
|
82
|
+
/**
|
|
83
|
+
* Get all projects
|
|
84
|
+
*/
|
|
85
|
+
async getAllProjects() {
|
|
86
|
+
const config = await this.load();
|
|
87
|
+
return config.projects || {};
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Get a specific project by ID
|
|
91
|
+
*/
|
|
92
|
+
async getProject(projectId) {
|
|
93
|
+
const config = await this.load();
|
|
94
|
+
return config.projects?.[projectId] || null;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Create a new project context
|
|
98
|
+
*/
|
|
99
|
+
async createProject(projectId, project) {
|
|
100
|
+
const config = await this.load();
|
|
101
|
+
// Validate ID format
|
|
102
|
+
if (!/^[a-z0-9-]+$/.test(projectId)) {
|
|
103
|
+
throw new Error('Project ID must contain only lowercase letters, numbers, and hyphens');
|
|
104
|
+
}
|
|
105
|
+
// Check if project already exists
|
|
106
|
+
if (config.projects?.[projectId]) {
|
|
107
|
+
throw new Error(`Project '${projectId}' already exists`);
|
|
108
|
+
}
|
|
109
|
+
// Create specs folder
|
|
110
|
+
const specsFolder = project.specsFolder || `.specweave/docs/internal/specs/${projectId}`;
|
|
111
|
+
const fullPath = path.join(this.projectRoot, specsFolder);
|
|
112
|
+
await fs.ensureDir(fullPath);
|
|
113
|
+
// Create README for the project
|
|
114
|
+
const readmePath = path.join(fullPath, 'README.md');
|
|
115
|
+
await fs.writeFile(readmePath, this.generateProjectReadme(projectId, project), 'utf-8');
|
|
116
|
+
// Add project
|
|
117
|
+
if (!config.projects) {
|
|
118
|
+
config.projects = {};
|
|
119
|
+
}
|
|
120
|
+
config.projects[projectId] = {
|
|
121
|
+
id: projectId,
|
|
122
|
+
...project,
|
|
123
|
+
specsFolder,
|
|
124
|
+
increments: project.increments || [],
|
|
125
|
+
};
|
|
126
|
+
await this.save();
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Update a project context
|
|
130
|
+
*/
|
|
131
|
+
async updateProject(projectId, updates) {
|
|
132
|
+
const config = await this.load();
|
|
133
|
+
const existing = config.projects?.[projectId];
|
|
134
|
+
if (!existing) {
|
|
135
|
+
throw new Error(`Project '${projectId}' does not exist`);
|
|
136
|
+
}
|
|
137
|
+
// Merge updates
|
|
138
|
+
config.projects[projectId] = {
|
|
139
|
+
...existing,
|
|
140
|
+
...updates,
|
|
141
|
+
id: projectId, // Preserve ID
|
|
142
|
+
};
|
|
143
|
+
await this.save();
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Delete a project context
|
|
147
|
+
*/
|
|
148
|
+
async deleteProject(projectId, deleteSpecs = false) {
|
|
149
|
+
const config = await this.load();
|
|
150
|
+
const project = config.projects?.[projectId];
|
|
151
|
+
if (!project) {
|
|
152
|
+
throw new Error(`Project '${projectId}' does not exist`);
|
|
153
|
+
}
|
|
154
|
+
// Optionally delete specs folder
|
|
155
|
+
if (deleteSpecs && project.specsFolder) {
|
|
156
|
+
const fullPath = path.join(this.projectRoot, project.specsFolder);
|
|
157
|
+
await fs.remove(fullPath);
|
|
158
|
+
}
|
|
159
|
+
delete config.projects[projectId];
|
|
160
|
+
await this.save();
|
|
161
|
+
}
|
|
162
|
+
// ==========================================================================
|
|
163
|
+
// Project Detection
|
|
164
|
+
// ==========================================================================
|
|
165
|
+
/**
|
|
166
|
+
* Detect project from increment description
|
|
167
|
+
*
|
|
168
|
+
* @param description Increment description text
|
|
169
|
+
* @returns Detection result with matched project and confidence score
|
|
170
|
+
*/
|
|
171
|
+
async detectProject(description) {
|
|
172
|
+
const config = await this.load();
|
|
173
|
+
const projects = config.projects || {};
|
|
174
|
+
if (Object.keys(projects).length === 0) {
|
|
175
|
+
return {
|
|
176
|
+
confidence: 0,
|
|
177
|
+
matchedKeywords: [],
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
const lowerDesc = description.toLowerCase();
|
|
181
|
+
let bestMatch;
|
|
182
|
+
let bestScore = 0;
|
|
183
|
+
let bestKeywords = [];
|
|
184
|
+
for (const project of Object.values(projects)) {
|
|
185
|
+
let score = 0;
|
|
186
|
+
const matchedKeywords = [];
|
|
187
|
+
// Check project name
|
|
188
|
+
if (lowerDesc.includes(project.name.toLowerCase())) {
|
|
189
|
+
score += 10;
|
|
190
|
+
matchedKeywords.push(project.name);
|
|
191
|
+
}
|
|
192
|
+
// Check team name
|
|
193
|
+
if (project.team && lowerDesc.includes(project.team.toLowerCase())) {
|
|
194
|
+
score += 5;
|
|
195
|
+
matchedKeywords.push(project.team);
|
|
196
|
+
}
|
|
197
|
+
// Check keywords
|
|
198
|
+
for (const keyword of project.keywords) {
|
|
199
|
+
if (lowerDesc.includes(keyword.toLowerCase())) {
|
|
200
|
+
score += 3;
|
|
201
|
+
matchedKeywords.push(keyword);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// Update best match
|
|
205
|
+
if (score > bestScore) {
|
|
206
|
+
bestScore = score;
|
|
207
|
+
bestMatch = project;
|
|
208
|
+
bestKeywords = matchedKeywords;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// Calculate confidence (0-1)
|
|
212
|
+
const confidence = bestScore > 0 ? Math.min(bestScore / 10, 1) : 0;
|
|
213
|
+
const result = {
|
|
214
|
+
project: bestMatch,
|
|
215
|
+
confidence,
|
|
216
|
+
matchedKeywords: bestKeywords,
|
|
217
|
+
};
|
|
218
|
+
// Add suggested profile if project has default
|
|
219
|
+
if (bestMatch?.defaultSyncProfile) {
|
|
220
|
+
result.suggestedProfile = bestMatch.defaultSyncProfile;
|
|
221
|
+
}
|
|
222
|
+
return result;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Link increment to project
|
|
226
|
+
*/
|
|
227
|
+
async linkIncrementToProject(projectId, incrementId) {
|
|
228
|
+
const config = await this.load();
|
|
229
|
+
const project = config.projects?.[projectId];
|
|
230
|
+
if (!project) {
|
|
231
|
+
throw new Error(`Project '${projectId}' does not exist`);
|
|
232
|
+
}
|
|
233
|
+
// Add increment to project's increments list
|
|
234
|
+
if (!project.increments) {
|
|
235
|
+
project.increments = [];
|
|
236
|
+
}
|
|
237
|
+
if (!project.increments.includes(incrementId)) {
|
|
238
|
+
project.increments.push(incrementId);
|
|
239
|
+
await this.save();
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Unlink increment from project
|
|
244
|
+
*/
|
|
245
|
+
async unlinkIncrementFromProject(projectId, incrementId) {
|
|
246
|
+
const config = await this.load();
|
|
247
|
+
const project = config.projects?.[projectId];
|
|
248
|
+
if (!project) {
|
|
249
|
+
throw new Error(`Project '${projectId}' does not exist`);
|
|
250
|
+
}
|
|
251
|
+
if (project.increments) {
|
|
252
|
+
project.increments = project.increments.filter((id) => id !== incrementId);
|
|
253
|
+
await this.save();
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
// ==========================================================================
|
|
257
|
+
// Specs Folder Management
|
|
258
|
+
// ==========================================================================
|
|
259
|
+
/**
|
|
260
|
+
* Get specs folder path for a project
|
|
261
|
+
*/
|
|
262
|
+
getSpecsFolder(projectId) {
|
|
263
|
+
return `.specweave/docs/internal/specs/${projectId}`;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Ensure specs folder exists for a project
|
|
267
|
+
*/
|
|
268
|
+
async ensureSpecsFolder(projectId) {
|
|
269
|
+
const project = await this.getProject(projectId);
|
|
270
|
+
if (!project) {
|
|
271
|
+
throw new Error(`Project '${projectId}' does not exist`);
|
|
272
|
+
}
|
|
273
|
+
const fullPath = path.join(this.projectRoot, project.specsFolder);
|
|
274
|
+
await fs.ensureDir(fullPath);
|
|
275
|
+
return project.specsFolder;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Get all spec files for a project
|
|
279
|
+
*/
|
|
280
|
+
async getProjectSpecs(projectId) {
|
|
281
|
+
const project = await this.getProject(projectId);
|
|
282
|
+
if (!project) {
|
|
283
|
+
throw new Error(`Project '${projectId}' does not exist`);
|
|
284
|
+
}
|
|
285
|
+
const fullPath = path.join(this.projectRoot, project.specsFolder);
|
|
286
|
+
try {
|
|
287
|
+
const files = await fs.readdir(fullPath);
|
|
288
|
+
return files
|
|
289
|
+
.filter((f) => f.startsWith('spec-') && f.endsWith('.md'))
|
|
290
|
+
.map((f) => path.join(project.specsFolder, f));
|
|
291
|
+
}
|
|
292
|
+
catch (error) {
|
|
293
|
+
if (error.code === 'ENOENT') {
|
|
294
|
+
return [];
|
|
295
|
+
}
|
|
296
|
+
throw error;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
// ==========================================================================
|
|
300
|
+
// Helper Methods
|
|
301
|
+
// ==========================================================================
|
|
302
|
+
/**
|
|
303
|
+
* Generate README for project specs folder
|
|
304
|
+
*/
|
|
305
|
+
generateProjectReadme(projectId, project) {
|
|
306
|
+
return `# ${project.name}
|
|
307
|
+
|
|
308
|
+
${project.description}
|
|
309
|
+
|
|
310
|
+
${project.team ? `**Team**: ${project.team}\n` : ''}
|
|
311
|
+
**Keywords**: ${project.keywords.join(', ')}
|
|
312
|
+
${project.defaultSyncProfile ? `**Default Sync**: ${project.defaultSyncProfile}\n` : ''}
|
|
313
|
+
|
|
314
|
+
## Specifications
|
|
315
|
+
|
|
316
|
+
This folder contains all specifications for the **${project.name}** project.
|
|
317
|
+
|
|
318
|
+
- Each spec file follows the format: \`spec-NNN-feature-area.md\`
|
|
319
|
+
- Specs are permanent, feature-level documentation
|
|
320
|
+
- Updated continuously as features evolve
|
|
321
|
+
|
|
322
|
+
## Related Increments
|
|
323
|
+
|
|
324
|
+
${project.increments && project.increments.length > 0
|
|
325
|
+
? project.increments.map((inc) => `- ${inc}`).join('\n')
|
|
326
|
+
: 'No increments yet.'}
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
**Last Updated**: ${new Date().toISOString().split('T')[0]}
|
|
331
|
+
`;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Get statistics about projects
|
|
335
|
+
*/
|
|
336
|
+
async getStats() {
|
|
337
|
+
const config = await this.load();
|
|
338
|
+
const projects = config.projects || {};
|
|
339
|
+
const stats = {
|
|
340
|
+
totalProjects: Object.keys(projects).length,
|
|
341
|
+
totalIncrements: 0,
|
|
342
|
+
projectsByTeam: {},
|
|
343
|
+
};
|
|
344
|
+
for (const project of Object.values(projects)) {
|
|
345
|
+
stats.totalIncrements += project.increments?.length || 0;
|
|
346
|
+
if (project.team) {
|
|
347
|
+
stats.projectsByTeam[project.team] =
|
|
348
|
+
(stats.projectsByTeam[project.team] || 0) + 1;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return stats;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
//# sourceMappingURL=project-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-context.js","sourceRoot":"","sources":["../../../src/core/sync/project-context.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rate Limiter for External Sync
|
|
3
|
+
*
|
|
4
|
+
* Provides rate limiting protection, estimation, and backoff strategies
|
|
5
|
+
* for GitHub, JIRA, and Azure DevOps sync operations.
|
|
6
|
+
*/
|
|
7
|
+
import { SyncProvider, TimeRangePreset, TimeRangeEstimate, RateLimitStatus } from '../types/sync-profile';
|
|
8
|
+
export declare const PROVIDER_RATE_LIMITS: {
|
|
9
|
+
readonly github: {
|
|
10
|
+
readonly limit: 5000;
|
|
11
|
+
readonly window: "1h";
|
|
12
|
+
readonly thresholds: {
|
|
13
|
+
readonly low: 250;
|
|
14
|
+
readonly medium: 1000;
|
|
15
|
+
readonly high: 2500;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
readonly jira: {
|
|
19
|
+
readonly limit: 100;
|
|
20
|
+
readonly window: "1m";
|
|
21
|
+
readonly thresholds: {
|
|
22
|
+
readonly low: 25;
|
|
23
|
+
readonly medium: 50;
|
|
24
|
+
readonly high: 75;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
readonly ado: {
|
|
28
|
+
readonly limit: 200;
|
|
29
|
+
readonly window: "5m";
|
|
30
|
+
readonly thresholds: {
|
|
31
|
+
readonly low: 50;
|
|
32
|
+
readonly medium: 100;
|
|
33
|
+
readonly high: 150;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
export declare class RateLimiter {
|
|
38
|
+
private provider;
|
|
39
|
+
constructor(provider: SyncProvider);
|
|
40
|
+
/**
|
|
41
|
+
* Estimate sync operation impact
|
|
42
|
+
*
|
|
43
|
+
* @param timeRange Time range preset
|
|
44
|
+
* @param customFactor Custom scaling factor (default: 1.0)
|
|
45
|
+
* @returns Estimate of items, API calls, duration, and impact
|
|
46
|
+
*/
|
|
47
|
+
estimateSync(timeRange: TimeRangePreset, customFactor?: number): TimeRangeEstimate;
|
|
48
|
+
/**
|
|
49
|
+
* Calculate rate limit impact level
|
|
50
|
+
*
|
|
51
|
+
* @param apiCalls Number of API calls
|
|
52
|
+
* @returns Impact level: low, medium, high, or critical
|
|
53
|
+
*/
|
|
54
|
+
private calculateImpact;
|
|
55
|
+
/**
|
|
56
|
+
* Check current rate limit status (provider-specific)
|
|
57
|
+
*
|
|
58
|
+
* @param client Provider client (e.g., GitHubClient)
|
|
59
|
+
* @returns Current rate limit status
|
|
60
|
+
*/
|
|
61
|
+
checkRateLimitStatus(client: any): Promise<RateLimitStatus | null>;
|
|
62
|
+
/**
|
|
63
|
+
* Check GitHub rate limit status
|
|
64
|
+
*/
|
|
65
|
+
private checkGitHubRateLimit;
|
|
66
|
+
/**
|
|
67
|
+
* Check JIRA rate limit status
|
|
68
|
+
* (JIRA doesn't expose rate limit info - return estimated)
|
|
69
|
+
*/
|
|
70
|
+
private checkJiraRateLimit;
|
|
71
|
+
/**
|
|
72
|
+
* Check Azure DevOps rate limit status
|
|
73
|
+
* (ADO doesn't expose rate limit info - return estimated)
|
|
74
|
+
*/
|
|
75
|
+
private checkAdoRateLimit;
|
|
76
|
+
/**
|
|
77
|
+
* Validate sync operation is safe to proceed
|
|
78
|
+
*
|
|
79
|
+
* @param estimate Sync estimate
|
|
80
|
+
* @param rateLimitStatus Current rate limit status (optional)
|
|
81
|
+
* @returns Validation result
|
|
82
|
+
*/
|
|
83
|
+
validateSync(estimate: TimeRangeEstimate, rateLimitStatus?: RateLimitStatus | null): {
|
|
84
|
+
safe: boolean;
|
|
85
|
+
warnings: string[];
|
|
86
|
+
blockers: string[];
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Get impact percentage for given API calls
|
|
90
|
+
*/
|
|
91
|
+
private getImpactPercentage;
|
|
92
|
+
/**
|
|
93
|
+
* Calculate backoff delay when rate limited
|
|
94
|
+
*
|
|
95
|
+
* @param attempt Current retry attempt (0-indexed)
|
|
96
|
+
* @param maxBackoff Maximum backoff in milliseconds (default: 5 minutes)
|
|
97
|
+
* @returns Delay in milliseconds
|
|
98
|
+
*/
|
|
99
|
+
calculateBackoff(attempt: number, maxBackoff?: number): number;
|
|
100
|
+
/**
|
|
101
|
+
* Wait for rate limit to reset
|
|
102
|
+
*
|
|
103
|
+
* @param resetAt ISO timestamp when rate limit resets
|
|
104
|
+
* @returns Promise that resolves when rate limit resets
|
|
105
|
+
*/
|
|
106
|
+
waitForReset(resetAt: string): Promise<void>;
|
|
107
|
+
/**
|
|
108
|
+
* Format estimate for display
|
|
109
|
+
*/
|
|
110
|
+
formatEstimate(estimate: TimeRangeEstimate): string;
|
|
111
|
+
/**
|
|
112
|
+
* Format rate limit status for display
|
|
113
|
+
*/
|
|
114
|
+
formatRateLimitStatus(status: RateLimitStatus): string;
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=rate-limiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../../src/core/sync/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACL,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,eAAe,EAChB,MAAM,uBAAuB,CAAC;AAM/B,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BvB,CAAC;AAkCX,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAe;gBAEnB,QAAQ,EAAE,YAAY;IAQlC;;;;;;OAMG;IACH,YAAY,CACV,SAAS,EAAE,eAAe,EAC1B,YAAY,GAAE,MAAY,GACzB,iBAAiB;IAsBpB;;;;;OAKG;IACH,OAAO,CAAC,eAAe;IAoBvB;;;;;OAKG;IACG,oBAAoB,CAAC,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAiBxE;;OAEG;YACW,oBAAoB;IA+BlC;;;OAGG;YACW,kBAAkB;IAYhC;;;OAGG;YACW,iBAAiB;IAgB/B;;;;;;OAMG;IACH,YAAY,CACV,QAAQ,EAAE,iBAAiB,EAC3B,eAAe,CAAC,EAAE,eAAe,GAAG,IAAI,GACvC;QACD,IAAI,EAAE,OAAO,CAAC;QACd,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB;IAoDD;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAS3B;;;;;;OAMG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,GAAE,MAAsB,GAAG,MAAM;IAM7E;;;;;OAKG;IACG,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBlD;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM;IAWnD;;OAEG;IACH,qBAAqB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM;CAOvD"}
|