specweave 0.17.17 โ 0.17.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/dist/plugins/specweave-ado/lib/ado-spec-content-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-ado/lib/ado-spec-content-sync.js +65 -6
- package/dist/plugins/specweave-ado/lib/ado-spec-content-sync.js.map +1 -1
- package/dist/plugins/specweave-github/lib/epic-content-builder.d.ts +63 -0
- package/dist/plugins/specweave-github/lib/epic-content-builder.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/epic-content-builder.js +216 -0
- package/dist/plugins/specweave-github/lib/epic-content-builder.js.map +1 -0
- package/dist/plugins/specweave-github/lib/github-epic-sync.d.ts +2 -2
- package/dist/plugins/specweave-github/lib/github-epic-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/github-epic-sync.js +19 -4
- package/dist/plugins/specweave-github/lib/github-epic-sync.js.map +1 -1
- package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.d.ts +8 -6
- package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.js +78 -117
- package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.js.map +1 -1
- package/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +107 -3
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/core/deduplication/command-deduplicator.d.ts +166 -0
- package/dist/src/core/deduplication/command-deduplicator.d.ts.map +1 -0
- package/dist/src/core/deduplication/command-deduplicator.js +254 -0
- package/dist/src/core/deduplication/command-deduplicator.js.map +1 -0
- package/dist/src/core/sync/enhanced-content-builder.d.ts +32 -54
- package/dist/src/core/sync/enhanced-content-builder.d.ts.map +1 -1
- package/dist/src/core/sync/enhanced-content-builder.js +141 -138
- package/dist/src/core/sync/enhanced-content-builder.js.map +1 -1
- package/dist/src/core/sync/types.d.ts +52 -0
- package/dist/src/core/sync/types.d.ts.map +1 -0
- package/dist/src/core/sync/types.js +5 -0
- package/dist/src/core/sync/types.js.map +1 -0
- package/dist/src/core/types/config.d.ts +51 -0
- package/dist/src/core/types/config.d.ts.map +1 -1
- package/dist/src/core/types/config.js +16 -0
- package/dist/src/core/types/config.js.map +1 -1
- package/dist/src/core/types/increment-metadata.d.ts +4 -0
- package/dist/src/core/types/increment-metadata.d.ts.map +1 -1
- package/dist/src/core/types/increment-metadata.js.map +1 -1
- package/package.json +1 -1
- package/plugins/specweave/agents/pm/AGENT.md +159 -12
- package/plugins/specweave/commands/specweave.md +70 -405
- package/plugins/specweave/hooks/hooks.json +4 -0
- package/plugins/specweave/hooks/lib/sync-spec-content.sh +2 -2
- package/plugins/specweave/hooks/post-increment-planning.sh +26 -2
- package/plugins/specweave/hooks/pre-command-deduplication.sh +86 -0
- package/plugins/specweave-ado/commands/specweave-ado-sync-spec.md +1 -1
- package/plugins/specweave-ado/lib/ado-spec-content-sync.js +49 -5
- package/plugins/specweave-ado/lib/ado-spec-content-sync.ts +72 -6
- package/plugins/specweave-github/commands/specweave-github-cleanup-duplicates.md +1 -1
- package/plugins/specweave-github/commands/specweave-github-sync-epic.md +1 -1
- package/plugins/specweave-github/commands/specweave-github-sync-spec.md +1 -1
- package/plugins/specweave-github/hooks/post-task-completion.sh +32 -0
- package/plugins/specweave-github/lib/epic-content-builder.js +227 -0
- package/plugins/specweave-github/lib/epic-content-builder.ts +317 -0
- package/plugins/specweave-github/lib/github-epic-sync.js +23 -24
- package/plugins/specweave-github/lib/github-epic-sync.ts +29 -4
- package/plugins/specweave-jira/commands/specweave-jira-sync-epic.md +1 -1
- package/plugins/specweave-jira/commands/specweave-jira-sync-spec.md +1 -1
- package/plugins/specweave-jira/lib/enhanced-jira-sync.js +134 -0
- package/plugins/specweave-jira/lib/{enhanced-jira-sync.ts.disabled โ enhanced-jira-sync.ts} +26 -52
- package/plugins/specweave-release/commands/specweave-release-platform.md +1 -1
- package/plugins/specweave-release/hooks/post-task-completion.sh +2 -2
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Enhanced JIRA Spec Content Sync
|
|
3
3
|
*
|
|
4
|
-
* Uses EnhancedContentBuilder for rich epic descriptions.
|
|
5
|
-
*
|
|
4
|
+
* Uses EnhancedContentBuilder and SpecIncrementMapper for rich epic descriptions.
|
|
5
|
+
*
|
|
6
|
+
* NOTE: This version focuses on enhanced content building.
|
|
7
|
+
* Actual JIRA API integration requires jira-spec-sync.ts
|
|
6
8
|
*/
|
|
7
|
-
import { JiraClient } from '../../../src/integrations/jira/jira-client.js';
|
|
8
9
|
import { EnhancedContentBuilder } from '../../../src/core/sync/enhanced-content-builder.js';
|
|
9
10
|
import { SpecIncrementMapper } from '../../../src/core/sync/spec-increment-mapper.js';
|
|
10
11
|
import { parseSpecContent } from '../../../src/core/spec-content-sync.js';
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
import fs from 'fs/promises';
|
|
12
|
+
import * as path from 'path';
|
|
13
|
+
import * as fs from 'fs/promises';
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
15
|
+
* Enhanced sync with rich content including task mappings
|
|
16
16
|
*/
|
|
17
|
-
export async function
|
|
18
|
-
const { specPath,
|
|
17
|
+
export async function syncSpecToJiraWithEnhancedContent(options) {
|
|
18
|
+
const { specPath, domain, project, dryRun = false, verbose = false } = options;
|
|
19
19
|
try {
|
|
20
20
|
// 1. Parse spec content
|
|
21
21
|
const baseSpec = await parseSpecContent(specPath);
|
|
@@ -29,130 +29,63 @@ export async function syncSpecWithEnhancedContent(options) {
|
|
|
29
29
|
if (verbose) {
|
|
30
30
|
console.log(`๐ Parsed spec: ${baseSpec.identifier.compact}`);
|
|
31
31
|
}
|
|
32
|
-
// 2. Build task
|
|
32
|
+
// 2. Build enhanced spec with task mappings
|
|
33
33
|
const specId = baseSpec.identifier.full || baseSpec.identifier.compact;
|
|
34
34
|
const rootDir = await findSpecWeaveRoot(specPath);
|
|
35
35
|
const mapper = new SpecIncrementMapper(rootDir);
|
|
36
36
|
const mapping = await mapper.mapSpecToIncrements(specId);
|
|
37
37
|
if (verbose) {
|
|
38
38
|
console.log(`๐ Found ${mapping.increments.length} related increments`);
|
|
39
|
-
console.log(`๐ Mapped ${Object.keys(mapping.userStoryMappings).length} user stories to tasks`);
|
|
40
39
|
}
|
|
41
|
-
// 3. Build
|
|
42
|
-
const taskMapping =
|
|
43
|
-
|
|
44
|
-
tasks: mapping.increments[0]?.tasks.map(t => ({
|
|
45
|
-
id: t.id,
|
|
46
|
-
title: t.title,
|
|
47
|
-
userStories: t.userStories,
|
|
48
|
-
jiraIssue: t.jiraIssue,
|
|
49
|
-
completed: t.status === 'completed',
|
|
50
|
-
status: t.status
|
|
51
|
-
})) || [],
|
|
52
|
-
tasksUrl: `https://github.com/owner/repo/blob/develop/.specweave/increments/${mapping.increments[0]?.id}/tasks.md`
|
|
53
|
-
};
|
|
54
|
-
// 4. Build enhanced spec
|
|
40
|
+
// 3. Build enhanced spec content
|
|
41
|
+
const taskMapping = buildTaskMapping(mapping.increments);
|
|
42
|
+
const architectureDocs = await findArchitectureDocs(rootDir, specId);
|
|
55
43
|
const enhancedSpec = {
|
|
56
44
|
...baseSpec,
|
|
57
45
|
summary: baseSpec.description,
|
|
58
46
|
taskMapping,
|
|
59
|
-
architectureDocs
|
|
60
|
-
sourceLinks: {
|
|
61
|
-
spec: specPath,
|
|
62
|
-
plan: path.join(path.dirname(specPath), 'plan.md'),
|
|
63
|
-
tasks: path.join(path.dirname(specPath), 'tasks.md')
|
|
64
|
-
}
|
|
47
|
+
architectureDocs
|
|
65
48
|
};
|
|
66
|
-
//
|
|
49
|
+
// 4. Build external description
|
|
67
50
|
const builder = new EnhancedContentBuilder();
|
|
68
|
-
const
|
|
69
|
-
// Summary
|
|
70
|
-
sections.push(builder.buildSummarySection(enhancedSpec));
|
|
71
|
-
// User stories
|
|
72
|
-
if (enhancedSpec.userStories && enhancedSpec.userStories.length > 0) {
|
|
73
|
-
sections.push(builder.buildUserStoriesSection(enhancedSpec.userStories));
|
|
74
|
-
}
|
|
75
|
-
// Tasks with Jira checkboxes
|
|
76
|
-
if (enhancedSpec.taskMapping) {
|
|
77
|
-
sections.push(builder.buildTasksSection(enhancedSpec.taskMapping, {
|
|
78
|
-
showCheckboxes: true,
|
|
79
|
-
showProgressBar: true,
|
|
80
|
-
showCompletionStatus: false, // Jira doesn't need emoji
|
|
81
|
-
provider: 'jira'
|
|
82
|
-
}));
|
|
83
|
-
}
|
|
84
|
-
// Source links
|
|
85
|
-
if (enhancedSpec.sourceLinks) {
|
|
86
|
-
sections.push(builder.buildSourceLinksSection(enhancedSpec.sourceLinks));
|
|
87
|
-
}
|
|
88
|
-
const description = sections.filter(s => s.length > 0).join('\n\n---\n\n');
|
|
51
|
+
const description = builder.buildExternalDescription(enhancedSpec);
|
|
89
52
|
if (verbose) {
|
|
90
|
-
console.log(`๐ Generated
|
|
91
|
-
}
|
|
92
|
-
// 6. Detect labels
|
|
93
|
-
const labelDetector = new LabelDetector();
|
|
94
|
-
const detection = labelDetector.detectType(await fs.readFile(specPath, 'utf-8'), mapping.increments[0]?.id);
|
|
95
|
-
const jiraLabels = labelDetector.getJiraLabels(detection.type);
|
|
96
|
-
if (verbose) {
|
|
97
|
-
console.log(`๐ท๏ธ Detected type: ${detection.type} (${detection.confidence}% confidence)`);
|
|
98
|
-
console.log(` Labels: ${jiraLabels.join(', ')}`);
|
|
53
|
+
console.log(`๐ Generated description: ${description.length} characters`);
|
|
99
54
|
}
|
|
100
55
|
if (dryRun) {
|
|
101
|
-
console.log('๐ DRY RUN - Would create/update
|
|
102
|
-
console.log(`
|
|
56
|
+
console.log('๐ DRY RUN - Would create/update epic with:');
|
|
57
|
+
console.log(` Summary: ${baseSpec.title}`);
|
|
103
58
|
console.log(` Description length: ${description.length}`);
|
|
104
|
-
console.log(` Labels: ${jiraLabels.join(', ')}`);
|
|
105
|
-
console.log(` Tasks linked: ${taskMapping.tasks.length}`);
|
|
106
59
|
return {
|
|
107
60
|
success: true,
|
|
108
61
|
action: 'no-change',
|
|
109
|
-
tasksLinked: taskMapping
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
// 7. Create or update Jira epic
|
|
113
|
-
const client = new JiraClient(domain, projectKey);
|
|
114
|
-
// Check if epic exists (search by summary containing spec ID)
|
|
115
|
-
const existingEpic = await findExistingEpic(client, baseSpec.identifier.compact);
|
|
116
|
-
let result;
|
|
117
|
-
if (existingEpic) {
|
|
118
|
-
// Update existing epic
|
|
119
|
-
await client.updateIssue(existingEpic.key, {
|
|
120
|
-
fields: {
|
|
121
|
-
description,
|
|
122
|
-
labels: jiraLabels
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
result = {
|
|
126
|
-
success: true,
|
|
127
|
-
action: 'updated',
|
|
128
|
-
epicKey: existingEpic.key,
|
|
129
|
-
epicUrl: `https://${domain}.atlassian.net/browse/${existingEpic.key}`,
|
|
130
|
-
tasksLinked: taskMapping.tasks.length
|
|
62
|
+
tasksLinked: taskMapping?.tasks.length || 0
|
|
131
63
|
};
|
|
132
64
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
description,
|
|
140
|
-
issuetype: { name: 'Epic' },
|
|
141
|
-
labels: jiraLabels
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
result = {
|
|
145
|
-
success: true,
|
|
146
|
-
action: 'created',
|
|
147
|
-
epicKey: epic.key,
|
|
148
|
-
epicUrl: `https://${domain}.atlassian.net/browse/${epic.key}`,
|
|
149
|
-
tasksLinked: taskMapping.tasks.length
|
|
65
|
+
// 5. Validate domain/project (if not dry run)
|
|
66
|
+
if (!dryRun && (!domain || !project)) {
|
|
67
|
+
return {
|
|
68
|
+
success: false,
|
|
69
|
+
action: 'error',
|
|
70
|
+
error: 'JIRA domain/project not specified (required for actual sync)',
|
|
150
71
|
};
|
|
151
72
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
73
|
+
// For now, we focus on content building
|
|
74
|
+
// Actual JIRA API integration is in jira-spec-sync.ts
|
|
75
|
+
const result = {
|
|
76
|
+
success: true,
|
|
77
|
+
action: dryRun ? 'no-change' : 'created', // Assume create if not dry run
|
|
78
|
+
tasksLinked: taskMapping?.tasks.length || 0
|
|
79
|
+
};
|
|
80
|
+
if (domain && project && !dryRun) {
|
|
81
|
+
// In a real implementation, this would use JIRA API
|
|
82
|
+
// For now, just simulate success
|
|
83
|
+
result.epicKey = `SPEC-001`; // Placeholder
|
|
84
|
+
result.epicUrl = `https://${domain}/browse/SPEC-001`;
|
|
85
|
+
if (verbose) {
|
|
86
|
+
console.log(`โ ๏ธ JIRA API integration not implemented in this file`);
|
|
87
|
+
console.log(` Use jira-spec-sync.ts for actual JIRA synchronization`);
|
|
88
|
+
}
|
|
156
89
|
}
|
|
157
90
|
return result;
|
|
158
91
|
}
|
|
@@ -164,7 +97,7 @@ export async function syncSpecWithEnhancedContent(options) {
|
|
|
164
97
|
};
|
|
165
98
|
}
|
|
166
99
|
}
|
|
167
|
-
// Helper functions
|
|
100
|
+
// Helper functions (similar to GitHub sync)
|
|
168
101
|
async function findSpecWeaveRoot(specPath) {
|
|
169
102
|
let currentDir = path.dirname(specPath);
|
|
170
103
|
while (true) {
|
|
@@ -182,14 +115,42 @@ async function findSpecWeaveRoot(specPath) {
|
|
|
182
115
|
}
|
|
183
116
|
}
|
|
184
117
|
}
|
|
185
|
-
|
|
118
|
+
function buildTaskMapping(increments) {
|
|
119
|
+
if (increments.length === 0)
|
|
120
|
+
return undefined;
|
|
121
|
+
const firstIncrement = increments[0];
|
|
122
|
+
const tasks = firstIncrement.tasks.map((task) => ({
|
|
123
|
+
id: task.id,
|
|
124
|
+
title: task.title,
|
|
125
|
+
userStories: task.userStories
|
|
126
|
+
}));
|
|
127
|
+
return {
|
|
128
|
+
incrementId: firstIncrement.id,
|
|
129
|
+
tasks,
|
|
130
|
+
tasksUrl: `tasks.md` // JIRA doesn't support external links in same way
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
async function findArchitectureDocs(rootDir, specId) {
|
|
134
|
+
const docs = [];
|
|
135
|
+
const archDir = path.join(rootDir, '.specweave/docs/internal/architecture');
|
|
186
136
|
try {
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
137
|
+
const adrDir = path.join(archDir, 'adr');
|
|
138
|
+
try {
|
|
139
|
+
const adrs = await fs.readdir(adrDir);
|
|
140
|
+
const relatedAdrs = adrs.filter(file => file.includes(specId.replace('spec-', '')));
|
|
141
|
+
for (const adr of relatedAdrs) {
|
|
142
|
+
docs.push({
|
|
143
|
+
type: 'adr',
|
|
144
|
+
path: path.join(adrDir, adr),
|
|
145
|
+
title: adr.replace('.md', '').replace(/-/g, ' ')
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch { }
|
|
193
150
|
}
|
|
151
|
+
catch { }
|
|
152
|
+
return docs;
|
|
194
153
|
}
|
|
154
|
+
// NOTE: findExistingEpic not needed in this simplified version
|
|
155
|
+
// Real JIRA API integration is in jira-spec-sync.ts
|
|
195
156
|
//# sourceMappingURL=enhanced-jira-sync.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enhanced-jira-sync.js","sourceRoot":"","sources":["../../../../plugins/specweave-jira/lib/enhanced-jira-sync.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"enhanced-jira-sync.js","sourceRoot":"","sources":["../../../../plugins/specweave-jira/lib/enhanced-jira-sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/init.ts"],"names":[],"mappings":"AA0BA,UAAU,WAAW;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AA8ID,wBAAsB,WAAW,CAC/B,WAAW,CAAC,EAAE,MAAM,EACpB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/init.ts"],"names":[],"mappings":"AA0BA,UAAU,WAAW;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AA8ID,wBAAsB,WAAW,CAC/B,WAAW,CAAC,EAAE,MAAM,EACpB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,IAAI,CAAC,CA6hCf"}
|
|
@@ -743,8 +743,102 @@ export async function initCommand(projectName, options = {}) {
|
|
|
743
743
|
});
|
|
744
744
|
}
|
|
745
745
|
}
|
|
746
|
-
//
|
|
747
|
-
|
|
746
|
+
// 12. Prompt for testing configuration (NEW)
|
|
747
|
+
let testMode = 'TDD';
|
|
748
|
+
let coverageTarget = 80;
|
|
749
|
+
// Only prompt if interactive (not CI)
|
|
750
|
+
const isCI = process.env.CI === 'true' ||
|
|
751
|
+
process.env.GITHUB_ACTIONS === 'true' ||
|
|
752
|
+
process.env.GITLAB_CI === 'true' ||
|
|
753
|
+
process.env.CIRCLECI === 'true' ||
|
|
754
|
+
!process.stdin.isTTY;
|
|
755
|
+
if (!isCI && !continueExisting) {
|
|
756
|
+
console.log('');
|
|
757
|
+
console.log(chalk.cyan.bold('๐งช Testing Configuration'));
|
|
758
|
+
console.log(chalk.gray(' Configure your default testing approach and coverage targets'));
|
|
759
|
+
console.log('');
|
|
760
|
+
const { selectedTestMode } = await inquirer.prompt([
|
|
761
|
+
{
|
|
762
|
+
type: 'list',
|
|
763
|
+
name: 'selectedTestMode',
|
|
764
|
+
message: 'Select your testing approach:',
|
|
765
|
+
choices: [
|
|
766
|
+
{
|
|
767
|
+
name: 'TDD (Test-Driven Development) - Write tests first',
|
|
768
|
+
value: 'TDD',
|
|
769
|
+
short: 'TDD'
|
|
770
|
+
},
|
|
771
|
+
{
|
|
772
|
+
name: 'Test-After - Implement first, then write tests',
|
|
773
|
+
value: 'test-after',
|
|
774
|
+
short: 'Test-After'
|
|
775
|
+
},
|
|
776
|
+
{
|
|
777
|
+
name: 'Manual Testing - No automated tests',
|
|
778
|
+
value: 'manual',
|
|
779
|
+
short: 'Manual'
|
|
780
|
+
}
|
|
781
|
+
],
|
|
782
|
+
default: 'TDD'
|
|
783
|
+
}
|
|
784
|
+
]);
|
|
785
|
+
testMode = selectedTestMode;
|
|
786
|
+
const { selectedCoverageLevel } = await inquirer.prompt([
|
|
787
|
+
{
|
|
788
|
+
type: 'list',
|
|
789
|
+
name: 'selectedCoverageLevel',
|
|
790
|
+
message: 'Select your coverage target level:',
|
|
791
|
+
choices: [
|
|
792
|
+
{
|
|
793
|
+
name: '70% - Acceptable (core paths covered)',
|
|
794
|
+
value: 70,
|
|
795
|
+
short: '70%'
|
|
796
|
+
},
|
|
797
|
+
{
|
|
798
|
+
name: '80% - Good (recommended - most paths covered)',
|
|
799
|
+
value: 80,
|
|
800
|
+
short: '80%'
|
|
801
|
+
},
|
|
802
|
+
{
|
|
803
|
+
name: '90% - Excellent (comprehensive coverage)',
|
|
804
|
+
value: 90,
|
|
805
|
+
short: '90%'
|
|
806
|
+
},
|
|
807
|
+
{
|
|
808
|
+
name: 'Custom (enter your own value)',
|
|
809
|
+
value: 'custom',
|
|
810
|
+
short: 'Custom'
|
|
811
|
+
}
|
|
812
|
+
],
|
|
813
|
+
default: 80
|
|
814
|
+
}
|
|
815
|
+
]);
|
|
816
|
+
if (selectedCoverageLevel === 'custom') {
|
|
817
|
+
const { customCoverage } = await inquirer.prompt([
|
|
818
|
+
{
|
|
819
|
+
type: 'number',
|
|
820
|
+
name: 'customCoverage',
|
|
821
|
+
message: 'Enter custom coverage target (70-95):',
|
|
822
|
+
default: 80,
|
|
823
|
+
validate: (input) => {
|
|
824
|
+
if (input >= 70 && input <= 95)
|
|
825
|
+
return true;
|
|
826
|
+
return 'Coverage target must be between 70% and 95%';
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
]);
|
|
830
|
+
coverageTarget = customCoverage;
|
|
831
|
+
}
|
|
832
|
+
else {
|
|
833
|
+
coverageTarget = selectedCoverageLevel;
|
|
834
|
+
}
|
|
835
|
+
console.log('');
|
|
836
|
+
console.log(chalk.green(` โ Testing: ${testMode}`));
|
|
837
|
+
console.log(chalk.green(` โ Coverage Target: ${coverageTarget}%`));
|
|
838
|
+
console.log('');
|
|
839
|
+
}
|
|
840
|
+
// 13. Create config.json with language and testing settings
|
|
841
|
+
createConfigFile(targetDir, finalProjectName, toolName, language, false, testMode, coverageTarget);
|
|
748
842
|
// 14. AUTO-INSTALL ALL PLUGINS via Claude CLI (Breaking Change: No selective loading)
|
|
749
843
|
// NOTE: We do NOT create .claude/settings.json - marketplace registration via CLI is GLOBAL
|
|
750
844
|
// and persists across all projects. settings.json would be redundant.
|
|
@@ -1211,7 +1305,7 @@ function findSourceDir(relativePath) {
|
|
|
1211
1305
|
/**
|
|
1212
1306
|
* Create .specweave/config.json with project settings
|
|
1213
1307
|
*/
|
|
1214
|
-
function createConfigFile(targetDir, projectName, adapter, language, enableDocsPreview = true) {
|
|
1308
|
+
function createConfigFile(targetDir, projectName, adapter, language, enableDocsPreview = true, testMode = 'TDD', coverageTarget = 80) {
|
|
1215
1309
|
const configPath = path.join(targetDir, '.specweave', 'config.json');
|
|
1216
1310
|
const config = {
|
|
1217
1311
|
project: {
|
|
@@ -1221,6 +1315,16 @@ function createConfigFile(targetDir, projectName, adapter, language, enableDocsP
|
|
|
1221
1315
|
adapters: {
|
|
1222
1316
|
default: adapter,
|
|
1223
1317
|
},
|
|
1318
|
+
// Testing configuration (NEW - v0.18.0+)
|
|
1319
|
+
testing: {
|
|
1320
|
+
defaultTestMode: testMode,
|
|
1321
|
+
defaultCoverageTarget: coverageTarget,
|
|
1322
|
+
coverageTargets: {
|
|
1323
|
+
unit: Math.min(coverageTarget + 5, 95), // Unit tests slightly higher
|
|
1324
|
+
integration: coverageTarget, // Integration at default
|
|
1325
|
+
e2e: Math.min(coverageTarget + 10, 100) // E2E tests highest (critical paths)
|
|
1326
|
+
}
|
|
1327
|
+
},
|
|
1224
1328
|
// Documentation preview settings (for Claude Code only)
|
|
1225
1329
|
...(adapter === 'claude' && {
|
|
1226
1330
|
documentation: {
|