specweave 0.23.18 → 0.24.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.
Files changed (167) hide show
  1. package/.claude-plugin/marketplace.json +93 -49
  2. package/CLAUDE.md +137 -4
  3. package/dist/src/cli/helpers/ado-area-path-mapper.d.ts +89 -0
  4. package/dist/src/cli/helpers/ado-area-path-mapper.d.ts.map +1 -0
  5. package/dist/src/cli/helpers/ado-area-path-mapper.js +213 -0
  6. package/dist/src/cli/helpers/ado-area-path-mapper.js.map +1 -0
  7. package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.d.ts +29 -0
  8. package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.d.ts.map +1 -0
  9. package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.js +109 -0
  10. package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.js.map +1 -0
  11. package/dist/src/cli/helpers/issue-tracker/ado.d.ts +1 -0
  12. package/dist/src/cli/helpers/issue-tracker/ado.d.ts.map +1 -1
  13. package/dist/src/cli/helpers/issue-tracker/ado.js +2 -0
  14. package/dist/src/cli/helpers/issue-tracker/ado.js.map +1 -1
  15. package/dist/src/cli/helpers/smart-filter.d.ts +83 -0
  16. package/dist/src/cli/helpers/smart-filter.d.ts.map +1 -0
  17. package/dist/src/cli/helpers/smart-filter.js +265 -0
  18. package/dist/src/cli/helpers/smart-filter.js.map +1 -0
  19. package/dist/src/core/qa/quality-gate-decider.d.ts +1 -1
  20. package/dist/src/core/qa/quality-gate-decider.js +2 -2
  21. package/dist/src/core/qa/quality-gate-decider.js.map +1 -1
  22. package/dist/src/core/qa/risk-calculator.d.ts +2 -2
  23. package/dist/src/core/qa/risk-calculator.js +2 -2
  24. package/dist/src/core/validators/ac-presence-validator.d.ts +56 -0
  25. package/dist/src/core/validators/ac-presence-validator.d.ts.map +1 -0
  26. package/dist/src/core/validators/ac-presence-validator.js +149 -0
  27. package/dist/src/core/validators/ac-presence-validator.js.map +1 -0
  28. package/dist/src/integrations/ado/area-path-mapper.d.ts +137 -0
  29. package/dist/src/integrations/ado/area-path-mapper.d.ts.map +1 -0
  30. package/dist/src/integrations/ado/area-path-mapper.js +267 -0
  31. package/dist/src/integrations/ado/area-path-mapper.js.map +1 -0
  32. package/dist/src/integrations/jira/filter-processor.d.ts +126 -0
  33. package/dist/src/integrations/jira/filter-processor.d.ts.map +1 -0
  34. package/dist/src/integrations/jira/filter-processor.js +207 -0
  35. package/dist/src/integrations/jira/filter-processor.js.map +1 -0
  36. package/dist/src/integrations/jira/jira-client.d.ts +13 -0
  37. package/dist/src/integrations/jira/jira-client.d.ts.map +1 -1
  38. package/dist/src/integrations/jira/jira-client.js +33 -0
  39. package/dist/src/integrations/jira/jira-client.js.map +1 -1
  40. package/dist/src/utils/ac-embedder.d.ts +63 -0
  41. package/dist/src/utils/ac-embedder.d.ts.map +1 -0
  42. package/dist/src/utils/ac-embedder.js +217 -0
  43. package/dist/src/utils/ac-embedder.js.map +1 -0
  44. package/dist/src/utils/env-manager.d.ts +86 -0
  45. package/dist/src/utils/env-manager.d.ts.map +1 -0
  46. package/dist/src/utils/env-manager.js +188 -0
  47. package/dist/src/utils/env-manager.js.map +1 -0
  48. package/package.json +1 -1
  49. package/plugins/specweave/.claude-plugin/plugin.json +1 -1
  50. package/plugins/specweave/agents/AGENTS-INDEX.md +1 -1
  51. package/plugins/specweave/agents/increment-quality-judge-v2/AGENT.md +9 -9
  52. package/plugins/specweave/commands/specweave-do.md +37 -0
  53. package/plugins/specweave/commands/specweave-done.md +159 -0
  54. package/plugins/specweave/commands/specweave-embed-acs.md +446 -0
  55. package/plugins/specweave/commands/specweave-next.md +148 -3
  56. package/plugins/specweave/commands/specweave-qa.md +2 -2
  57. package/plugins/specweave/hooks/pre-increment-start.sh +168 -0
  58. package/plugins/specweave/skills/SKILLS-INDEX.md +1 -1
  59. package/plugins/specweave-ado/.claude-plugin/plugin.json +1 -1
  60. package/plugins/specweave-ado/commands/specweave-ado-import-projects.md +331 -0
  61. package/plugins/specweave-alternatives/.claude-plugin/plugin.json +10 -0
  62. package/plugins/specweave-alternatives/commands/alternatives-analyze.md +336 -0
  63. package/plugins/specweave-alternatives/skills/architecture-alternatives/SKILL.md +651 -0
  64. package/plugins/specweave-alternatives/skills/bmad-method/SKILL.md +420 -0
  65. package/plugins/specweave-alternatives/skills/spec-kit-expert/SKILL.md +487 -0
  66. package/plugins/specweave-backend/commands/api-scaffold.md +80 -0
  67. package/plugins/specweave-backend/commands/crud-generate.md +109 -0
  68. package/plugins/specweave-backend/commands/migration-generate.md +139 -0
  69. package/plugins/specweave-confluent/commands/connector-deploy.md +154 -0
  70. package/plugins/specweave-confluent/commands/ksqldb-query.md +179 -0
  71. package/plugins/specweave-confluent/commands/schema-register.md +123 -0
  72. package/plugins/specweave-core/.claude-plugin/plugin.json +21 -0
  73. package/plugins/specweave-core/commands/architecture-review.md +288 -0
  74. package/plugins/specweave-core/commands/code-review.md +213 -0
  75. package/plugins/specweave-core/commands/refactor-plan.md +249 -0
  76. package/plugins/specweave-core/skills/code-quality/SKILL.md +157 -0
  77. package/plugins/specweave-core/skills/design-patterns/SKILL.md +244 -0
  78. package/plugins/specweave-core/skills/software-architecture/SKILL.md +83 -0
  79. package/plugins/specweave-cost-optimizer/.claude-plugin/plugin.json +22 -0
  80. package/plugins/specweave-cost-optimizer/commands/cost-analyze.md +360 -0
  81. package/plugins/specweave-cost-optimizer/commands/cost-optimize.md +480 -0
  82. package/plugins/specweave-cost-optimizer/skills/aws-cost-expert/SKILL.md +416 -0
  83. package/plugins/specweave-cost-optimizer/skills/cloud-pricing/SKILL.md +325 -0
  84. package/plugins/specweave-cost-optimizer/skills/cost-optimization/SKILL.md +337 -0
  85. package/plugins/specweave-diagrams/.claude-plugin/plugin.json +1 -1
  86. package/plugins/specweave-diagrams/commands/diagrams-generate.md +168 -0
  87. package/plugins/specweave-docs/.claude-plugin/plugin.json +10 -0
  88. package/plugins/specweave-docs/commands/docs-generate.md +441 -0
  89. package/plugins/specweave-docs/commands/docs-init.md +334 -0
  90. package/plugins/specweave-docs/skills/docusaurus/SKILL.md +581 -0
  91. package/plugins/specweave-docs/skills/spec-driven-brainstorming/SKILL.md +689 -0
  92. package/plugins/specweave-docs/skills/technical-writing/SKILL.md +1039 -0
  93. package/plugins/specweave-docs-preview/.claude-plugin/plugin.json +1 -1
  94. package/plugins/specweave-figma/.claude-plugin/plugin.json +23 -0
  95. package/plugins/specweave-figma/commands/figma-import.md +690 -0
  96. package/plugins/specweave-figma/commands/figma-to-react.md +834 -0
  97. package/plugins/specweave-figma/commands/figma-tokens.md +815 -0
  98. package/plugins/specweave-frontend/.claude-plugin/plugin.json +21 -0
  99. package/plugins/specweave-frontend/agents/frontend-architect/AGENT.md +387 -0
  100. package/plugins/specweave-frontend/agents/frontend-architect/README.md +385 -0
  101. package/plugins/specweave-frontend/agents/frontend-architect/examples.md +590 -0
  102. package/plugins/specweave-frontend/agents/frontend-architect/templates/component-template.tsx +152 -0
  103. package/plugins/specweave-frontend/agents/frontend-architect/templates/hook-template.ts +311 -0
  104. package/plugins/specweave-frontend/agents/frontend-architect/templates/page-template.tsx +228 -0
  105. package/plugins/specweave-frontend/commands/component-generate.md +510 -0
  106. package/plugins/specweave-frontend/commands/design-system-init.md +494 -0
  107. package/plugins/specweave-frontend/commands/frontend-scaffold.md +207 -0
  108. package/plugins/specweave-frontend/commands/nextjs-setup.md +396 -0
  109. package/plugins/specweave-frontend/skills/design-system-architect/SKILL.md +278 -0
  110. package/plugins/specweave-frontend/skills/frontend/SKILL.md +420 -0
  111. package/plugins/specweave-frontend/skills/nextjs/SKILL.md +546 -0
  112. package/plugins/specweave-github/.claude-plugin/plugin.json +1 -1
  113. package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +194 -0
  114. package/plugins/specweave-infrastructure/.claude-plugin/plugin.json +1 -1
  115. package/plugins/specweave-jira/.claude-plugin/plugin.json +1 -1
  116. package/plugins/specweave-jira/commands/import-projects.js +183 -0
  117. package/plugins/specweave-jira/commands/import-projects.md +97 -0
  118. package/plugins/specweave-jira/commands/import-projects.ts +288 -0
  119. package/plugins/specweave-jira/commands/specweave-jira-import-projects.md +298 -0
  120. package/plugins/specweave-kafka/.claude-plugin/plugin.json +1 -1
  121. package/plugins/specweave-kafka-streams/.claude-plugin/plugin.json +1 -1
  122. package/plugins/specweave-kubernetes/commands/cluster-setup.md +262 -0
  123. package/plugins/specweave-kubernetes/commands/deployment-generate.md +242 -0
  124. package/plugins/specweave-kubernetes/commands/helm-scaffold.md +333 -0
  125. package/plugins/specweave-ml/.claude-plugin/plugin.json +1 -1
  126. package/plugins/specweave-mobile/commands/app-scaffold.md +233 -0
  127. package/plugins/specweave-mobile/commands/build-config.md +256 -0
  128. package/plugins/specweave-mobile/commands/screen-generate.md +289 -0
  129. package/plugins/specweave-n8n/.claude-plugin/plugin.json +1 -1
  130. package/plugins/specweave-plugin-dev/.claude-plugin/plugin.json +13 -12
  131. package/plugins/specweave-plugin-dev/commands/plugin-create.md +333 -0
  132. package/plugins/specweave-plugin-dev/commands/plugin-publish.md +339 -0
  133. package/plugins/specweave-plugin-dev/commands/plugin-test.md +293 -0
  134. package/plugins/specweave-plugin-dev/skills/claude-sdk/SKILL.md +162 -0
  135. package/plugins/specweave-plugin-dev/skills/marketplace-publishing/SKILL.md +263 -0
  136. package/plugins/specweave-plugin-dev/skills/plugin-development/SKILL.md +316 -0
  137. package/plugins/specweave-release/.claude-plugin/plugin.json +1 -1
  138. package/plugins/specweave-release/commands/specweave-release-npm.md +110 -0
  139. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +168 -0
  140. package/plugins/specweave-testing/.claude-plugin/plugin.json +21 -0
  141. package/plugins/specweave-testing/agents/qa-engineer/AGENT.md +797 -0
  142. package/plugins/specweave-testing/agents/qa-engineer/README.md +443 -0
  143. package/plugins/specweave-testing/agents/qa-engineer/templates/playwright-e2e-test.ts +470 -0
  144. package/plugins/specweave-testing/agents/qa-engineer/templates/test-data-factory.ts +507 -0
  145. package/plugins/specweave-testing/agents/qa-engineer/templates/vitest-unit-test.ts +400 -0
  146. package/plugins/specweave-testing/agents/qa-engineer/test-strategies.md +726 -0
  147. package/plugins/specweave-testing/commands/e2e-setup.md +1081 -0
  148. package/plugins/specweave-testing/commands/test-coverage.md +979 -0
  149. package/plugins/specweave-testing/commands/test-generate.md +1156 -0
  150. package/plugins/specweave-testing/commands/test-init.md +409 -0
  151. package/plugins/specweave-testing/skills/e2e-playwright/SKILL.md +769 -0
  152. package/plugins/specweave-testing/skills/tdd-expert/SKILL.md +934 -0
  153. package/plugins/specweave-testing/skills/unit-testing-expert/SKILL.md +1011 -0
  154. package/plugins/specweave-tooling/.claude-plugin/plugin.json +22 -0
  155. package/plugins/specweave-tooling/commands/specweave-tooling-skill-create.md +691 -0
  156. package/plugins/specweave-tooling/commands/specweave-tooling-skill-package.md +751 -0
  157. package/plugins/specweave-tooling/commands/specweave-tooling-skill-validate.md +858 -0
  158. package/plugins/specweave-ui/.claude-plugin/plugin.json +10 -0
  159. package/plugins/specweave-ui/commands/ui-automate.md +199 -0
  160. package/plugins/specweave-ui/commands/ui-inspect.md +70 -0
  161. package/plugins/specweave-ui/skills/browser-automation/SKILL.md +314 -0
  162. package/plugins/specweave-ui/skills/ui-testing/SKILL.md +716 -0
  163. package/plugins/specweave-ui/skills/visual-regression/SKILL.md +728 -0
  164. package/plugins/specweave/commands/check-hooks.md +0 -257
  165. package/plugins/specweave/commands/specweave-archive-increments.md +0 -82
  166. package/plugins/specweave-plugin-dev/skills/plugin-expert/SKILL.md +0 -1231
  167. /package/plugins/specweave/{agents/code-reviewer.md → skills/code-reviewer/SKILL.md} +0 -0
@@ -0,0 +1,288 @@
1
+ /**
2
+ * JIRA Project Import Command (Post-Init)
3
+ *
4
+ * Import additional JIRA projects after initial setup with smart filtering,
5
+ * resume support, and merge capabilities.
6
+ *
7
+ * Features:
8
+ * - Smart filtering (active, type, lead, JQL)
9
+ * - Filter presets (production, active-only, agile-only)
10
+ * - Dry-run preview mode
11
+ * - Resume interrupted imports
12
+ * - Progress tracking with ETA
13
+ * - Merge with existing projects (no duplicates)
14
+ *
15
+ * NEW (v0.24.0): Post-init flexibility for project management
16
+ *
17
+ * @module plugins/specweave-jira/commands/import-projects
18
+ */
19
+
20
+ import chalk from 'chalk';
21
+ import inquirer from 'inquirer';
22
+ import { existsSync } from 'fs';
23
+ import path from 'path';
24
+ import { JiraClient } from '../../../src/integrations/jira/jira-client.js';
25
+ import { FilterProcessor, type FilterOptions } from '../../../src/integrations/jira/filter-processor.js';
26
+ import { AsyncProjectLoader } from '../../../src/cli/helpers/async-project-loader.js';
27
+ import { mergeEnvList, getEnvValue } from '../../../src/utils/env-manager.js';
28
+ import { consoleLogger, type Logger } from '../../../src/utils/logger.js';
29
+ import { credentialsManager } from '../../../src/core/credentials-manager.js';
30
+
31
+ export interface ImportProjectsOptions {
32
+ filter?: 'active' | 'archived' | 'all';
33
+ type?: string[];
34
+ lead?: string;
35
+ jql?: string;
36
+ preset?: string;
37
+ dryRun?: boolean;
38
+ resume?: boolean;
39
+ noProgress?: boolean;
40
+ logger?: Logger;
41
+ }
42
+
43
+ export interface ImportState {
44
+ total: number;
45
+ completed: string[];
46
+ remaining: string[];
47
+ timestamp: number;
48
+ }
49
+
50
+ /**
51
+ * Import JIRA projects command
52
+ *
53
+ * TC-063: Post-Init Import (Merge with Existing)
54
+ * TC-064: Filter Active Projects Only
55
+ * TC-068: Resume Interrupted Import
56
+ * TC-069: Dry-Run Preview
57
+ * TC-070: Progress During Import
58
+ *
59
+ * @param options - Import options
60
+ */
61
+ export async function importProjects(options: ImportProjectsOptions = {}): Promise<void> {
62
+ const logger = options.logger ?? consoleLogger;
63
+ const projectRoot = process.cwd();
64
+
65
+ // Step 1: Load credentials
66
+ console.log(chalk.cyan('\n📥 JIRA Project Import\n'));
67
+
68
+ const credentials = credentialsManager.getJiraCredentials();
69
+ if (!credentials) {
70
+ console.log(chalk.red('❌ No JIRA credentials found'));
71
+ console.log(chalk.gray(' Run: specweave init'));
72
+ return;
73
+ }
74
+
75
+ const client = new JiraClient(credentials);
76
+ const filterProcessor = new FilterProcessor(client, { logger });
77
+
78
+ // Step 2: Check for resume state
79
+ if (options.resume) {
80
+ const resumed = await resumeImport(projectRoot, client, filterProcessor, options);
81
+ if (resumed) {
82
+ return;
83
+ }
84
+ console.log(chalk.yellow('⚠️ No import state found. Starting fresh import.\n'));
85
+ }
86
+
87
+ // Step 3: Read existing projects from .env
88
+ const existing = await loadExistingProjects(projectRoot, logger);
89
+ console.log(chalk.gray(`Current projects: ${existing.length > 0 ? existing.join(', ') : 'none'}\n`));
90
+
91
+ // Step 4: Fetch available projects from JIRA
92
+ console.log(chalk.cyan('📡 Fetching available JIRA projects...\n'));
93
+
94
+ let allProjects: any[] = [];
95
+ try {
96
+ const response = await client.searchProjects({ maxResults: 1000 });
97
+ allProjects = response.values || [];
98
+ console.log(chalk.green(`✓ Found ${allProjects.length} total projects\n`));
99
+ } catch (error: any) {
100
+ console.log(chalk.red(`❌ Failed to fetch projects: ${error.message}`));
101
+ return;
102
+ }
103
+
104
+ // Step 5: Apply filters
105
+ let filteredProjects = allProjects;
106
+
107
+ if (options.preset) {
108
+ // Use filter preset
109
+ console.log(chalk.cyan(`🔍 Applying preset: ${options.preset}\n`));
110
+ try {
111
+ filteredProjects = await filterProcessor.applyPreset(allProjects, options.preset);
112
+ } catch (error: any) {
113
+ console.log(chalk.red(`❌ ${error.message}`));
114
+ return;
115
+ }
116
+ } else if (options.filter || options.type || options.lead || options.jql) {
117
+ // Build filter options
118
+ const filterOptions: FilterOptions = {};
119
+
120
+ if (options.filter === 'active') {
121
+ filterOptions.active = true;
122
+ } else if (options.filter === 'archived') {
123
+ filterOptions.active = false;
124
+ }
125
+
126
+ if (options.type) {
127
+ filterOptions.types = options.type;
128
+ }
129
+
130
+ if (options.lead) {
131
+ filterOptions.lead = options.lead;
132
+ }
133
+
134
+ if (options.jql) {
135
+ filterOptions.jql = options.jql;
136
+ }
137
+
138
+ console.log(chalk.cyan('🔍 Applying filters...\n'));
139
+ filteredProjects = await filterProcessor.applyFilters(allProjects, filterOptions);
140
+ }
141
+
142
+ // Step 6: Exclude existing projects
143
+ const newProjects = filteredProjects.filter(p => {
144
+ return !existing.some(e => e.toLowerCase() === p.key.toLowerCase());
145
+ });
146
+
147
+ if (newProjects.length === 0) {
148
+ console.log(chalk.yellow('⚠️ No new projects found to import'));
149
+ console.log(chalk.gray(' All available projects are already imported\n'));
150
+ return;
151
+ }
152
+
153
+ // Step 7: Show preview
154
+ console.log(chalk.cyan('📋 Import Preview:\n'));
155
+ console.log(chalk.white(` Total available: ${allProjects.length}`));
156
+ console.log(chalk.white(` After filtering: ${filteredProjects.length}`));
157
+ console.log(chalk.white(` Already imported: ${existing.length}`));
158
+ console.log(chalk.white(` New projects: ${chalk.green.bold(newProjects.length)}\n`));
159
+
160
+ if (newProjects.length <= 10) {
161
+ console.log(chalk.gray('Projects to import:'));
162
+ newProjects.forEach(p => {
163
+ const typeLabel = p.projectTypeKey || 'unknown';
164
+ const leadLabel = p.lead?.displayName || 'no lead';
165
+ console.log(chalk.gray(` ✨ ${p.key} - ${p.name} (${typeLabel}, ${leadLabel})`));
166
+ });
167
+ console.log('');
168
+ }
169
+
170
+ // Step 8: Dry-run mode (exit without changes)
171
+ if (options.dryRun) {
172
+ console.log(chalk.yellow('🔍 Dry-run mode: No changes will be made\n'));
173
+ console.log(chalk.green(`✓ Preview complete: ${newProjects.length} project(s) would be imported\n`));
174
+ return;
175
+ }
176
+
177
+ // Step 9: Confirm import
178
+ const { confirmed } = await inquirer.prompt([{
179
+ type: 'confirm',
180
+ name: 'confirmed',
181
+ message: `Import ${newProjects.length} new project(s)?`,
182
+ default: true
183
+ }]);
184
+
185
+ if (!confirmed) {
186
+ console.log(chalk.yellow('\n⏭️ Import canceled\n'));
187
+ return;
188
+ }
189
+
190
+ // Step 10: Extract project keys
191
+ const projectKeys = newProjects.map(p => p.key);
192
+
193
+ // Step 11: Merge with existing
194
+ console.log(chalk.cyan('\n📥 Importing projects...\n'));
195
+
196
+ try {
197
+ await mergeEnvList({
198
+ key: 'JIRA_PROJECTS',
199
+ newValues: projectKeys,
200
+ projectRoot,
201
+ logger,
202
+ createBackup: true
203
+ });
204
+
205
+ console.log(chalk.green(`\n✅ Successfully imported ${projectKeys.length} project(s)\n`));
206
+ console.log(chalk.gray('Updated: .env (JIRA_PROJECTS)'));
207
+ console.log(chalk.gray('Backup: .env.backup\n'));
208
+
209
+ } catch (error: any) {
210
+ console.log(chalk.red(`\n❌ Import failed: ${error.message}\n`));
211
+ }
212
+ }
213
+
214
+ /**
215
+ * Load existing JIRA projects from .env
216
+ */
217
+ async function loadExistingProjects(projectRoot: string, logger: Logger): Promise<string[]> {
218
+ const value = await getEnvValue(projectRoot, 'JIRA_PROJECTS');
219
+ if (!value) {
220
+ return [];
221
+ }
222
+
223
+ return value.split(',').map(v => v.trim()).filter(v => v.length > 0);
224
+ }
225
+
226
+ /**
227
+ * Resume interrupted import
228
+ */
229
+ async function resumeImport(
230
+ projectRoot: string,
231
+ client: JiraClient,
232
+ filterProcessor: FilterProcessor,
233
+ options: ImportProjectsOptions
234
+ ): Promise<boolean> {
235
+ const stateFile = path.join(projectRoot, '.specweave', 'cache', 'import-state.json');
236
+
237
+ if (!existsSync(stateFile)) {
238
+ return false;
239
+ }
240
+
241
+ console.log(chalk.cyan('🔄 Resuming interrupted import...\n'));
242
+
243
+ // Load state and continue
244
+ // (Implementation would load state, skip completed, import remaining)
245
+
246
+ return false; // Placeholder - full implementation would handle resume
247
+ }
248
+
249
+ /**
250
+ * Command entry point (called by CLI)
251
+ */
252
+ export default async function main(): Promise<void> {
253
+ // Parse CLI arguments
254
+ const args = process.argv.slice(2);
255
+ const options: ImportProjectsOptions = {};
256
+
257
+ for (let i = 0; i < args.length; i++) {
258
+ const arg = args[i];
259
+
260
+ if (arg === '--filter') {
261
+ options.filter = args[++i] as 'active' | 'archived' | 'all';
262
+ } else if (arg === '--type') {
263
+ options.type = args[++i].split(',');
264
+ } else if (arg === '--lead') {
265
+ options.lead = args[++i];
266
+ } else if (arg === '--jql') {
267
+ options.jql = args[++i];
268
+ } else if (arg === '--preset') {
269
+ options.preset = args[++i];
270
+ } else if (arg === '--dry-run') {
271
+ options.dryRun = true;
272
+ } else if (arg === '--resume') {
273
+ options.resume = true;
274
+ } else if (arg === '--no-progress') {
275
+ options.noProgress = true;
276
+ }
277
+ }
278
+
279
+ await importProjects(options);
280
+ }
281
+
282
+ // Run command if called directly
283
+ if (import.meta.url === `file://${process.argv[1]}`) {
284
+ main().catch(error => {
285
+ console.error(chalk.red(`\n❌ Error: ${error.message}\n`));
286
+ process.exit(1);
287
+ });
288
+ }
@@ -0,0 +1,298 @@
1
+ ---
2
+ name: specweave-jira:import-projects
3
+ description: Import additional JIRA projects post-init with filtering, resume support, and dry-run preview
4
+ ---
5
+
6
+ # Import JIRA Projects Command
7
+
8
+ You are a JIRA project import expert. Help users add additional JIRA projects to their SpecWeave workspace after initial setup.
9
+
10
+ ## Purpose
11
+
12
+ This command allows users to import additional JIRA projects **after** initial SpecWeave setup (`specweave init`), with advanced filtering, resume capability, and dry-run preview.
13
+
14
+ **Use Cases**:
15
+ - Adding new JIRA projects to existing workspace
16
+ - Importing archived/paused projects later
17
+ - Selective import with filters (active only, specific types, custom JQL)
18
+
19
+ ## Command Syntax
20
+
21
+ ```bash
22
+ # Basic import (interactive)
23
+ /specweave-jira:import-projects
24
+
25
+ # With filters
26
+ /specweave-jira:import-projects --filter active
27
+ /specweave-jira:import-projects --type agile --lead "john.doe@company.com"
28
+ /specweave-jira:import-projects --jql "project IN (BACKEND, FRONTEND) AND status != Archived"
29
+
30
+ # Dry-run (preview)
31
+ /specweave-jira:import-projects --dry-run
32
+
33
+ # Resume interrupted import
34
+ /specweave-jira:import-projects --resume
35
+
36
+ # Combined
37
+ /specweave-jira:import-projects --filter active --dry-run
38
+ ```
39
+
40
+ ## Your Task
41
+
42
+ When the user runs this command:
43
+
44
+ ### Step 1: Validate Prerequisites
45
+ ```typescript
46
+ import { readEnvFile, parseEnvFile } from '../../../src/utils/env-file.js';
47
+
48
+ // 1. Check if Jira credentials exist
49
+ const envContent = readEnvFile(process.cwd());
50
+ const parsed = parseEnvFile(envContent);
51
+
52
+ if (!parsed.JIRA_API_TOKEN || !parsed.JIRA_EMAIL || !parsed.JIRA_DOMAIN) {
53
+ console.log('❌ Missing Jira credentials. Run `specweave init` first.');
54
+ return;
55
+ }
56
+
57
+ // 2. Get existing projects
58
+ const existingProjects = parsed.JIRA_PROJECTS?.split(',') || [];
59
+ console.log(`\n📋 Current projects: ${existingProjects.join(', ') || 'None'}\n`);
60
+ ```
61
+
62
+ ### Step 2: Fetch Available Projects
63
+ ```typescript
64
+ import { getProjectCount } from '../../../src/cli/helpers/project-count-fetcher.js';
65
+ import { AsyncProjectLoader } from '../../../src/cli/helpers/async-project-loader.js';
66
+
67
+ // Count check (< 1 second)
68
+ const countResult = await getProjectCount({
69
+ provider: 'jira',
70
+ credentials: {
71
+ domain: parsed.JIRA_DOMAIN,
72
+ email: parsed.JIRA_EMAIL,
73
+ token: parsed.JIRA_API_TOKEN,
74
+ instanceType: 'cloud'
75
+ }
76
+ });
77
+
78
+ console.log(`✓ Found ${countResult.accessible} accessible projects`);
79
+
80
+ // Fetch all projects (with smart pagination)
81
+ const loader = new AsyncProjectLoader(
82
+ {
83
+ domain: parsed.JIRA_DOMAIN,
84
+ email: parsed.JIRA_EMAIL,
85
+ token: parsed.JIRA_API_TOKEN,
86
+ instanceType: 'cloud'
87
+ },
88
+ 'jira',
89
+ {
90
+ batchSize: 50,
91
+ updateFrequency: 5,
92
+ showEta: true
93
+ }
94
+ );
95
+
96
+ const result = await loader.fetchAllProjects(countResult.accessible);
97
+ let allProjects = result.projects;
98
+ ```
99
+
100
+ ### Step 3: Apply Filters (if specified)
101
+ ```typescript
102
+ import { FilterProcessor } from '../../../src/integrations/jira/filter-processor.js';
103
+
104
+ const options = {
105
+ filter: args.filter, // 'active' | 'all'
106
+ type: args.type, // 'agile' | 'software' | 'business'
107
+ lead: args.lead, // Email address
108
+ jql: args.jql // Custom JQL
109
+ };
110
+
111
+ const filterProcessor = new FilterProcessor({ domain: parsed.JIRA_DOMAIN, token: parsed.JIRA_API_TOKEN });
112
+ const filteredProjects = await filterProcessor.applyFilters(allProjects, options);
113
+
114
+ console.log(`\n🔍 Filters applied:`);
115
+ if (options.filter === 'active') console.log(` • Active projects only`);
116
+ if (options.type) console.log(` • Type: ${options.type}`);
117
+ if (options.lead) console.log(` • Lead: ${options.lead}`);
118
+ if (options.jql) console.log(` • JQL: ${options.jql}`);
119
+ console.log(`\n📊 Results: ${filteredProjects.length} projects (down from ${allProjects.length})\n`);
120
+ ```
121
+
122
+ ### Step 4: Exclude Existing Projects
123
+ ```typescript
124
+ const newProjects = filteredProjects.filter(p => !existingProjects.includes(p.key));
125
+
126
+ if (newProjects.length === 0) {
127
+ console.log('✅ No new projects to import. All filtered projects are already configured.');
128
+ return;
129
+ }
130
+
131
+ console.log(`📥 ${newProjects.length} new project(s) available for import:\n`);
132
+ newProjects.forEach(p => {
133
+ console.log(` ✨ ${p.key} - ${p.name} (${p.projectTypeKey}, lead: ${p.lead?.displayName || 'N/A'})`);
134
+ });
135
+ ```
136
+
137
+ ### Step 5: Dry-Run or Execute
138
+ ```typescript
139
+ if (args.dryRun) {
140
+ console.log('\n🔎 DRY RUN: No changes will be made.\n');
141
+ console.log('The following projects would be imported:');
142
+ newProjects.forEach(p => {
143
+ const status = p.archived ? '⏭️ (archived - skipped)' : '✨';
144
+ console.log(` ${status} ${p.key} - ${p.name}`);
145
+ });
146
+ console.log(`\nTotal: ${newProjects.filter(p => !p.archived).length} projects would be imported\n`);
147
+ return;
148
+ }
149
+
150
+ // Confirm import
151
+ const { confirmed } = await inquirer.prompt([{
152
+ type: 'confirm',
153
+ name: 'confirmed',
154
+ message: `Import ${newProjects.length} project(s)?`,
155
+ default: true
156
+ }]);
157
+
158
+ if (!confirmed) {
159
+ console.log('⏭️ Import cancelled.');
160
+ return;
161
+ }
162
+ ```
163
+
164
+ ### Step 6: Merge with Existing
165
+ ```typescript
166
+ import { updateEnvFile, mergeProjectList } from '../../../src/utils/env-manager.js';
167
+
168
+ const newKeys = newProjects.map(p => p.key);
169
+ const mergedProjects = mergeProjectList(existingProjects, newKeys);
170
+
171
+ // Update .env file (atomic write)
172
+ await updateEnvFile('JIRA_PROJECTS', mergedProjects.join(','));
173
+
174
+ console.log('\n✅ Projects imported successfully!\n');
175
+ console.log(`Updated: ${existingProjects.length} → ${mergedProjects.length} projects`);
176
+ console.log(`\nCurrent projects:\n ${mergedProjects.join(', ')}\n`);
177
+ ```
178
+
179
+ ### Step 7: Resume Support
180
+ ```typescript
181
+ if (args.resume) {
182
+ const { CacheManager } = await import('../../../src/core/cache/cache-manager.js');
183
+ const cacheManager = new CacheManager(process.cwd());
184
+
185
+ const importState = await cacheManager.get('jira-import-state');
186
+
187
+ if (!importState) {
188
+ console.log('⚠️ No import state found. Use without --resume to start fresh.');
189
+ return;
190
+ }
191
+
192
+ console.log(`\n📂 Resuming from: ${importState.lastProject} (${importState.completed}/${importState.total})`);
193
+
194
+ // Skip already-imported projects
195
+ const remainingProjects = allProjects.filter(p => !importState.succeeded.includes(p.key));
196
+
197
+ // Continue import with remaining projects
198
+ // (use same logic as Step 6)
199
+ }
200
+ ```
201
+
202
+ ## Examples
203
+
204
+ ### Example 1: Basic Import
205
+ **User**: `/specweave-jira:import-projects`
206
+
207
+ **Output**:
208
+ ```
209
+ 📋 Current projects: BACKEND, FRONTEND
210
+
211
+ ✓ Found 127 accessible projects
212
+ 📥 5 new project(s) available for import:
213
+
214
+ ✨ MOBILE - Mobile App (agile, lead: John Doe)
215
+ ✨ INFRA - Infrastructure (software, lead: Jane Smith)
216
+ ✨ QA - Quality Assurance (business, lead: Bob Wilson)
217
+ ✨ DOCS - Documentation (business, lead: Alice Cooper)
218
+ ✨ LEGACY - Legacy System (archived - skipped)
219
+
220
+ Import 5 project(s)? (Y/n)
221
+
222
+ ✅ Projects imported successfully!
223
+
224
+ Updated: 2 → 6 projects
225
+
226
+ Current projects:
227
+ BACKEND, FRONTEND, MOBILE, INFRA, QA, DOCS
228
+ ```
229
+
230
+ ### Example 2: Filter Active Only
231
+ **User**: `/specweave-jira:import-projects --filter active`
232
+
233
+ **Output**:
234
+ ```
235
+ 🔍 Filters applied:
236
+ • Active projects only
237
+
238
+ 📊 Results: 120 projects (down from 127)
239
+
240
+ 📥 4 new project(s) available for import:
241
+ (LEGACY project excluded because it's archived)
242
+ ```
243
+
244
+ ### Example 3: Dry-Run
245
+ **User**: `/specweave-jira:import-projects --dry-run`
246
+
247
+ **Output**:
248
+ ```
249
+ 🔎 DRY RUN: No changes will be made.
250
+
251
+ The following projects would be imported:
252
+ ✨ MOBILE - Mobile App
253
+ ✨ INFRA - Infrastructure
254
+ ✨ QA - Quality Assurance
255
+ ⏭️ LEGACY - Legacy System (archived - skipped)
256
+
257
+ Total: 3 projects would be imported
258
+ ```
259
+
260
+ ### Example 4: Custom JQL Filter
261
+ **User**: `/specweave-jira:import-projects --jql "project IN (MOBILE, INFRA) AND status != Archived"`
262
+
263
+ **Output**:
264
+ ```
265
+ 🔍 Filters applied:
266
+ • JQL: project IN (MOBILE, INFRA) AND status != Archived
267
+
268
+ 📊 Results: 2 projects (down from 127)
269
+
270
+ 📥 2 new project(s) available for import:
271
+ ✨ MOBILE - Mobile App
272
+ ✨ INFRA - Infrastructure
273
+ ```
274
+
275
+ ## Important Notes
276
+
277
+ - **Merge Logic**: No duplicates. Existing projects are preserved.
278
+ - **Atomic Updates**: Uses temp file + rename to prevent corruption.
279
+ - **Progress Tracking**: Shows progress bar for large imports (> 50 projects).
280
+ - **Resume Support**: Interrupted imports can be resumed with `--resume`.
281
+ - **Backup**: Creates `.env.backup` before modifying `.env`.
282
+
283
+ ## Related Commands
284
+
285
+ - `/specweave:init` - Initial SpecWeave setup
286
+ - `/specweave-jira:sync` - Sync increments with Jira epics
287
+ - `/specweave-jira:refresh-cache` - Clear cached project data
288
+
289
+ ## Error Handling
290
+
291
+ - **Missing Credentials**: Prompt user to run `specweave init` first
292
+ - **API Errors**: Show clear error message with suggestion
293
+ - **No New Projects**: Inform user all projects already imported
294
+ - **Permission Errors**: Check `.env` file permissions
295
+
296
+ ---
297
+
298
+ **Post-Init Flexibility**: This command provides flexibility to add projects after initial setup, supporting evolving team structures and project lifecycles.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "specweave-kafka",
3
3
  "description": "Apache Kafka event streaming integration with MCP servers, CLI tools (kcat), Terraform modules, and comprehensive observability stack",
4
- "version": "0.22.14",
4
+ "version": "0.24.0",
5
5
  "author": {
6
6
  "name": "SpecWeave Team",
7
7
  "url": "https://spec-weave.com"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "specweave-kafka-streams",
3
3
  "description": "Kafka Streams library integration for SpecWeave - Stream processing with Java/Kotlin, topology patterns, state stores, windowing, joins, and testing frameworks",
4
- "version": "0.22.14",
4
+ "version": "0.24.0",
5
5
  "author": {
6
6
  "name": "SpecWeave Team",
7
7
  "url": "https://spec-weave.com"