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.
Files changed (35) hide show
  1. package/CLAUDE.md +119 -27
  2. package/README.md +11 -3
  3. package/dist/cli/commands/init.d.ts.map +1 -1
  4. package/dist/cli/commands/init.js +74 -20
  5. package/dist/cli/commands/init.js.map +1 -1
  6. package/dist/cli/commands/migrate-to-profiles.js +2 -2
  7. package/dist/cli/commands/migrate-to-profiles.js.map +1 -1
  8. package/dist/cli/helpers/issue-tracker/index.d.ts.map +1 -1
  9. package/dist/cli/helpers/issue-tracker/index.js +8 -3
  10. package/dist/cli/helpers/issue-tracker/index.js.map +1 -1
  11. package/dist/cli/helpers/issue-tracker/utils.d.ts +5 -2
  12. package/dist/cli/helpers/issue-tracker/utils.d.ts.map +1 -1
  13. package/dist/cli/helpers/issue-tracker/utils.js +13 -6
  14. package/dist/cli/helpers/issue-tracker/utils.js.map +1 -1
  15. package/dist/core/sync/bidirectional-engine.d.ts +110 -0
  16. package/dist/core/sync/bidirectional-engine.d.ts.map +1 -0
  17. package/dist/core/sync/bidirectional-engine.js +356 -0
  18. package/dist/core/sync/bidirectional-engine.js.map +1 -0
  19. package/dist/utils/agents-md-compiler.js +2 -2
  20. package/dist/utils/env-multi-project-parser.d.ts +210 -0
  21. package/dist/utils/env-multi-project-parser.d.ts.map +1 -0
  22. package/dist/utils/env-multi-project-parser.js +406 -0
  23. package/dist/utils/env-multi-project-parser.js.map +1 -0
  24. package/package.json +1 -1
  25. package/plugins/specweave/hooks/post-first-increment.sh +79 -0
  26. package/plugins/specweave/skills/increment-planner/SKILL.md +50 -16
  27. package/plugins/specweave/skills/plugin-expert/SKILL.md +344 -0
  28. package/plugins/specweave/skills/specweave-framework/SKILL.md +2 -2
  29. package/plugins/specweave/skills/translator/SKILL.md +29 -0
  30. package/plugins/specweave/skills/translator/SKILL.md.bak +172 -0
  31. package/plugins/specweave-jira/lib/project-selector.ts +323 -0
  32. package/plugins/specweave-jira/lib/reorganization-detector.ts +359 -0
  33. package/plugins/specweave-jira/lib/setup-wizard.ts +256 -0
  34. package/src/templates/.gitignore.template +1 -0
  35. 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.17",
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. **Suggest installation** (if plugins detected):
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
- Optional:
573
- • specweave-diagrams - Architecture diagrams (helpful for "system architecture")
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
- 📦 Install plugins:
576
- /plugin install specweave-github
577
- /plugin install specweave-kubernetes
578
- /plugin install specweave-diagrams
579
-
580
- 💡 Plugins will auto-activate during implementation!
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@specweave
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**: