specweave 0.23.8 → 0.23.10
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 +118 -0
- package/dist/src/cli/commands/migrate-config.d.ts +22 -0
- package/dist/src/cli/commands/migrate-config.d.ts.map +1 -0
- package/dist/src/cli/commands/migrate-config.js +149 -0
- package/dist/src/cli/commands/migrate-config.js.map +1 -0
- package/dist/src/cli/helpers/issue-tracker/index.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/index.js +112 -60
- package/dist/src/cli/helpers/issue-tracker/index.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/jira.d.ts +24 -1
- package/dist/src/cli/helpers/issue-tracker/jira.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/jira.js +111 -131
- package/dist/src/cli/helpers/issue-tracker/jira.js.map +1 -1
- package/dist/src/core/config/config-manager.d.ts +135 -0
- package/dist/src/core/config/config-manager.d.ts.map +1 -0
- package/dist/src/core/config/config-manager.js +341 -0
- package/dist/src/core/config/config-manager.js.map +1 -0
- package/dist/src/core/config/config-migrator.d.ts +102 -0
- package/dist/src/core/config/config-migrator.d.ts.map +1 -0
- package/dist/src/core/config/config-migrator.js +367 -0
- package/dist/src/core/config/config-migrator.js.map +1 -0
- package/dist/src/core/config/index.d.ts +10 -0
- package/dist/src/core/config/index.d.ts.map +1 -0
- package/dist/src/core/config/index.js +10 -0
- package/dist/src/core/config/index.js.map +1 -0
- package/dist/src/core/config/types.d.ts +216 -0
- package/dist/src/core/config/types.d.ts.map +1 -0
- package/dist/src/core/config/types.js +32 -0
- package/dist/src/core/config/types.js.map +1 -0
- package/dist/src/integrations/jira/jira-hierarchy-mapper.d.ts +104 -0
- package/dist/src/integrations/jira/jira-hierarchy-mapper.d.ts.map +1 -0
- package/dist/src/integrations/jira/jira-hierarchy-mapper.js +178 -0
- package/dist/src/integrations/jira/jira-hierarchy-mapper.js.map +1 -0
- package/package.json +1 -1
- package/plugins/specweave/commands/migrate-config.md +104 -0
- package/plugins/specweave/hooks/post-task-completion.sh +1 -1
- package/plugins/specweave/hooks/pre-task-completion.sh +1 -1
- package/plugins/specweave-ado/hooks/post-task-completion.sh +1 -1
- package/plugins/specweave-github/hooks/post-task-completion.sh +1 -1
- package/plugins/specweave-jira/hooks/post-task-completion.sh +1 -1
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +132 -0
package/CLAUDE.md
CHANGED
|
@@ -1592,6 +1592,124 @@ vim .specweave/docs/internal/architecture/hld-system.md
|
|
|
1592
1592
|
vim .specweave/docs/public/guides/user-guide.md
|
|
1593
1593
|
```
|
|
1594
1594
|
|
|
1595
|
+
### Configuration Management
|
|
1596
|
+
|
|
1597
|
+
**CRITICAL**: SpecWeave separates secrets from configuration (v0.24.0+)
|
|
1598
|
+
|
|
1599
|
+
**Architecture**:
|
|
1600
|
+
- **Secrets** (tokens, passwords) → `.env` (gitignored, NEVER commit)
|
|
1601
|
+
- **Configuration** (domains, strategies, settings) → `.specweave/config.json` (committed to git)
|
|
1602
|
+
|
|
1603
|
+
**Why this matters**:
|
|
1604
|
+
- ✅ Team shares configuration via git
|
|
1605
|
+
- ✅ Secrets stay local (12-Factor App pattern)
|
|
1606
|
+
- ✅ Onboarding: `cp .env.example .env` (fill in your tokens)
|
|
1607
|
+
- ✅ Type-safe configuration with validation
|
|
1608
|
+
|
|
1609
|
+
**Using ConfigManager**:
|
|
1610
|
+
|
|
1611
|
+
```typescript
|
|
1612
|
+
import { getConfigManager } from '../core/config/index.js';
|
|
1613
|
+
|
|
1614
|
+
// Read configuration
|
|
1615
|
+
const configManager = getConfigManager(projectRoot);
|
|
1616
|
+
const config = await configManager.read();
|
|
1617
|
+
|
|
1618
|
+
// Get specific value
|
|
1619
|
+
const domain = await configManager.get('issueTracker.domain');
|
|
1620
|
+
|
|
1621
|
+
// Update configuration
|
|
1622
|
+
await configManager.update({
|
|
1623
|
+
issueTracker: {
|
|
1624
|
+
provider: 'jira',
|
|
1625
|
+
domain: 'example.atlassian.net',
|
|
1626
|
+
strategy: 'project-per-team'
|
|
1627
|
+
}
|
|
1628
|
+
});
|
|
1629
|
+
|
|
1630
|
+
// Write entire config (validates before writing)
|
|
1631
|
+
await configManager.write(newConfig);
|
|
1632
|
+
|
|
1633
|
+
// Set specific value
|
|
1634
|
+
await configManager.set('sync.enabled', true);
|
|
1635
|
+
```
|
|
1636
|
+
|
|
1637
|
+
**Init flow separation** (Jira example):
|
|
1638
|
+
|
|
1639
|
+
```typescript
|
|
1640
|
+
// Step 1: Save secrets to .env (gitignored)
|
|
1641
|
+
const secretEnvVars = getJiraEnvVars(credentials); // ONLY tokens/emails
|
|
1642
|
+
saveCredentialsToEnv(projectPath, 'jira', secretEnvVars);
|
|
1643
|
+
|
|
1644
|
+
// Step 2: Save config to .specweave/config.json (committed)
|
|
1645
|
+
const configManager = getConfigManager(projectPath);
|
|
1646
|
+
const jiraConfig = getJiraConfig(credentials); // domain, strategy, projects
|
|
1647
|
+
await configManager.update(jiraConfig);
|
|
1648
|
+
|
|
1649
|
+
// Step 3: Generate .env.example for team onboarding
|
|
1650
|
+
generateEnvExample(projectPath, 'jira');
|
|
1651
|
+
```
|
|
1652
|
+
|
|
1653
|
+
**What goes where**:
|
|
1654
|
+
|
|
1655
|
+
| Data Type | Location | Example | Committed? |
|
|
1656
|
+
|-----------|----------|---------|------------|
|
|
1657
|
+
| API Tokens | `.env` | `JIRA_API_TOKEN=xyz` | ❌ Never |
|
|
1658
|
+
| Emails | `.env` | `JIRA_EMAIL=user@example.com` | ❌ Never |
|
|
1659
|
+
| Domains | `config.json` | `"domain": "example.atlassian.net"` | ✅ Yes |
|
|
1660
|
+
| Strategies | `config.json` | `"strategy": "project-per-team"` | ✅ Yes |
|
|
1661
|
+
| Project Keys | `config.json` | `"projects": [{"key": "PROJ1"}]` | ✅ Yes |
|
|
1662
|
+
| Sync Settings | `config.json` | `"includeStatus": true` | ✅ Yes |
|
|
1663
|
+
|
|
1664
|
+
**Validation**:
|
|
1665
|
+
|
|
1666
|
+
ConfigManager validates configuration before writing:
|
|
1667
|
+
|
|
1668
|
+
```typescript
|
|
1669
|
+
const result = configManager.validate(config);
|
|
1670
|
+
if (!result.valid) {
|
|
1671
|
+
console.error('Validation errors:', result.errors);
|
|
1672
|
+
// Example error:
|
|
1673
|
+
// {
|
|
1674
|
+
// path: 'issueTracker.provider',
|
|
1675
|
+
// message: 'Invalid provider. Must be one of: none, jira, github, ado',
|
|
1676
|
+
// value: 'invalid-provider'
|
|
1677
|
+
// }
|
|
1678
|
+
}
|
|
1679
|
+
```
|
|
1680
|
+
|
|
1681
|
+
**Migration Tool** (for existing projects):
|
|
1682
|
+
|
|
1683
|
+
If you have an existing project using the old .env-only format, use the migration tool:
|
|
1684
|
+
|
|
1685
|
+
```bash
|
|
1686
|
+
# Preview what will be migrated (dry run)
|
|
1687
|
+
node -e "require('./dist/src/cli/commands/migrate-config.js').migrateConfig({ dryRun: true })"
|
|
1688
|
+
|
|
1689
|
+
# Perform migration
|
|
1690
|
+
node -e "require('./dist/src/cli/commands/migrate-config.js').migrateConfig()"
|
|
1691
|
+
|
|
1692
|
+
# Force migration even if not needed
|
|
1693
|
+
node -e "require('./dist/src/cli/commands/migrate-config.js').migrateConfig({ force: true })"
|
|
1694
|
+
```
|
|
1695
|
+
|
|
1696
|
+
**What the migration tool does**:
|
|
1697
|
+
1. ✅ Analyzes `.env` file and classifies variables
|
|
1698
|
+
2. ✅ Creates backup: `.env.backup.TIMESTAMP`
|
|
1699
|
+
3. ✅ Updates `.env` (keeps only secrets)
|
|
1700
|
+
4. ✅ Creates/updates `.specweave/config.json` (adds config)
|
|
1701
|
+
5. ✅ Generates `.env.example` for team onboarding
|
|
1702
|
+
|
|
1703
|
+
**Classification logic**:
|
|
1704
|
+
- **Secrets** (stay in .env): Variables containing `token`, `api_token`, `pat`, `secret`, `key`, `password`, `credential`, `auth`, or email addresses
|
|
1705
|
+
- **Config** (move to config.json): Everything else (domains, strategies, project keys, etc.)
|
|
1706
|
+
|
|
1707
|
+
**See also**:
|
|
1708
|
+
- ADR-0050: Secrets vs Configuration Separation
|
|
1709
|
+
- `src/core/config/config-manager.ts` - ConfigManager implementation
|
|
1710
|
+
- `src/core/config/config-migrator.ts` - Migration tool implementation
|
|
1711
|
+
- `tests/unit/core/config/config-migrator.test.ts` - Usage examples
|
|
1712
|
+
|
|
1595
1713
|
---
|
|
1596
1714
|
|
|
1597
1715
|
## Troubleshooting
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migrate Config Command
|
|
3
|
+
*
|
|
4
|
+
* Migrates old .env-only configuration to split secrets/config format
|
|
5
|
+
*
|
|
6
|
+
* @module cli/commands/migrate-config
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Command options
|
|
10
|
+
*/
|
|
11
|
+
export interface MigrateConfigOptions {
|
|
12
|
+
dryRun?: boolean;
|
|
13
|
+
force?: boolean;
|
|
14
|
+
yes?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Migrate configuration from .env-only to split format
|
|
18
|
+
*
|
|
19
|
+
* @param options - Command options
|
|
20
|
+
*/
|
|
21
|
+
export declare function migrateConfig(options?: MigrateConfigOptions): Promise<void>;
|
|
22
|
+
//# sourceMappingURL=migrate-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate-config.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/migrate-config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2IrF"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migrate Config Command
|
|
3
|
+
*
|
|
4
|
+
* Migrates old .env-only configuration to split secrets/config format
|
|
5
|
+
*
|
|
6
|
+
* @module cli/commands/migrate-config
|
|
7
|
+
*/
|
|
8
|
+
import chalk from 'chalk';
|
|
9
|
+
import inquirer from 'inquirer';
|
|
10
|
+
import ora from 'ora';
|
|
11
|
+
import { ConfigMigrator } from '../../core/config/config-migrator.js';
|
|
12
|
+
/**
|
|
13
|
+
* Migrate configuration from .env-only to split format
|
|
14
|
+
*
|
|
15
|
+
* @param options - Command options
|
|
16
|
+
*/
|
|
17
|
+
export async function migrateConfig(options = {}) {
|
|
18
|
+
const { dryRun = false, force = false, yes = false } = options;
|
|
19
|
+
console.log(chalk.bold.cyan('\n🔄 SpecWeave Configuration Migration\n'));
|
|
20
|
+
console.log(chalk.gray('Migrating from .env-only to split secrets/config format\n'));
|
|
21
|
+
const migrator = new ConfigMigrator(process.cwd());
|
|
22
|
+
// Check if migration is needed
|
|
23
|
+
if (!force) {
|
|
24
|
+
const spinner = ora('Checking if migration is needed...').start();
|
|
25
|
+
const needed = await migrator.needsMigration();
|
|
26
|
+
if (!needed) {
|
|
27
|
+
spinner.succeed('Migration not needed');
|
|
28
|
+
console.log(chalk.green('\n✅ Your project already uses the split format!'));
|
|
29
|
+
console.log(chalk.gray(' Secrets are in .env, config is in .specweave/config.json\n'));
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
spinner.succeed('Migration needed - old format detected');
|
|
33
|
+
}
|
|
34
|
+
// Preview migration
|
|
35
|
+
console.log(chalk.bold('\n📋 Migration Preview\n'));
|
|
36
|
+
const spinner = ora('Analyzing .env file...').start();
|
|
37
|
+
let preview;
|
|
38
|
+
try {
|
|
39
|
+
preview = await migrator.preview();
|
|
40
|
+
spinner.succeed('Analysis complete');
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
spinner.fail('Analysis failed');
|
|
44
|
+
console.error(chalk.red(`\n❌ Error: ${error.message}\n`));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
// Display classification results
|
|
48
|
+
console.log(chalk.bold('\nClassification Results:'));
|
|
49
|
+
console.log(chalk.green(` Secrets: ${preview.secretsCount} variables`));
|
|
50
|
+
console.log(chalk.blue(` Config: ${preview.configCount} variables`));
|
|
51
|
+
if (preview.warnings.length > 0) {
|
|
52
|
+
console.log(chalk.yellow('\n⚠️ Warnings:'));
|
|
53
|
+
preview.warnings.forEach(w => console.log(chalk.yellow(` - ${w}`)));
|
|
54
|
+
}
|
|
55
|
+
// Show detailed breakdown
|
|
56
|
+
console.log(chalk.bold('\n📊 Detailed Breakdown:\n'));
|
|
57
|
+
const secretVars = preview.classified.filter(c => c.type === 'secret');
|
|
58
|
+
const configVars = preview.classified.filter(c => c.type === 'config');
|
|
59
|
+
if (secretVars.length > 0) {
|
|
60
|
+
console.log(chalk.green.bold(' Secrets (will stay in .env):'));
|
|
61
|
+
secretVars.forEach(v => {
|
|
62
|
+
const maskedValue = maskSecret(v.value);
|
|
63
|
+
console.log(chalk.gray(` ${v.key}=${maskedValue}`));
|
|
64
|
+
console.log(chalk.gray(` └─ ${v.reason}\n`));
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
if (configVars.length > 0) {
|
|
68
|
+
console.log(chalk.blue.bold(' Configuration (will move to config.json):'));
|
|
69
|
+
configVars.forEach(v => {
|
|
70
|
+
console.log(chalk.gray(` ${v.key}=${v.value}`));
|
|
71
|
+
console.log(chalk.gray(` └─ ${v.reason}\n`));
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
// Dry run mode - stop here
|
|
75
|
+
if (dryRun) {
|
|
76
|
+
console.log(chalk.yellow('\n🔍 Dry run mode - no changes made\n'));
|
|
77
|
+
console.log(chalk.gray('Run without --dry-run to perform migration\n'));
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
// Confirm migration
|
|
81
|
+
if (!yes) {
|
|
82
|
+
console.log(chalk.bold('\n❓ Migration Actions:\n'));
|
|
83
|
+
console.log(chalk.gray(' 1. Backup .env → .env.backup.TIMESTAMP'));
|
|
84
|
+
console.log(chalk.gray(' 2. Update .env (keep only secrets)'));
|
|
85
|
+
console.log(chalk.gray(' 3. Create/update .specweave/config.json (add config)'));
|
|
86
|
+
console.log(chalk.gray(' 4. Generate .env.example (team template)\n'));
|
|
87
|
+
const { confirm } = await inquirer.prompt([
|
|
88
|
+
{
|
|
89
|
+
type: 'confirm',
|
|
90
|
+
name: 'confirm',
|
|
91
|
+
message: 'Proceed with migration?',
|
|
92
|
+
default: false
|
|
93
|
+
}
|
|
94
|
+
]);
|
|
95
|
+
if (!confirm) {
|
|
96
|
+
console.log(chalk.yellow('\n⚠️ Migration cancelled\n'));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Perform migration
|
|
101
|
+
console.log(chalk.bold('\n🚀 Performing Migration...\n'));
|
|
102
|
+
const migrationSpinner = ora('Migrating configuration...').start();
|
|
103
|
+
let result;
|
|
104
|
+
try {
|
|
105
|
+
result = await migrator.migrate({ backup: true, force });
|
|
106
|
+
migrationSpinner.succeed('Migration complete');
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
migrationSpinner.fail('Migration failed');
|
|
110
|
+
console.error(chalk.red(`\n❌ Error: ${error.message}\n`));
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
// Display results
|
|
114
|
+
console.log(chalk.bold.green('\n✅ Migration Successful!\n'));
|
|
115
|
+
console.log(chalk.bold('Summary:'));
|
|
116
|
+
console.log(chalk.green(` ✓ ${result.secretsCount} secrets kept in .env`));
|
|
117
|
+
console.log(chalk.blue(` ✓ ${result.configCount} config items moved to config.json`));
|
|
118
|
+
if (result.backupPath) {
|
|
119
|
+
console.log(chalk.gray(` ✓ Backup created: ${result.backupPath}`));
|
|
120
|
+
}
|
|
121
|
+
console.log(chalk.gray(` ✓ .env.example generated\n`));
|
|
122
|
+
// Show next steps
|
|
123
|
+
console.log(chalk.bold('📝 Next Steps:\n'));
|
|
124
|
+
console.log(chalk.cyan(' 1. Review .specweave/config.json (commit to git)'));
|
|
125
|
+
console.log(chalk.cyan(' 2. Share .env.example with team (commit to git)'));
|
|
126
|
+
console.log(chalk.cyan(' 3. Team members: cp .env.example .env (fill in tokens)'));
|
|
127
|
+
console.log(chalk.cyan(' 4. Verify: specweave init . (should detect existing config)\n'));
|
|
128
|
+
console.log(chalk.bold('🎯 Benefits:\n'));
|
|
129
|
+
console.log(chalk.green(' ✓ Team shares configuration via git'));
|
|
130
|
+
console.log(chalk.green(' ✓ Secrets stay local (never committed)'));
|
|
131
|
+
console.log(chalk.green(' ✓ Type-safe configuration with validation'));
|
|
132
|
+
console.log(chalk.green(' ✓ Easy onboarding for new team members\n'));
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Mask secret value for display
|
|
136
|
+
*
|
|
137
|
+
* @param value - Secret value
|
|
138
|
+
* @returns Masked value
|
|
139
|
+
*/
|
|
140
|
+
function maskSecret(value) {
|
|
141
|
+
if (value.length <= 8) {
|
|
142
|
+
return '***';
|
|
143
|
+
}
|
|
144
|
+
const visible = 4;
|
|
145
|
+
const start = value.substring(0, visible);
|
|
146
|
+
const end = value.substring(value.length - visible);
|
|
147
|
+
return `${start}${'*'.repeat(value.length - visible * 2)}${end}`;
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=migrate-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate-config.js","sourceRoot":"","sources":["../../../../src/cli/commands/migrate-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/cli/helpers/issue-tracker/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,OAAO,KAAK,EAAoC,YAAY,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/cli/helpers/issue-tracker/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,OAAO,KAAK,EAAoC,YAAY,EAAE,MAAM,YAAY,CAAC;AA2CjF;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CA+R/E;AAihBD,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC"}
|
|
@@ -8,17 +8,17 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import chalk from 'chalk';
|
|
10
10
|
import inquirer from 'inquirer';
|
|
11
|
-
import ora from 'ora';
|
|
12
11
|
import fs from 'fs';
|
|
13
12
|
import path from 'path';
|
|
14
13
|
import { execSync } from 'child_process';
|
|
15
|
-
import { detectDefaultTracker, getTrackerDisplayName
|
|
14
|
+
import { detectDefaultTracker, getTrackerDisplayName } from './utils.js';
|
|
16
15
|
import { readEnvFile, writeEnvFile, createEnvFromTemplate, updateEnvVars, ensureEnvGitignored } from '../../../utils/env-file.js';
|
|
17
16
|
import { getLocaleManager } from '../../../core/i18n/locale-manager.js';
|
|
17
|
+
import { getConfigManager } from '../../../core/config/index.js';
|
|
18
18
|
// GitHub
|
|
19
19
|
import { checkExistingGitHubCredentials, promptGitHubCredentials, validateGitHubConnection, getGitHubEnvVars, showGitHubSetupComplete, showGitHubSetupSkipped } from './github.js';
|
|
20
20
|
// Jira
|
|
21
|
-
import { checkExistingJiraCredentials, promptJiraCredentials, validateJiraConnection, getJiraEnvVars, showJiraSetupComplete, showJiraSetupSkipped } from './jira.js';
|
|
21
|
+
import { checkExistingJiraCredentials, promptJiraCredentials, validateJiraConnection, getJiraEnvVars, getJiraConfig, showJiraSetupComplete, showJiraSetupSkipped } from './jira.js';
|
|
22
22
|
// Azure DevOps
|
|
23
23
|
import { checkExistingAzureDevOpsCredentials, promptAzureDevOpsCredentials, validateAzureDevOpsConnection, getAzureDevOpsEnvVars, showAzureDevOpsSetupComplete, showAzureDevOpsSetupSkipped } from './ado.js';
|
|
24
24
|
/**
|
|
@@ -183,8 +183,7 @@ export async function setupIssueTracker(options) {
|
|
|
183
183
|
if (tracker === 'jira') {
|
|
184
184
|
await validateResources(tracker, credentials, projectPath);
|
|
185
185
|
}
|
|
186
|
-
//
|
|
187
|
-
await installPlugin(tracker, language);
|
|
186
|
+
// Show setup complete message (plugins managed via marketplace)
|
|
188
187
|
showSetupComplete(tracker, language);
|
|
189
188
|
return true;
|
|
190
189
|
}
|
|
@@ -273,9 +272,7 @@ export async function setupIssueTracker(options) {
|
|
|
273
272
|
if (tracker === 'jira' || tracker === 'ado') {
|
|
274
273
|
await validateResources(tracker, credentials, projectPath);
|
|
275
274
|
}
|
|
276
|
-
// Step 6:
|
|
277
|
-
await installPlugin(tracker, language);
|
|
278
|
-
// Step 7: Show success message
|
|
275
|
+
// Step 6: Show success message (plugins managed via marketplace)
|
|
279
276
|
showSetupComplete(tracker, language);
|
|
280
277
|
return true;
|
|
281
278
|
}
|
|
@@ -373,7 +370,85 @@ async function validateResources(tracker, credentials, projectPath) {
|
|
|
373
370
|
}
|
|
374
371
|
}
|
|
375
372
|
/**
|
|
376
|
-
*
|
|
373
|
+
* Generate .env.example template for team onboarding
|
|
374
|
+
*
|
|
375
|
+
* Creates a template file showing required environment variables
|
|
376
|
+
* with placeholder values and setup instructions
|
|
377
|
+
*/
|
|
378
|
+
function generateEnvExample(projectPath, tracker) {
|
|
379
|
+
const examplePath = path.join(projectPath, '.env.example');
|
|
380
|
+
let content = `# SpecWeave Environment Variables
|
|
381
|
+
#
|
|
382
|
+
# IMPORTANT: Copy this file to .env and replace placeholder values with your actual credentials
|
|
383
|
+
# NEVER commit .env to git! It's already in .gitignore
|
|
384
|
+
#
|
|
385
|
+
# Setup Instructions:
|
|
386
|
+
# 1. Copy: cp .env.example .env
|
|
387
|
+
# 2. Replace placeholder values below with your actual credentials
|
|
388
|
+
# 3. Run: specweave init . (to validate credentials)
|
|
389
|
+
|
|
390
|
+
`;
|
|
391
|
+
if (tracker === 'jira') {
|
|
392
|
+
content += `# ==========================================
|
|
393
|
+
# Jira Credentials (REQUIRED)
|
|
394
|
+
# ==========================================
|
|
395
|
+
# Get your Jira API token from:
|
|
396
|
+
# Cloud: https://id.atlassian.com/manage-profile/security/api-tokens
|
|
397
|
+
# Server: Your Jira instance → Settings → Personal Access Tokens
|
|
398
|
+
|
|
399
|
+
JIRA_API_TOKEN=your_jira_api_token_here
|
|
400
|
+
JIRA_EMAIL=your_email@company.com
|
|
401
|
+
|
|
402
|
+
# NOTE: Domain, strategy, and projects are now in .specweave/config.json
|
|
403
|
+
# (This makes them shareable across the team via git)
|
|
404
|
+
`;
|
|
405
|
+
}
|
|
406
|
+
else if (tracker === 'github') {
|
|
407
|
+
content += `# ==========================================
|
|
408
|
+
# GitHub Credentials (REQUIRED)
|
|
409
|
+
# ==========================================
|
|
410
|
+
# Get your GitHub token from:
|
|
411
|
+
# https://github.com/settings/tokens
|
|
412
|
+
# Required scopes: repo, read:org
|
|
413
|
+
|
|
414
|
+
GITHUB_TOKEN=your_github_token_here
|
|
415
|
+
`;
|
|
416
|
+
}
|
|
417
|
+
else if (tracker === 'ado') {
|
|
418
|
+
content += `# ==========================================
|
|
419
|
+
# Azure DevOps Credentials (REQUIRED)
|
|
420
|
+
# ==========================================
|
|
421
|
+
# Get your PAT from:
|
|
422
|
+
# https://dev.azure.com/YOUR_ORG/_usersSettings/tokens
|
|
423
|
+
|
|
424
|
+
ADO_PAT=your_ado_pat_here
|
|
425
|
+
`;
|
|
426
|
+
}
|
|
427
|
+
content += `
|
|
428
|
+
# ==========================================
|
|
429
|
+
# Optional: Additional Integrations
|
|
430
|
+
# ==========================================
|
|
431
|
+
# Uncomment and configure if you use multiple tools:
|
|
432
|
+
|
|
433
|
+
# GitHub (if using with Jira)
|
|
434
|
+
# GITHUB_TOKEN=your_github_token_here
|
|
435
|
+
|
|
436
|
+
# Bitbucket
|
|
437
|
+
# BITBUCKET_TOKEN=your_bitbucket_token_here
|
|
438
|
+
|
|
439
|
+
# GitLab
|
|
440
|
+
# GITLAB_TOKEN=your_gitlab_token_here
|
|
441
|
+
`;
|
|
442
|
+
fs.writeFileSync(examplePath, content, 'utf-8');
|
|
443
|
+
console.log(chalk.green('✓ Generated .env.example (commit this to git!)'));
|
|
444
|
+
console.log(chalk.gray(' Team members can copy it to .env and add their credentials'));
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Save credentials to .env file AND configuration to config.json
|
|
448
|
+
*
|
|
449
|
+
* NEW (v0.23.0): Implements ADR-0050 secrets/config separation
|
|
450
|
+
* - Secrets (tokens, emails) → .env (gitignored)
|
|
451
|
+
* - Configuration (domains, strategies, projects) → config.json (committed)
|
|
377
452
|
*/
|
|
378
453
|
async function saveCredentials(projectPath, tracker, credentials) {
|
|
379
454
|
// Read existing .env or create from template
|
|
@@ -381,14 +456,14 @@ async function saveCredentials(projectPath, tracker, credentials) {
|
|
|
381
456
|
if (!envContent) {
|
|
382
457
|
envContent = createEnvFromTemplate(projectPath);
|
|
383
458
|
}
|
|
384
|
-
// Get tracker-specific env vars
|
|
459
|
+
// Get tracker-specific env vars (ONLY secrets)
|
|
385
460
|
let envVars = [];
|
|
386
461
|
switch (tracker) {
|
|
387
462
|
case 'github':
|
|
388
463
|
envVars = getGitHubEnvVars(credentials);
|
|
389
464
|
break;
|
|
390
465
|
case 'jira':
|
|
391
|
-
envVars = getJiraEnvVars(credentials);
|
|
466
|
+
envVars = getJiraEnvVars(credentials); // NOW returns ONLY secrets
|
|
392
467
|
break;
|
|
393
468
|
case 'ado':
|
|
394
469
|
envVars = getAzureDevOpsEnvVars(credentials);
|
|
@@ -401,6 +476,18 @@ async function saveCredentials(projectPath, tracker, credentials) {
|
|
|
401
476
|
// Ensure .env is gitignored
|
|
402
477
|
ensureEnvGitignored(projectPath);
|
|
403
478
|
console.log(chalk.green('✓ Credentials saved to .env (gitignored)'));
|
|
479
|
+
// Save non-sensitive configuration to config.json
|
|
480
|
+
if (tracker === 'jira') {
|
|
481
|
+
const configManager = getConfigManager(projectPath);
|
|
482
|
+
const jiraConfig = getJiraConfig(credentials);
|
|
483
|
+
await configManager.update(jiraConfig);
|
|
484
|
+
console.log(chalk.green('✓ Configuration saved to .specweave/config.json'));
|
|
485
|
+
console.log(chalk.gray(` Domain: ${jiraConfig.issueTracker.domain}`));
|
|
486
|
+
console.log(chalk.gray(` Strategy: ${jiraConfig.issueTracker.strategy}`));
|
|
487
|
+
console.log(chalk.gray(` Projects: ${jiraConfig.issueTracker.projects?.map(p => p.key).join(', ')}`));
|
|
488
|
+
}
|
|
489
|
+
// Generate .env.example for team onboarding
|
|
490
|
+
generateEnvExample(projectPath, tracker);
|
|
404
491
|
}
|
|
405
492
|
/**
|
|
406
493
|
* Write sync config to .specweave/config.json
|
|
@@ -411,20 +498,9 @@ async function saveCredentials(projectPath, tracker, credentials) {
|
|
|
411
498
|
* NEW (v0.21.0): Includes sync settings (status sync, task checkboxes, auto-labels)
|
|
412
499
|
*/
|
|
413
500
|
async function writeSyncConfig(projectPath, tracker, credentials, syncSettings, syncPermissions, repositoryProfiles, monorepoProjects) {
|
|
414
|
-
const
|
|
415
|
-
// Read existing config
|
|
416
|
-
|
|
417
|
-
project: {
|
|
418
|
-
name: path.basename(projectPath),
|
|
419
|
-
version: '0.1.0'
|
|
420
|
-
},
|
|
421
|
-
adapters: {
|
|
422
|
-
default: 'claude'
|
|
423
|
-
}
|
|
424
|
-
};
|
|
425
|
-
if (fs.existsSync(configPath)) {
|
|
426
|
-
config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
427
|
-
}
|
|
501
|
+
const configManager = getConfigManager(projectPath);
|
|
502
|
+
// Read existing config
|
|
503
|
+
const config = await configManager.read();
|
|
428
504
|
// Add hooks configuration (enables auto-sync!)
|
|
429
505
|
config.hooks = {
|
|
430
506
|
post_task_completion: {
|
|
@@ -516,6 +592,8 @@ async function writeSyncConfig(projectPath, tracker, credentials, syncSettings,
|
|
|
516
592
|
const defaultProfile = repositoryProfiles.find(p => p.isDefault) || repositoryProfiles[0];
|
|
517
593
|
config.sync = {
|
|
518
594
|
enabled: true,
|
|
595
|
+
direction: 'bidirectional',
|
|
596
|
+
autoSync: false,
|
|
519
597
|
provider: tracker, // NEW: Exclusive provider
|
|
520
598
|
includeStatus: syncSettings.includeStatus, // NEW: Status sync toggle
|
|
521
599
|
autoApplyLabels: syncSettings.autoApplyLabels, // NEW: Auto-labeling
|
|
@@ -548,6 +626,8 @@ async function writeSyncConfig(projectPath, tracker, credentials, syncSettings,
|
|
|
548
626
|
};
|
|
549
627
|
config.sync = {
|
|
550
628
|
enabled: true,
|
|
629
|
+
direction: 'bidirectional',
|
|
630
|
+
autoSync: false,
|
|
551
631
|
provider: tracker, // NEW: Exclusive provider
|
|
552
632
|
includeStatus: syncSettings.includeStatus, // NEW: Status sync toggle
|
|
553
633
|
autoApplyLabels: syncSettings.autoApplyLabels, // NEW: Auto-labeling
|
|
@@ -579,6 +659,8 @@ async function writeSyncConfig(projectPath, tracker, credentials, syncSettings,
|
|
|
579
659
|
};
|
|
580
660
|
config.sync = {
|
|
581
661
|
enabled: true,
|
|
662
|
+
direction: 'bidirectional',
|
|
663
|
+
autoSync: false,
|
|
582
664
|
provider: tracker, // NEW: Exclusive provider
|
|
583
665
|
includeStatus: syncSettings.includeStatus, // NEW: Status sync toggle
|
|
584
666
|
autoApplyLabels: syncSettings.autoApplyLabels, // NEW: Auto-labeling
|
|
@@ -606,6 +688,8 @@ async function writeSyncConfig(projectPath, tracker, credentials, syncSettings,
|
|
|
606
688
|
};
|
|
607
689
|
config.sync = {
|
|
608
690
|
enabled: true,
|
|
691
|
+
direction: 'bidirectional',
|
|
692
|
+
autoSync: false,
|
|
609
693
|
provider: tracker, // NEW: Exclusive provider
|
|
610
694
|
includeStatus: syncSettings.includeStatus, // NEW: Status sync toggle
|
|
611
695
|
autoApplyLabels: syncSettings.autoApplyLabels, // NEW: Auto-labeling
|
|
@@ -618,8 +702,8 @@ async function writeSyncConfig(projectPath, tracker, credentials, syncSettings,
|
|
|
618
702
|
profiles
|
|
619
703
|
};
|
|
620
704
|
}
|
|
621
|
-
// Write config
|
|
622
|
-
|
|
705
|
+
// Write config using ConfigManager
|
|
706
|
+
await configManager.write(config);
|
|
623
707
|
console.log(chalk.green(`✓ Sync config written to .specweave/config.json`));
|
|
624
708
|
console.log(chalk.gray(` Provider: ${tracker}`));
|
|
625
709
|
console.log(chalk.gray(` Auto-sync: enabled`));
|
|
@@ -627,39 +711,7 @@ async function writeSyncConfig(projectPath, tracker, credentials, syncSettings,
|
|
|
627
711
|
console.log(chalk.gray(` Auto-labeling: ${syncSettings.autoApplyLabels ? 'enabled' : 'disabled'}`));
|
|
628
712
|
console.log(chalk.gray(` Hooks: post_task_completion, post_increment_planning`));
|
|
629
713
|
}
|
|
630
|
-
|
|
631
|
-
* Install tracker plugin
|
|
632
|
-
*/
|
|
633
|
-
async function installPlugin(tracker, language) {
|
|
634
|
-
const spinner = ora(`Installing ${getTrackerDisplayName(tracker)} plugin...`).start();
|
|
635
|
-
// Check if Claude CLI is available
|
|
636
|
-
if (!isClaudeCliAvailable()) {
|
|
637
|
-
spinner.warn('Claude CLI not found');
|
|
638
|
-
console.log(chalk.yellow('\n📦 Manual plugin installation required:'));
|
|
639
|
-
console.log(chalk.white(` /plugin install specweave-${tracker}\n`));
|
|
640
|
-
return;
|
|
641
|
-
}
|
|
642
|
-
// Install plugin
|
|
643
|
-
const result = installTrackerPlugin(tracker);
|
|
644
|
-
if (result.success) {
|
|
645
|
-
if (result.alreadyInstalled) {
|
|
646
|
-
spinner.succeed(`${getTrackerDisplayName(tracker)} plugin already installed`);
|
|
647
|
-
}
|
|
648
|
-
else {
|
|
649
|
-
spinner.succeed(`${getTrackerDisplayName(tracker)} plugin installed`);
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
else {
|
|
653
|
-
spinner.fail(`Could not auto-install plugin`);
|
|
654
|
-
console.log(chalk.yellow('\n📦 Manual plugin installation:'));
|
|
655
|
-
console.log(chalk.white(` /plugin install specweave-${tracker}`));
|
|
656
|
-
// Show error details in DEBUG mode
|
|
657
|
-
if (process.env.DEBUG && result.error) {
|
|
658
|
-
console.log(chalk.gray(` Error: ${result.error}`));
|
|
659
|
-
}
|
|
660
|
-
console.log('');
|
|
661
|
-
}
|
|
662
|
-
}
|
|
714
|
+
// Removed installPlugin() function - plugins are managed via marketplace, not during init
|
|
663
715
|
/**
|
|
664
716
|
* Show setup complete message
|
|
665
717
|
*/
|