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.
Files changed (42) hide show
  1. package/.claude-plugin/marketplace.json +55 -0
  2. package/CLAUDE.md +42 -0
  3. package/dist/src/cli/commands/init.d.ts.map +1 -1
  4. package/dist/src/cli/commands/init.js +80 -41
  5. package/dist/src/cli/commands/init.js.map +1 -1
  6. package/dist/src/cli/helpers/issue-tracker/types.d.ts +1 -1
  7. package/dist/src/cli/helpers/issue-tracker/types.d.ts.map +1 -1
  8. package/dist/src/config/types.d.ts +24 -24
  9. package/dist/src/core/config/types.d.ts +25 -0
  10. package/dist/src/core/config/types.d.ts.map +1 -1
  11. package/dist/src/core/config/types.js +6 -0
  12. package/dist/src/core/config/types.js.map +1 -1
  13. package/dist/src/core/repo-structure/repo-bulk-discovery.d.ts +33 -0
  14. package/dist/src/core/repo-structure/repo-bulk-discovery.d.ts.map +1 -0
  15. package/dist/src/core/repo-structure/repo-bulk-discovery.js +275 -0
  16. package/dist/src/core/repo-structure/repo-bulk-discovery.js.map +1 -0
  17. package/dist/src/core/repo-structure/repo-structure-manager.d.ts +9 -0
  18. package/dist/src/core/repo-structure/repo-structure-manager.d.ts.map +1 -1
  19. package/dist/src/core/repo-structure/repo-structure-manager.js +255 -87
  20. package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
  21. package/dist/src/init/architecture/types.d.ts +6 -6
  22. package/dist/src/utils/plugin-validator.d.ts.map +1 -1
  23. package/dist/src/utils/plugin-validator.js +15 -14
  24. package/dist/src/utils/plugin-validator.js.map +1 -1
  25. package/package.json +4 -4
  26. package/plugins/specweave/.claude-plugin/plugin.json +4 -4
  27. package/plugins/specweave/agents/pm/AGENT.md +2 -0
  28. package/plugins/specweave/commands/specweave-do.md +0 -47
  29. package/plugins/specweave/commands/specweave-increment.md +0 -82
  30. package/plugins/specweave/commands/specweave-next.md +0 -47
  31. package/plugins/specweave/hooks/post-task-completion.sh +67 -6
  32. package/plugins/specweave/hooks/pre-edit-spec.sh +11 -0
  33. package/plugins/specweave/hooks/pre-task-completion.sh +69 -2
  34. package/plugins/specweave/hooks/pre-write-spec.sh +11 -0
  35. package/plugins/specweave/skills/increment-planner/SKILL.md +124 -4
  36. package/plugins/specweave-frontend/agents/frontend-architect/AGENT.md +21 -0
  37. package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +150 -0
  38. package/plugins/specweave-payments/commands/stripe-setup.md +931 -0
  39. package/plugins/specweave-payments/commands/subscription-flow.md +1193 -0
  40. package/plugins/specweave-payments/commands/subscription-manage.md +386 -0
  41. package/plugins/specweave-payments/commands/webhook-setup.md +295 -0
  42. 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;AAgB9D,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,CA80Cf"}
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)' : '(recommended)'}`,
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 Selection for GitHub (if GitHub detected and token available)
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
- const { useMultiRepo } = await inquirer.prompt([
1567
- {
1568
- type: 'confirm',
1569
- name: 'useMultiRepo',
1570
- message: 'Do you want to import from multiple repositories?',
1571
- default: false
1572
- }
1573
- ]);
1574
- if (useMultiRepo) {
1575
- try {
1576
- const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
1577
- repoSelectionConfig = await selectRepositories(octokit, process.env.GITHUB_TOKEN);
1578
- if (repoSelectionConfig) {
1579
- // Save to config.json for future imports
1580
- const configPath = path.join(targetDir, '.specweave', 'config.json');
1581
- let config = {};
1582
- if (fs.existsSync(configPath)) {
1583
- config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
1584
- }
1585
- if (!config.github) {
1586
- config.github = {};
1587
- }
1588
- config.github.repositories = repoSelectionConfig.repositories;
1589
- config.github.selectionStrategy = repoSelectionConfig.selectionStrategy;
1590
- if (repoSelectionConfig.pattern) {
1591
- config.github.pattern = repoSelectionConfig.pattern;
1592
- }
1593
- if (repoSelectionConfig.organizationName) {
1594
- config.github.organizationName = repoSelectionConfig.organizationName;
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
- fs.ensureDirSync(path.dirname(configPath));
1597
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
1598
- console.log(chalk.green(`✅ Repository selection saved to config.json\n`));
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