specweave 0.8.17 → 0.8.19
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 +119 -27
- package/README.md +11 -3
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +74 -20
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/migrate-to-profiles.js +2 -2
- package/dist/cli/commands/migrate-to-profiles.js.map +1 -1
- package/dist/cli/helpers/issue-tracker/index.d.ts.map +1 -1
- package/dist/cli/helpers/issue-tracker/index.js +8 -3
- package/dist/cli/helpers/issue-tracker/index.js.map +1 -1
- package/dist/cli/helpers/issue-tracker/utils.d.ts +5 -2
- package/dist/cli/helpers/issue-tracker/utils.d.ts.map +1 -1
- package/dist/cli/helpers/issue-tracker/utils.js +13 -6
- package/dist/cli/helpers/issue-tracker/utils.js.map +1 -1
- package/dist/core/sync/bidirectional-engine.d.ts +110 -0
- package/dist/core/sync/bidirectional-engine.d.ts.map +1 -0
- package/dist/core/sync/bidirectional-engine.js +356 -0
- package/dist/core/sync/bidirectional-engine.js.map +1 -0
- package/dist/utils/agents-md-compiler.js +2 -2
- package/dist/utils/env-multi-project-parser.d.ts +210 -0
- package/dist/utils/env-multi-project-parser.d.ts.map +1 -0
- package/dist/utils/env-multi-project-parser.js +406 -0
- package/dist/utils/env-multi-project-parser.js.map +1 -0
- package/package.json +1 -1
- package/plugins/specweave/hooks/post-first-increment.sh +79 -0
- package/plugins/specweave/skills/increment-planner/SKILL.md +50 -16
- package/plugins/specweave/skills/plugin-expert/SKILL.md +344 -0
- package/plugins/specweave/skills/specweave-framework/SKILL.md +2 -2
- package/plugins/specweave/skills/translator/SKILL.md +29 -0
- package/plugins/specweave/skills/translator/SKILL.md.bak +172 -0
- package/plugins/specweave-jira/lib/project-selector.ts +323 -0
- package/plugins/specweave-jira/lib/reorganization-detector.ts +359 -0
- package/plugins/specweave-jira/lib/setup-wizard.ts +256 -0
- package/src/templates/.gitignore.template +1 -0
- package/plugins/specweave-jira/lib/jira-client-v2.ts +0 -529
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment Multi-Project Parser
|
|
3
|
+
*
|
|
4
|
+
* Parses comma-separated project lists from .env:
|
|
5
|
+
* - JIRA_PROJECT_KEYS=BACKEND,FRONTEND,MOBILE
|
|
6
|
+
* - GITHUB_REPOS=owner/backend-api,owner/frontend-web
|
|
7
|
+
* - AZURE_DEVOPS_PROJECTS=backend-api,frontend-web
|
|
8
|
+
*
|
|
9
|
+
* Auto-creates sync profiles for each project.
|
|
10
|
+
*/
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// Parsing Functions
|
|
13
|
+
// ============================================================================
|
|
14
|
+
/**
|
|
15
|
+
* Parse comma-separated list from environment variable
|
|
16
|
+
*
|
|
17
|
+
* Handles:
|
|
18
|
+
* - Comma separation
|
|
19
|
+
* - Whitespace trimming
|
|
20
|
+
* - Empty values filtering
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* parseCommaSeparated("BACKEND, FRONTEND, MOBILE")
|
|
24
|
+
* // Returns: ["BACKEND", "FRONTEND", "MOBILE"]
|
|
25
|
+
*/
|
|
26
|
+
export function parseCommaSeparated(value) {
|
|
27
|
+
if (!value) {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
return value
|
|
31
|
+
.split(',')
|
|
32
|
+
.map((item) => item.trim())
|
|
33
|
+
.filter((item) => item.length > 0);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Parse JIRA project keys from .env
|
|
37
|
+
*
|
|
38
|
+
* Reads:
|
|
39
|
+
* - JIRA_PROJECT_KEYS (comma-separated, NEW format)
|
|
40
|
+
* - JIRA_PROJECT_KEY (single, legacy format)
|
|
41
|
+
* - JIRA_DOMAIN, JIRA_EMAIL, JIRA_API_TOKEN (shared credentials)
|
|
42
|
+
*
|
|
43
|
+
* @returns Array of JIRA project configurations
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* // .env:
|
|
47
|
+
* // JIRA_PROJECT_KEYS=BACKEND,FRONTEND,MOBILE
|
|
48
|
+
* // JIRA_DOMAIN=mycompany.atlassian.net
|
|
49
|
+
* // JIRA_EMAIL=user@example.com
|
|
50
|
+
* // JIRA_API_TOKEN=abc123
|
|
51
|
+
*
|
|
52
|
+
* parseJiraProjects()
|
|
53
|
+
* // Returns: [
|
|
54
|
+
* // { projectKey: "BACKEND", domain: "...", email: "...", apiToken: "..." },
|
|
55
|
+
* // { projectKey: "FRONTEND", ... },
|
|
56
|
+
* // { projectKey: "MOBILE", ... }
|
|
57
|
+
* // ]
|
|
58
|
+
*/
|
|
59
|
+
export function parseJiraProjects() {
|
|
60
|
+
const domain = process.env.JIRA_DOMAIN;
|
|
61
|
+
const email = process.env.JIRA_EMAIL;
|
|
62
|
+
const apiToken = process.env.JIRA_API_TOKEN;
|
|
63
|
+
// Missing credentials → return empty array
|
|
64
|
+
if (!domain || !email || !apiToken) {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
// Try new format (JIRA_PROJECT_KEYS - plural)
|
|
68
|
+
const projectKeysStr = process.env.JIRA_PROJECT_KEYS;
|
|
69
|
+
if (projectKeysStr) {
|
|
70
|
+
const projectKeys = parseCommaSeparated(projectKeysStr);
|
|
71
|
+
return projectKeys.map((projectKey) => ({
|
|
72
|
+
projectKey,
|
|
73
|
+
domain,
|
|
74
|
+
email,
|
|
75
|
+
apiToken,
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
// Fallback to legacy format (JIRA_PROJECT_KEY - singular)
|
|
79
|
+
const legacyProjectKey = process.env.JIRA_PROJECT_KEY;
|
|
80
|
+
if (legacyProjectKey) {
|
|
81
|
+
return [
|
|
82
|
+
{
|
|
83
|
+
projectKey: legacyProjectKey.trim(),
|
|
84
|
+
domain,
|
|
85
|
+
email,
|
|
86
|
+
apiToken,
|
|
87
|
+
},
|
|
88
|
+
];
|
|
89
|
+
}
|
|
90
|
+
return [];
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Parse GitHub repositories from .env
|
|
94
|
+
*
|
|
95
|
+
* Reads:
|
|
96
|
+
* - GITHUB_REPOS (comma-separated, format: "owner/repo,owner2/repo2")
|
|
97
|
+
* - GITHUB_TOKEN (shared credential)
|
|
98
|
+
*
|
|
99
|
+
* @returns Array of GitHub repository configurations
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* // .env:
|
|
103
|
+
* // GITHUB_REPOS=myorg/backend-api,myorg/frontend-web
|
|
104
|
+
* // GITHUB_TOKEN=ghp_abc123
|
|
105
|
+
*
|
|
106
|
+
* parseGitHubRepos()
|
|
107
|
+
* // Returns: [
|
|
108
|
+
* // { owner: "myorg", repo: "backend-api", token: "..." },
|
|
109
|
+
* // { owner: "myorg", repo: "frontend-web", token: "..." }
|
|
110
|
+
* // ]
|
|
111
|
+
*/
|
|
112
|
+
export function parseGitHubRepos() {
|
|
113
|
+
const token = process.env.GITHUB_TOKEN;
|
|
114
|
+
// Missing token → return empty array
|
|
115
|
+
if (!token) {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
// Parse GITHUB_REPOS (comma-separated "owner/repo" format)
|
|
119
|
+
const reposStr = process.env.GITHUB_REPOS;
|
|
120
|
+
if (!reposStr) {
|
|
121
|
+
return [];
|
|
122
|
+
}
|
|
123
|
+
const repos = parseCommaSeparated(reposStr);
|
|
124
|
+
const configs = [];
|
|
125
|
+
for (const repo of repos) {
|
|
126
|
+
// Format: "owner/repo"
|
|
127
|
+
const parts = repo.split('/');
|
|
128
|
+
if (parts.length === 2) {
|
|
129
|
+
configs.push({
|
|
130
|
+
owner: parts[0].trim(),
|
|
131
|
+
repo: parts[1].trim(),
|
|
132
|
+
token,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return configs;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Parse Azure DevOps projects from .env
|
|
140
|
+
*
|
|
141
|
+
* Reads:
|
|
142
|
+
* - AZURE_DEVOPS_PROJECTS (comma-separated)
|
|
143
|
+
* - AZURE_DEVOPS_ORG (shared organization)
|
|
144
|
+
* - AZURE_DEVOPS_PAT (shared credential)
|
|
145
|
+
*
|
|
146
|
+
* @returns Array of Azure DevOps project configurations
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* // .env:
|
|
150
|
+
* // AZURE_DEVOPS_PROJECTS=backend-api,frontend-web
|
|
151
|
+
* // AZURE_DEVOPS_ORG=easychamp
|
|
152
|
+
* // AZURE_DEVOPS_PAT=xyz789
|
|
153
|
+
*
|
|
154
|
+
* parseAdoProjects()
|
|
155
|
+
* // Returns: [
|
|
156
|
+
* // { organization: "easychamp", project: "backend-api", pat: "..." },
|
|
157
|
+
* // { organization: "easychamp", project: "frontend-web", pat: "..." }
|
|
158
|
+
* // ]
|
|
159
|
+
*/
|
|
160
|
+
export function parseAdoProjects() {
|
|
161
|
+
const organization = process.env.AZURE_DEVOPS_ORG;
|
|
162
|
+
const pat = process.env.AZURE_DEVOPS_PAT;
|
|
163
|
+
// Missing credentials → return empty array
|
|
164
|
+
if (!organization || !pat) {
|
|
165
|
+
return [];
|
|
166
|
+
}
|
|
167
|
+
// Try new format (AZURE_DEVOPS_PROJECTS - plural)
|
|
168
|
+
const projectsStr = process.env.AZURE_DEVOPS_PROJECTS;
|
|
169
|
+
if (projectsStr) {
|
|
170
|
+
const projects = parseCommaSeparated(projectsStr);
|
|
171
|
+
return projects.map((project) => ({
|
|
172
|
+
organization,
|
|
173
|
+
project,
|
|
174
|
+
pat,
|
|
175
|
+
}));
|
|
176
|
+
}
|
|
177
|
+
// Fallback to legacy format (AZURE_DEVOPS_PROJECT - singular)
|
|
178
|
+
const legacyProject = process.env.AZURE_DEVOPS_PROJECT;
|
|
179
|
+
if (legacyProject) {
|
|
180
|
+
return [
|
|
181
|
+
{
|
|
182
|
+
organization,
|
|
183
|
+
project: legacyProject.trim(),
|
|
184
|
+
pat,
|
|
185
|
+
},
|
|
186
|
+
];
|
|
187
|
+
}
|
|
188
|
+
return [];
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Parse all multi-project configurations from .env
|
|
192
|
+
*
|
|
193
|
+
* @returns All detected project configurations
|
|
194
|
+
*/
|
|
195
|
+
export function parseMultiProjectEnv() {
|
|
196
|
+
return {
|
|
197
|
+
jira: parseJiraProjects(),
|
|
198
|
+
github: parseGitHubRepos(),
|
|
199
|
+
ado: parseAdoProjects(),
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
// ============================================================================
|
|
203
|
+
// Sync Profile Generation
|
|
204
|
+
// ============================================================================
|
|
205
|
+
/**
|
|
206
|
+
* Generate sync profile ID from project identifier
|
|
207
|
+
*
|
|
208
|
+
* Format: "{provider}-{project-id}"
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* generateProfileId("jira", "BACKEND")
|
|
212
|
+
* // Returns: "jira-backend"
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* generateProfileId("github", "backend-api")
|
|
216
|
+
* // Returns: "github-backend-api"
|
|
217
|
+
*/
|
|
218
|
+
export function generateProfileId(provider, projectId) {
|
|
219
|
+
return `${provider}-${projectId.toLowerCase().replace(/[^a-z0-9-]/g, '-')}`;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Create JIRA sync profile from project configuration
|
|
223
|
+
*/
|
|
224
|
+
export function createJiraSyncProfile(config) {
|
|
225
|
+
const profileId = generateProfileId('jira', config.projectKey);
|
|
226
|
+
return {
|
|
227
|
+
id: profileId,
|
|
228
|
+
profile: {
|
|
229
|
+
provider: 'jira',
|
|
230
|
+
displayName: `JIRA ${config.projectKey}`,
|
|
231
|
+
description: `Auto-created from JIRA_PROJECT_KEYS (project: ${config.projectKey})`,
|
|
232
|
+
config: {
|
|
233
|
+
domain: config.domain,
|
|
234
|
+
projectKey: config.projectKey,
|
|
235
|
+
issueType: 'Epic',
|
|
236
|
+
},
|
|
237
|
+
timeRange: {
|
|
238
|
+
default: '1M',
|
|
239
|
+
max: '3M',
|
|
240
|
+
},
|
|
241
|
+
rateLimits: {
|
|
242
|
+
maxItemsPerSync: 200,
|
|
243
|
+
warnThreshold: 50,
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Create GitHub sync profile from repository configuration
|
|
250
|
+
*/
|
|
251
|
+
export function createGitHubSyncProfile(config) {
|
|
252
|
+
const profileId = generateProfileId('github', config.repo);
|
|
253
|
+
return {
|
|
254
|
+
id: profileId,
|
|
255
|
+
profile: {
|
|
256
|
+
provider: 'github',
|
|
257
|
+
displayName: `${config.owner}/${config.repo}`,
|
|
258
|
+
description: `Auto-created from GITHUB_REPOS`,
|
|
259
|
+
config: {
|
|
260
|
+
owner: config.owner,
|
|
261
|
+
repo: config.repo,
|
|
262
|
+
},
|
|
263
|
+
timeRange: {
|
|
264
|
+
default: '1M',
|
|
265
|
+
max: '6M',
|
|
266
|
+
},
|
|
267
|
+
rateLimits: {
|
|
268
|
+
maxItemsPerSync: 500,
|
|
269
|
+
warnThreshold: 100,
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Create Azure DevOps sync profile from project configuration
|
|
276
|
+
*/
|
|
277
|
+
export function createAdoSyncProfile(config) {
|
|
278
|
+
const profileId = generateProfileId('ado', config.project);
|
|
279
|
+
return {
|
|
280
|
+
id: profileId,
|
|
281
|
+
profile: {
|
|
282
|
+
provider: 'ado',
|
|
283
|
+
displayName: `${config.organization}/${config.project}`,
|
|
284
|
+
description: `Auto-created from AZURE_DEVOPS_PROJECTS`,
|
|
285
|
+
config: {
|
|
286
|
+
organization: config.organization,
|
|
287
|
+
project: config.project,
|
|
288
|
+
workItemType: 'Epic',
|
|
289
|
+
},
|
|
290
|
+
timeRange: {
|
|
291
|
+
default: '1M',
|
|
292
|
+
max: '1Y',
|
|
293
|
+
},
|
|
294
|
+
rateLimits: {
|
|
295
|
+
maxItemsPerSync: 500,
|
|
296
|
+
warnThreshold: 100,
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Generate all sync profiles from environment variables
|
|
303
|
+
*
|
|
304
|
+
* @returns Array of { id, profile } objects ready to be created
|
|
305
|
+
*
|
|
306
|
+
* @example
|
|
307
|
+
* // .env:
|
|
308
|
+
* // JIRA_PROJECT_KEYS=BACKEND,FRONTEND
|
|
309
|
+
* // GITHUB_REPOS=myorg/backend-api
|
|
310
|
+
*
|
|
311
|
+
* const profiles = generateSyncProfilesFromEnv();
|
|
312
|
+
* // Returns: [
|
|
313
|
+
* // { id: "jira-backend", profile: { ... } },
|
|
314
|
+
* // { id: "jira-frontend", profile: { ... } },
|
|
315
|
+
* // { id: "github-backend-api", profile: { ... } }
|
|
316
|
+
* // ]
|
|
317
|
+
*/
|
|
318
|
+
export function generateSyncProfilesFromEnv() {
|
|
319
|
+
const envConfig = parseMultiProjectEnv();
|
|
320
|
+
const profiles = [];
|
|
321
|
+
// JIRA profiles
|
|
322
|
+
for (const jiraConfig of envConfig.jira) {
|
|
323
|
+
profiles.push(createJiraSyncProfile(jiraConfig));
|
|
324
|
+
}
|
|
325
|
+
// GitHub profiles
|
|
326
|
+
for (const githubConfig of envConfig.github) {
|
|
327
|
+
profiles.push(createGitHubSyncProfile(githubConfig));
|
|
328
|
+
}
|
|
329
|
+
// Azure DevOps profiles
|
|
330
|
+
for (const adoConfig of envConfig.ado) {
|
|
331
|
+
profiles.push(createAdoSyncProfile(adoConfig));
|
|
332
|
+
}
|
|
333
|
+
return profiles;
|
|
334
|
+
}
|
|
335
|
+
// ============================================================================
|
|
336
|
+
// Validation
|
|
337
|
+
// ============================================================================
|
|
338
|
+
/**
|
|
339
|
+
* Validate JIRA project key format
|
|
340
|
+
*
|
|
341
|
+
* Rules:
|
|
342
|
+
* - 2-10 characters
|
|
343
|
+
* - Uppercase letters only
|
|
344
|
+
* - No special characters
|
|
345
|
+
*
|
|
346
|
+
* @example
|
|
347
|
+
* validateJiraProjectKey("BACKEND") // → true
|
|
348
|
+
* validateJiraProjectKey("backend") // → "Must be uppercase"
|
|
349
|
+
* validateJiraProjectKey("BACK") // → true
|
|
350
|
+
* validateJiraProjectKey("B") // → "Must be 2-10 characters"
|
|
351
|
+
*/
|
|
352
|
+
export function validateJiraProjectKey(key) {
|
|
353
|
+
if (!key) {
|
|
354
|
+
return 'Project key is required';
|
|
355
|
+
}
|
|
356
|
+
if (!/^[A-Z0-9]+$/.test(key)) {
|
|
357
|
+
return 'Project key must be uppercase letters and numbers only (e.g., BACKEND, PROJ1)';
|
|
358
|
+
}
|
|
359
|
+
if (key.length < 2 || key.length > 10) {
|
|
360
|
+
return 'Project key must be 2-10 characters';
|
|
361
|
+
}
|
|
362
|
+
return true;
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Validate GitHub repo format
|
|
366
|
+
*
|
|
367
|
+
* Format: "owner/repo"
|
|
368
|
+
*
|
|
369
|
+
* @example
|
|
370
|
+
* validateGitHubRepo("myorg/backend-api") // → true
|
|
371
|
+
* validateGitHubRepo("backend-api") // → "Must be owner/repo format"
|
|
372
|
+
*/
|
|
373
|
+
export function validateGitHubRepo(repo) {
|
|
374
|
+
if (!repo) {
|
|
375
|
+
return 'Repository is required';
|
|
376
|
+
}
|
|
377
|
+
const parts = repo.split('/');
|
|
378
|
+
if (parts.length !== 2) {
|
|
379
|
+
return 'Repository must be in "owner/repo" format (e.g., myorg/backend-api)';
|
|
380
|
+
}
|
|
381
|
+
const [owner, repoName] = parts;
|
|
382
|
+
if (!owner || !repoName) {
|
|
383
|
+
return 'Both owner and repo name are required';
|
|
384
|
+
}
|
|
385
|
+
if (!/^[a-zA-Z0-9-_.]+$/.test(owner) || !/^[a-zA-Z0-9-_.]+$/.test(repoName)) {
|
|
386
|
+
return 'Owner and repo name can only contain letters, numbers, hyphens, underscores, and dots';
|
|
387
|
+
}
|
|
388
|
+
return true;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Validate Azure DevOps project name
|
|
392
|
+
*
|
|
393
|
+
* @example
|
|
394
|
+
* validateAdoProject("backend-api") // → true
|
|
395
|
+
* validateAdoProject("") // → "Project name is required"
|
|
396
|
+
*/
|
|
397
|
+
export function validateAdoProject(project) {
|
|
398
|
+
if (!project) {
|
|
399
|
+
return 'Project name is required';
|
|
400
|
+
}
|
|
401
|
+
if (project.length < 2 || project.length > 64) {
|
|
402
|
+
return 'Project name must be 2-64 characters';
|
|
403
|
+
}
|
|
404
|
+
return true;
|
|
405
|
+
}
|
|
406
|
+
//# sourceMappingURL=env-multi-project-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-multi-project-parser.js","sourceRoot":"","sources":["../../src/utils/env-multi-project-parser.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specweave",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.19",
|
|
4
4
|
"description": "Spec-driven development framework for Claude Code. AI-native workflow with living documentation, intelligent agents, and multilingual support (9 languages). Enterprise-grade traceability with permanent specs and temporary increments.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# SpecWeave Post-First-Increment Hook
|
|
3
|
+
#
|
|
4
|
+
# Triggers after the first increment is completed
|
|
5
|
+
# Suggests docs-preview plugin for internal documentation
|
|
6
|
+
#
|
|
7
|
+
# NON-INTERACTIVE: Just shows a message (hooks run in background)
|
|
8
|
+
|
|
9
|
+
set -euo pipefail
|
|
10
|
+
|
|
11
|
+
# Get project root (where .specweave/ lives)
|
|
12
|
+
PROJECT_ROOT="$(pwd)"
|
|
13
|
+
|
|
14
|
+
# Check if .specweave directory exists
|
|
15
|
+
if [ ! -d ".specweave" ]; then
|
|
16
|
+
# Not in SpecWeave project, skip
|
|
17
|
+
exit 0
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
# Check if this is the first increment completion
|
|
21
|
+
# Count completed increments in .specweave/increments/
|
|
22
|
+
COMPLETED_COUNT=0
|
|
23
|
+
if [ -d ".specweave/increments" ]; then
|
|
24
|
+
# Count directories that have COMPLETION-REPORT.md or completion metadata
|
|
25
|
+
for inc_dir in .specweave/increments/[0-9][0-9][0-9][0-9]-*/; do
|
|
26
|
+
if [ -d "$inc_dir" ]; then
|
|
27
|
+
if [ -f "${inc_dir}reports/COMPLETION-REPORT.md" ] || \
|
|
28
|
+
[ -f "${inc_dir}COMPLETION-SUMMARY.md" ] || \
|
|
29
|
+
([ -f "${inc_dir}metadata.json" ] && grep -q '"status".*"completed"' "${inc_dir}metadata.json" 2>/dev/null); then
|
|
30
|
+
COMPLETED_COUNT=$((COMPLETED_COUNT + 1))
|
|
31
|
+
fi
|
|
32
|
+
fi
|
|
33
|
+
done
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# Only trigger on first completion
|
|
37
|
+
if [ "$COMPLETED_COUNT" -ne 1 ]; then
|
|
38
|
+
exit 0
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# Check if docs-preview plugin is already installed
|
|
42
|
+
PLUGIN_INSTALLED=false
|
|
43
|
+
if command -v claude &> /dev/null; then
|
|
44
|
+
if claude plugin list --installed 2>/dev/null | grep -q "specweave-docs-preview"; then
|
|
45
|
+
PLUGIN_INSTALLED=true
|
|
46
|
+
fi
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
# If already installed, skip suggestion
|
|
50
|
+
if [ "$PLUGIN_INSTALLED" = true ]; then
|
|
51
|
+
exit 0
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
# Show suggestion (non-interactive message)
|
|
55
|
+
echo ""
|
|
56
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
57
|
+
echo "🎉 Congratulations! You completed your first increment!"
|
|
58
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
59
|
+
echo ""
|
|
60
|
+
echo "📚 Preview your documentation in a beautiful UI?"
|
|
61
|
+
echo ""
|
|
62
|
+
echo "The specweave-docs-preview plugin can generate a Docusaurus site from"
|
|
63
|
+
echo "your .specweave/docs/ folder with:"
|
|
64
|
+
echo ""
|
|
65
|
+
echo " ✓ Auto-generated sidebar from folder structure"
|
|
66
|
+
echo " ✓ Hot reload (edit markdown, see changes instantly)"
|
|
67
|
+
echo " ✓ Mermaid diagram rendering"
|
|
68
|
+
echo " ✓ Priority sorting (Strategy → Specs → Architecture → ...)"
|
|
69
|
+
echo ""
|
|
70
|
+
echo "📦 Install with:"
|
|
71
|
+
echo " /plugin install specweave-docs-preview"
|
|
72
|
+
echo ""
|
|
73
|
+
echo "🚀 Then launch:"
|
|
74
|
+
echo " /specweave:docs preview"
|
|
75
|
+
echo ""
|
|
76
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
77
|
+
echo ""
|
|
78
|
+
|
|
79
|
+
exit 0
|
|
@@ -526,6 +526,8 @@ created: YYYY-MM-DD
|
|
|
526
526
|
|
|
527
527
|
**Purpose**: Analyze spec content to identify required SpecWeave plugins AND check if external PM tool sync is configured.
|
|
528
528
|
|
|
529
|
+
**⚠️ CRITICAL**: For ALL plugin installations, consult the `plugin-expert` skill for correct syntax. NEVER use `@marketplace` suffix!
|
|
530
|
+
|
|
529
531
|
**Why This Matters**:
|
|
530
532
|
1. SpecWeave's plugin system enables context efficiency (70%+ reduction) by loading only relevant capabilities
|
|
531
533
|
2. PM tool integration enables automatic sync of increment progress to external systems (GitHub Issues, Jira, Azure DevOps)
|
|
@@ -561,25 +563,57 @@ created: YYYY-MM-DD
|
|
|
561
563
|
- For Claude Code: Check if plugin available via `/plugin list --installed`
|
|
562
564
|
- Skip already-installed plugins
|
|
563
565
|
|
|
564
|
-
4.
|
|
565
|
-
```
|
|
566
|
-
🔌 This increment requires additional plugins:
|
|
567
|
-
|
|
568
|
-
Required:
|
|
569
|
-
• specweave-github - GitHub integration (detected: "sync tasks to GitHub issues")
|
|
570
|
-
• specweave-kubernetes - K8s deployment (detected: "deploy to production cluster")
|
|
566
|
+
4. **🚨 AUTOMATIC PLUGIN INSTALLATION** (if plugins detected):
|
|
571
567
|
|
|
572
|
-
|
|
573
|
-
|
|
568
|
+
**IMPORTANT**: When you detect required plugins, you MUST:
|
|
569
|
+
- ✅ Proactively offer to install them (not just suggest)
|
|
570
|
+
- ✅ Explain WHY each plugin is needed (based on detected keywords)
|
|
571
|
+
- ✅ Show clear install commands
|
|
572
|
+
- ✅ Remind user that plugins provide expert AI agents and capabilities
|
|
574
573
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
574
|
+
**Output Format**:
|
|
575
|
+
```
|
|
576
|
+
🔌 Detected plugin requirements from spec content:
|
|
577
|
+
|
|
578
|
+
REQUIRED (will significantly improve implementation):
|
|
579
|
+
• specweave-github - GitHub Issues integration
|
|
580
|
+
Detected: "sync tasks to GitHub issues", "create pull requests"
|
|
581
|
+
Provides: GitHub sync, PR automation, issue tracking
|
|
582
|
+
→ Without this: Manual GitHub sync required
|
|
583
|
+
|
|
584
|
+
• specweave-kubernetes - Kubernetes deployment
|
|
585
|
+
Detected: "deploy to production cluster", "kubectl apply"
|
|
586
|
+
Provides: K8s expert agent, Helm chart generation, deployment validation
|
|
587
|
+
→ Without this: Manual K8s configuration, no validation
|
|
588
|
+
|
|
589
|
+
OPTIONAL (helpful but not critical):
|
|
590
|
+
• specweave-diagrams - Architecture diagrams
|
|
591
|
+
Detected: "system architecture", "component diagram"
|
|
592
|
+
Provides: Mermaid + C4 diagram generation
|
|
593
|
+
→ Without this: Manual diagram creation
|
|
594
|
+
|
|
595
|
+
📦 Install recommended plugins:
|
|
596
|
+
/plugin install specweave-github
|
|
597
|
+
/plugin install specweave-kubernetes
|
|
598
|
+
|
|
599
|
+
📦 Install optional plugins:
|
|
600
|
+
/plugin install specweave-diagrams
|
|
601
|
+
|
|
602
|
+
💡 Benefits:
|
|
603
|
+
• Plugins provide specialized AI agents (GitHub expert, K8s expert, etc.)
|
|
604
|
+
• Skills auto-activate based on context (zero manual invocation)
|
|
605
|
+
• 70%+ context reduction (only load what you need)
|
|
606
|
+
• Best practices built-in (from real-world experience)
|
|
607
|
+
|
|
608
|
+
Would you like me to wait while you install these plugins? (Recommended)
|
|
609
|
+
Or shall I continue without them? (Limited capabilities)
|
|
581
610
|
```
|
|
582
611
|
|
|
612
|
+
**User Decision Points**:
|
|
613
|
+
- If user installs plugins → continue with full capabilities
|
|
614
|
+
- If user skips → continue but remind about limitations later
|
|
615
|
+
- NEVER block increment creation (plugins are enhancements, not requirements)
|
|
616
|
+
|
|
583
617
|
5. **Auto-Sync to PM Tool** (v0.8.0+):
|
|
584
618
|
|
|
585
619
|
**🚨 CRITICAL: SpecWeave Repo Dog-Food Requirement**:
|
|
@@ -619,7 +653,7 @@ created: YYYY-MM-DD
|
|
|
619
653
|
⚠️ External PM Tool Configured: GitHub Issues
|
|
620
654
|
Plugin missing: specweave-github
|
|
621
655
|
|
|
622
|
-
To enable auto-sync: /plugin install specweave-github
|
|
656
|
+
To enable auto-sync: /plugin install specweave-github
|
|
623
657
|
Or continue without PM sync (local-only mode)
|
|
624
658
|
```
|
|
625
659
|
- **If PM tool not configured**:
|