specweave 0.24.0 → 0.24.6
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-plugin/marketplace.json +55 -0
- package/CLAUDE.md +42 -0
- package/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +80 -41
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/types.d.ts +1 -1
- package/dist/src/cli/helpers/issue-tracker/types.d.ts.map +1 -1
- package/dist/src/config/types.d.ts +24 -24
- package/dist/src/core/config/types.d.ts +25 -0
- package/dist/src/core/config/types.d.ts.map +1 -1
- package/dist/src/core/config/types.js +6 -0
- package/dist/src/core/config/types.js.map +1 -1
- package/dist/src/core/repo-structure/repo-bulk-discovery.d.ts +33 -0
- package/dist/src/core/repo-structure/repo-bulk-discovery.d.ts.map +1 -0
- package/dist/src/core/repo-structure/repo-bulk-discovery.js +275 -0
- package/dist/src/core/repo-structure/repo-bulk-discovery.js.map +1 -0
- package/dist/src/core/repo-structure/repo-structure-manager.d.ts +9 -0
- package/dist/src/core/repo-structure/repo-structure-manager.d.ts.map +1 -1
- package/dist/src/core/repo-structure/repo-structure-manager.js +255 -87
- package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
- package/dist/src/init/architecture/types.d.ts +6 -6
- package/dist/src/utils/plugin-validator.d.ts.map +1 -1
- package/dist/src/utils/plugin-validator.js +15 -14
- package/dist/src/utils/plugin-validator.js.map +1 -1
- package/package.json +4 -4
- package/plugins/specweave/.claude-plugin/plugin.json +4 -4
- package/plugins/specweave/agents/pm/AGENT.md +2 -0
- package/plugins/specweave/commands/specweave-do.md +0 -47
- package/plugins/specweave/commands/specweave-increment.md +0 -82
- package/plugins/specweave/commands/specweave-next.md +0 -47
- package/plugins/specweave/hooks/post-task-completion.sh +67 -6
- package/plugins/specweave/hooks/pre-edit-spec.sh +11 -0
- package/plugins/specweave/hooks/pre-task-completion.sh +69 -2
- package/plugins/specweave/hooks/pre-write-spec.sh +11 -0
- package/plugins/specweave/skills/increment-planner/SKILL.md +124 -4
- package/plugins/specweave-frontend/agents/frontend-architect/AGENT.md +21 -0
- package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +150 -0
- package/plugins/specweave-payments/commands/stripe-setup.md +931 -0
- package/plugins/specweave-payments/commands/subscription-flow.md +1193 -0
- package/plugins/specweave-payments/commands/subscription-manage.md +386 -0
- package/plugins/specweave-payments/commands/webhook-setup.md +295 -0
- package/plugins/specweave-testing/agents/qa-engineer/AGENT.md +21 -0
|
@@ -128,6 +128,61 @@
|
|
|
128
128
|
"email": "anton.abyzov@gmail.com"
|
|
129
129
|
}
|
|
130
130
|
},
|
|
131
|
+
{
|
|
132
|
+
"name": "specweave-backend",
|
|
133
|
+
"description": "Backend development - Node.js, Python, .NET, REST APIs, database design, microservices architecture",
|
|
134
|
+
"source": "./plugins/specweave-backend",
|
|
135
|
+
"category": "development",
|
|
136
|
+
"version": "1.0.0",
|
|
137
|
+
"author": {
|
|
138
|
+
"name": "Anton Abyzov",
|
|
139
|
+
"email": "anton.abyzov@gmail.com"
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"name": "specweave-confluent",
|
|
144
|
+
"description": "Confluent Cloud integration - Schema Registry, ksqlDB, Kafka Connect, Flink, stream processing, enterprise Kafka features",
|
|
145
|
+
"source": "./plugins/specweave-confluent",
|
|
146
|
+
"category": "development",
|
|
147
|
+
"version": "1.0.0",
|
|
148
|
+
"author": {
|
|
149
|
+
"name": "Anton Abyzov",
|
|
150
|
+
"email": "anton.abyzov@gmail.com"
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"name": "specweave-kubernetes",
|
|
155
|
+
"description": "Kubernetes deployment - K8s manifests, Helm charts, GitOps, cluster management, container orchestration",
|
|
156
|
+
"source": "./plugins/specweave-kubernetes",
|
|
157
|
+
"category": "development",
|
|
158
|
+
"version": "1.0.0",
|
|
159
|
+
"author": {
|
|
160
|
+
"name": "Anton Abyzov",
|
|
161
|
+
"email": "anton.abyzov@gmail.com"
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"name": "specweave-mobile",
|
|
166
|
+
"description": "React Native & Expo mobile development - environment setup, debugging, performance optimization, native modules, testing",
|
|
167
|
+
"source": "./plugins/specweave-mobile",
|
|
168
|
+
"category": "development",
|
|
169
|
+
"version": "1.0.0",
|
|
170
|
+
"author": {
|
|
171
|
+
"name": "Anton Abyzov",
|
|
172
|
+
"email": "anton.abyzov@gmail.com"
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"name": "specweave-payments",
|
|
177
|
+
"description": "Payment processing - Stripe, PayPal, billing, PCI compliance, subscription management, payment gateways",
|
|
178
|
+
"source": "./plugins/specweave-payments",
|
|
179
|
+
"category": "development",
|
|
180
|
+
"version": "1.0.0",
|
|
181
|
+
"author": {
|
|
182
|
+
"name": "Anton Abyzov",
|
|
183
|
+
"email": "anton.abyzov@gmail.com"
|
|
184
|
+
}
|
|
185
|
+
},
|
|
131
186
|
{
|
|
132
187
|
"name": "specweave-frontend",
|
|
133
188
|
"description": "Frontend development - React, Next.js, component generation, design systems, UI scaffolding",
|
package/CLAUDE.md
CHANGED
|
@@ -725,6 +725,48 @@ npm run rebuild
|
|
|
725
725
|
- ADR-0060 (Three-tier optimization architecture)
|
|
726
726
|
- `.specweave/increments/0050-*/reports/hook-crash-analysis.md` (Incident analysis)
|
|
727
727
|
|
|
728
|
+
### Active Increment Filtering (v0.24.4 - ARCHITECTURAL FIX)
|
|
729
|
+
|
|
730
|
+
**Critical architectural change**: Hooks now **ONLY** process active increments.
|
|
731
|
+
|
|
732
|
+
**Problem**: The old logic used `ls -td` (time-based) which:
|
|
733
|
+
- Processed 50+ increments on every TodoWrite
|
|
734
|
+
- Could pick completed increments if recently modified
|
|
735
|
+
- Caused infinite loops when hitting bad AC data
|
|
736
|
+
- Wasted 90%+ of hook overhead on completed work
|
|
737
|
+
|
|
738
|
+
**Solution**: State-based filtering (`.specweave/state/active-increment.json`)
|
|
739
|
+
|
|
740
|
+
```bash
|
|
741
|
+
# NEW: Read active increments from state file
|
|
742
|
+
mapfile -t ACTIVE_INCREMENTS < <(jq -r '.ids[]' "$ACTIVE_STATE_FILE")
|
|
743
|
+
|
|
744
|
+
# Process ONLY active increments
|
|
745
|
+
for CURRENT_INCREMENT in "${ACTIVE_INCREMENTS[@]}"; do
|
|
746
|
+
# Safety: Skip if completed/abandoned/archived
|
|
747
|
+
if [[ "$STATUS" == "completed" ]] || [[ "$STATUS" == "abandoned" ]]; then
|
|
748
|
+
continue
|
|
749
|
+
fi
|
|
750
|
+
|
|
751
|
+
# Process (tasks.md, AC sync, living docs, etc.)
|
|
752
|
+
done
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
**Impact**:
|
|
756
|
+
- ✅ 95% reduction in hook overhead (50+ → 1-2 increments)
|
|
757
|
+
- ✅ Zero risk of infinite loops (completed increments never touched)
|
|
758
|
+
- ✅ Clean architecture (source of truth: state file)
|
|
759
|
+
- ✅ Multi-increment support (processes array)
|
|
760
|
+
|
|
761
|
+
**Fail-safe defaults**:
|
|
762
|
+
- No state file → skip all work
|
|
763
|
+
- Empty array → skip all work (normal when no active increments)
|
|
764
|
+
- Missing directory → skip increment
|
|
765
|
+
- Archived → skip increment
|
|
766
|
+
- Completed/abandoned status → skip increment
|
|
767
|
+
|
|
768
|
+
**See**: `.specweave/increments/0050-*/reports/ARCHITECTURAL-FIX-ACTIVE-INCREMENT-FILTERING.md`
|
|
769
|
+
|
|
728
770
|
---
|
|
729
771
|
|
|
730
772
|
## Development Workflow
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,MAAM,EAAiB,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,MAAM,EAAiB,MAAM,uBAAuB,CAAC;AAiB9D,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;IAChB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AA8ID,wBAAsB,WAAW,CAC/B,WAAW,CAAC,EAAE,MAAM,EACpB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,IAAI,CAAC,CAy2Cf"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import fs from 'fs-extra';
|
|
1
|
+
import fs from 'fs-extra'; // legacy fs-extra
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
import os from 'os';
|
|
4
4
|
import chalk from 'chalk';
|
|
@@ -15,6 +15,7 @@ import { getLocaleManager } from '../../core/i18n/locale-manager.js';
|
|
|
15
15
|
import { consoleLogger } from '../../utils/logger.js';
|
|
16
16
|
import { generateInitialIncrement } from '../helpers/init/initial-increment-generator.js';
|
|
17
17
|
import { ImportCoordinator } from '../../importers/import-coordinator.js';
|
|
18
|
+
import { StatusLineUpdater } from '../../core/status-line/status-line-updater.js';
|
|
18
19
|
import { ItemConverter } from '../../importers/item-converter.js';
|
|
19
20
|
import { loadImportConfig } from '../../config/import-config.js';
|
|
20
21
|
const __dirname = getDirname(import.meta.url);
|
|
@@ -1082,6 +1083,8 @@ export async function initCommand(projectName, options = {}) {
|
|
|
1082
1083
|
// Detect existing git remote
|
|
1083
1084
|
const gitRemoteDetection = detectGitHubRemote(targetDir);
|
|
1084
1085
|
let repositoryHosting = 'local';
|
|
1086
|
+
let isMultiRepo = false;
|
|
1087
|
+
let repoSelectionConfig = null;
|
|
1085
1088
|
if (!isCI) {
|
|
1086
1089
|
const { hosting } = await inquirer.prompt([{
|
|
1087
1090
|
type: 'list',
|
|
@@ -1089,8 +1092,12 @@ export async function initCommand(projectName, options = {}) {
|
|
|
1089
1092
|
message: 'How do you host your repository?',
|
|
1090
1093
|
choices: [
|
|
1091
1094
|
{
|
|
1092
|
-
name: `🐙 GitHub ${gitRemoteDetection ? '(detected)' : '
|
|
1093
|
-
value: 'github'
|
|
1095
|
+
name: `🐙 GitHub - Single repository ${gitRemoteDetection ? '(detected)' : ''}`,
|
|
1096
|
+
value: 'github-single'
|
|
1097
|
+
},
|
|
1098
|
+
{
|
|
1099
|
+
name: '🐙 GitHub - Multiple repositories (microservices, monorepo)',
|
|
1100
|
+
value: 'github-multi'
|
|
1094
1101
|
},
|
|
1095
1102
|
{
|
|
1096
1103
|
name: '💻 Local git only (no remote sync)',
|
|
@@ -1101,9 +1108,17 @@ export async function initCommand(projectName, options = {}) {
|
|
|
1101
1108
|
value: 'other'
|
|
1102
1109
|
}
|
|
1103
1110
|
],
|
|
1104
|
-
default: gitRemoteDetection ? 'github' : 'local'
|
|
1111
|
+
default: gitRemoteDetection ? 'github-single' : 'local'
|
|
1105
1112
|
}]);
|
|
1106
1113
|
repositoryHosting = hosting;
|
|
1114
|
+
// Normalize for backwards compatibility
|
|
1115
|
+
if (hosting === 'github-single') {
|
|
1116
|
+
repositoryHosting = 'github';
|
|
1117
|
+
}
|
|
1118
|
+
else if (hosting === 'github-multi') {
|
|
1119
|
+
repositoryHosting = 'github';
|
|
1120
|
+
isMultiRepo = true;
|
|
1121
|
+
}
|
|
1107
1122
|
// Show info for non-GitHub choices
|
|
1108
1123
|
if (hosting === 'other') {
|
|
1109
1124
|
console.log('');
|
|
@@ -1377,6 +1392,18 @@ export async function initCommand(projectName, options = {}) {
|
|
|
1377
1392
|
console.log(chalk.green(` ✔ Created initial increment: ${incrementId}`));
|
|
1378
1393
|
console.log(chalk.gray(' ✔ Status: ACTIVE (ready to work)'));
|
|
1379
1394
|
console.log(chalk.gray(' ✔ Files: spec.md, plan.md, tasks.md, metadata.json'));
|
|
1395
|
+
// Initialize status line cache for the new increment
|
|
1396
|
+
try {
|
|
1397
|
+
const statusLineUpdater = new StatusLineUpdater(targetDir);
|
|
1398
|
+
await statusLineUpdater.update();
|
|
1399
|
+
console.log(chalk.gray(' ✔ Status line initialized'));
|
|
1400
|
+
}
|
|
1401
|
+
catch (statusLineError) {
|
|
1402
|
+
// Non-critical: Status line will be created on first task completion
|
|
1403
|
+
if (process.env.DEBUG) {
|
|
1404
|
+
console.log(chalk.gray(` ⚠️ Status line init skipped: ${statusLineError instanceof Error ? statusLineError.message : String(statusLineError)}`));
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1380
1407
|
console.log('');
|
|
1381
1408
|
console.log(chalk.yellow(' 💡 TIP: Delete this increment and create your first real feature:'));
|
|
1382
1409
|
console.log(chalk.gray(' rm -rf .specweave/increments/0001-project-setup'));
|
|
@@ -1560,49 +1587,61 @@ async function promptAndRunExternalImport(targetDir, isCI) {
|
|
|
1560
1587
|
platforms: []
|
|
1561
1588
|
};
|
|
1562
1589
|
}
|
|
1563
|
-
// US-011: Multi-Repo
|
|
1590
|
+
// US-011: Multi-Repo Import
|
|
1591
|
+
// NOTE: This is a separate function scope, so we need our own repoSelectionConfig variable
|
|
1564
1592
|
let repoSelectionConfig = null;
|
|
1565
1593
|
if (githubRemote && process.env.GITHUB_TOKEN) {
|
|
1566
|
-
|
|
1567
|
-
{
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1594
|
+
try {
|
|
1595
|
+
const { useMultiRepo } = await inquirer.prompt([
|
|
1596
|
+
{
|
|
1597
|
+
type: 'confirm',
|
|
1598
|
+
name: 'useMultiRepo',
|
|
1599
|
+
message: 'Do you want to import from multiple repositories?',
|
|
1600
|
+
default: false
|
|
1601
|
+
}
|
|
1602
|
+
]);
|
|
1603
|
+
if (useMultiRepo) {
|
|
1604
|
+
try {
|
|
1605
|
+
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
|
|
1606
|
+
repoSelectionConfig = await selectRepositories(octokit, process.env.GITHUB_TOKEN);
|
|
1607
|
+
if (repoSelectionConfig) {
|
|
1608
|
+
try {
|
|
1609
|
+
const configPath = path.join(targetDir, '.specweave', 'config.json');
|
|
1610
|
+
let config = {};
|
|
1611
|
+
if (fs.existsSync(configPath)) {
|
|
1612
|
+
config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
1613
|
+
}
|
|
1614
|
+
if (!config.github) {
|
|
1615
|
+
config.github = {};
|
|
1616
|
+
}
|
|
1617
|
+
config.github.repositories = repoSelectionConfig.repositories;
|
|
1618
|
+
config.github.selectionStrategy = repoSelectionConfig.selectionStrategy;
|
|
1619
|
+
if (repoSelectionConfig.pattern) {
|
|
1620
|
+
config.github.pattern = repoSelectionConfig.pattern;
|
|
1621
|
+
}
|
|
1622
|
+
if (repoSelectionConfig.organizationName) {
|
|
1623
|
+
config.github.organizationName = repoSelectionConfig.organizationName;
|
|
1624
|
+
}
|
|
1625
|
+
fs.ensureDirSync(path.dirname(configPath));
|
|
1626
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
1627
|
+
}
|
|
1628
|
+
catch {
|
|
1629
|
+
// Silent - config save is not critical
|
|
1630
|
+
}
|
|
1595
1631
|
}
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1632
|
+
}
|
|
1633
|
+
catch {
|
|
1634
|
+
// Silent - continue with single repo
|
|
1599
1635
|
}
|
|
1600
1636
|
}
|
|
1601
|
-
catch (error) {
|
|
1602
|
-
console.error(chalk.yellow(`⚠️ Failed to select repositories: ${error instanceof Error ? error.message : String(error)}`));
|
|
1603
|
-
console.log(chalk.gray('Continuing with single repository import...\n'));
|
|
1604
|
-
}
|
|
1605
1637
|
}
|
|
1638
|
+
catch {
|
|
1639
|
+
// Silent - skip multi-repo prompt
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
else if (repoSelectionConfig) {
|
|
1643
|
+
// User already configured multi-repo in hosting section - reuse it!
|
|
1644
|
+
console.log(chalk.gray(`✓ Using multi-repository configuration from hosting setup\n`));
|
|
1606
1645
|
}
|
|
1607
1646
|
// Map config timeRangeMonths to closest prompt option
|
|
1608
1647
|
let defaultTimeRange = 3; // Default to 3 months
|