specweave 0.1.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.
- package/INSTALL.md +848 -0
- package/LICENSE +21 -0
- package/README.md +675 -0
- package/SPECWEAVE.md +665 -0
- package/bin/install-agents.sh +57 -0
- package/bin/install-all.sh +49 -0
- package/bin/install-commands.sh +56 -0
- package/bin/install-skills.sh +57 -0
- package/bin/specweave.js +81 -0
- package/dist/adapters/adapter-base.d.ts +50 -0
- package/dist/adapters/adapter-base.d.ts.map +1 -0
- package/dist/adapters/adapter-base.js +146 -0
- package/dist/adapters/adapter-base.js.map +1 -0
- package/dist/adapters/adapter-interface.d.ts +108 -0
- package/dist/adapters/adapter-interface.d.ts.map +1 -0
- package/dist/adapters/adapter-interface.js +9 -0
- package/dist/adapters/adapter-interface.js.map +1 -0
- package/dist/adapters/claude/adapter.d.ts +54 -0
- package/dist/adapters/claude/adapter.d.ts.map +1 -0
- package/dist/adapters/claude/adapter.js +184 -0
- package/dist/adapters/claude/adapter.js.map +1 -0
- package/dist/adapters/copilot/adapter.d.ts +42 -0
- package/dist/adapters/copilot/adapter.d.ts.map +1 -0
- package/dist/adapters/copilot/adapter.js +239 -0
- package/dist/adapters/copilot/adapter.js.map +1 -0
- package/dist/adapters/cursor/adapter.d.ts +42 -0
- package/dist/adapters/cursor/adapter.d.ts.map +1 -0
- package/dist/adapters/cursor/adapter.js +297 -0
- package/dist/adapters/cursor/adapter.js.map +1 -0
- package/dist/adapters/generic/adapter.d.ts +40 -0
- package/dist/adapters/generic/adapter.d.ts.map +1 -0
- package/dist/adapters/generic/adapter.js +155 -0
- package/dist/adapters/generic/adapter.js.map +1 -0
- package/dist/cli/commands/init.d.ts +6 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +247 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/install.d.ts +7 -0
- package/dist/cli/commands/install.d.ts.map +1 -0
- package/dist/cli/commands/install.js +160 -0
- package/dist/cli/commands/install.js.map +1 -0
- package/dist/cli/commands/list.d.ts +6 -0
- package/dist/cli/commands/list.d.ts.map +1 -0
- package/dist/cli/commands/list.js +154 -0
- package/dist/cli/commands/list.js.map +1 -0
- package/package.json +90 -0
- package/src/adapters/README.md +312 -0
- package/src/adapters/adapter-base.ts +146 -0
- package/src/adapters/adapter-interface.ts +120 -0
- package/src/adapters/claude/README.md +241 -0
- package/src/adapters/claude/adapter.ts +157 -0
- package/src/adapters/copilot/.github/copilot/instructions.md +376 -0
- package/src/adapters/copilot/README.md +200 -0
- package/src/adapters/copilot/adapter.ts +210 -0
- package/src/adapters/cursor/.cursor/context/docs-context.md +62 -0
- package/src/adapters/cursor/.cursor/context/increments-context.md +71 -0
- package/src/adapters/cursor/.cursor/context/strategy-context.md +73 -0
- package/src/adapters/cursor/.cursor/context/tests-context.md +89 -0
- package/src/adapters/cursor/.cursorrules +325 -0
- package/src/adapters/cursor/README.md +243 -0
- package/src/adapters/cursor/adapter.ts +268 -0
- package/src/adapters/generic/README.md +277 -0
- package/src/adapters/generic/SPECWEAVE-MANUAL.md +676 -0
- package/src/adapters/generic/adapter.ts +159 -0
- package/src/adapters/registry.yaml +126 -0
- package/src/agents/architect/AGENT.md +416 -0
- package/src/agents/devops/AGENT.md +1738 -0
- package/src/agents/docs-writer/AGENT.md +239 -0
- package/src/agents/performance/AGENT.md +228 -0
- package/src/agents/pm/AGENT.md +751 -0
- package/src/agents/qa-lead/AGENT.md +150 -0
- package/src/agents/security/AGENT.md +179 -0
- package/src/agents/sre/AGENT.md +582 -0
- package/src/agents/sre/modules/backend-diagnostics.md +481 -0
- package/src/agents/sre/modules/database-diagnostics.md +509 -0
- package/src/agents/sre/modules/infrastructure.md +561 -0
- package/src/agents/sre/modules/monitoring.md +439 -0
- package/src/agents/sre/modules/security-incidents.md +421 -0
- package/src/agents/sre/modules/ui-diagnostics.md +302 -0
- package/src/agents/sre/playbooks/01-high-cpu-usage.md +204 -0
- package/src/agents/sre/playbooks/02-database-deadlock.md +241 -0
- package/src/agents/sre/playbooks/03-memory-leak.md +252 -0
- package/src/agents/sre/playbooks/04-slow-api-response.md +269 -0
- package/src/agents/sre/playbooks/05-ddos-attack.md +293 -0
- package/src/agents/sre/playbooks/06-disk-full.md +314 -0
- package/src/agents/sre/playbooks/07-service-down.md +333 -0
- package/src/agents/sre/playbooks/08-data-corruption.md +337 -0
- package/src/agents/sre/playbooks/09-cascade-failure.md +430 -0
- package/src/agents/sre/playbooks/10-rate-limit-exceeded.md +464 -0
- package/src/agents/sre/scripts/health-check.sh +230 -0
- package/src/agents/sre/scripts/log-analyzer.py +213 -0
- package/src/agents/sre/scripts/metrics-collector.sh +294 -0
- package/src/agents/sre/scripts/trace-analyzer.js +257 -0
- package/src/agents/sre/templates/incident-report.md +249 -0
- package/src/agents/sre/templates/mitigation-plan.md +375 -0
- package/src/agents/sre/templates/post-mortem.md +418 -0
- package/src/agents/sre/templates/runbook-template.md +412 -0
- package/src/agents/tech-lead/AGENT.md +263 -0
- package/src/commands/add-tasks.md +176 -0
- package/src/commands/close-increment.md +347 -0
- package/src/commands/create-increment.md +223 -0
- package/src/commands/create-project.md +528 -0
- package/src/commands/generate-docs.md +623 -0
- package/src/commands/list-increments.md +180 -0
- package/src/commands/review-docs.md +331 -0
- package/src/commands/start-increment.md +139 -0
- package/src/commands/sync-github.md +115 -0
- package/src/commands/validate-increment.md +800 -0
- package/src/hooks/README.md +252 -0
- package/src/hooks/docs-changed.sh +59 -0
- package/src/hooks/human-input-required.sh +55 -0
- package/src/hooks/post-task-completion.sh +57 -0
- package/src/hooks/pre-implementation.sh +47 -0
- package/src/skills/ado-sync/README.md +449 -0
- package/src/skills/ado-sync/SKILL.md +245 -0
- package/src/skills/ado-sync/test-cases/test-1.yaml +9 -0
- package/src/skills/ado-sync/test-cases/test-2.yaml +8 -0
- package/src/skills/ado-sync/test-cases/test-3.yaml +9 -0
- package/src/skills/bmad-method-expert/SKILL.md +628 -0
- package/src/skills/bmad-method-expert/scripts/analyze-project.js +318 -0
- package/src/skills/bmad-method-expert/scripts/check-setup.js +208 -0
- package/src/skills/bmad-method-expert/scripts/generate-template.js +1149 -0
- package/src/skills/bmad-method-expert/scripts/validate-documents.js +340 -0
- package/src/skills/bmad-method-expert/test-cases/test-1-placeholder.yaml +12 -0
- package/src/skills/bmad-method-expert/test-cases/test-2-placeholder.yaml +12 -0
- package/src/skills/bmad-method-expert/test-cases/test-3-placeholder.yaml +12 -0
- package/src/skills/brownfield-analyzer/SKILL.md +523 -0
- package/src/skills/brownfield-analyzer/test-cases/test-1-basic-analysis.yaml +48 -0
- package/src/skills/brownfield-analyzer/test-cases/test-2-placeholder.yaml +12 -0
- package/src/skills/brownfield-analyzer/test-cases/test-3-placeholder.yaml +12 -0
- package/src/skills/brownfield-onboarder/SKILL.md +625 -0
- package/src/skills/brownfield-onboarder/test-cases/test-1-placeholder.yaml +12 -0
- package/src/skills/brownfield-onboarder/test-cases/test-2-placeholder.yaml +12 -0
- package/src/skills/brownfield-onboarder/test-cases/test-3-placeholder.yaml +12 -0
- package/src/skills/calendar-system/test-cases/test-1-placeholder.yaml +12 -0
- package/src/skills/calendar-system/test-cases/test-2-placeholder.yaml +12 -0
- package/src/skills/calendar-system/test-cases/test-3-placeholder.yaml +12 -0
- package/src/skills/context-loader/SKILL.md +734 -0
- package/src/skills/context-loader/test-cases/test-1-basic-loading.yaml +39 -0
- package/src/skills/context-loader/test-cases/test-2-token-budget-exceeded.yaml +44 -0
- package/src/skills/context-loader/test-cases/test-3-section-anchors.yaml +45 -0
- package/src/skills/context-optimizer/SKILL.md +618 -0
- package/src/skills/context-optimizer/test-cases/test-1-bug-fix-narrow.yaml +97 -0
- package/src/skills/context-optimizer/test-cases/test-2-feature-focused.yaml +109 -0
- package/src/skills/context-optimizer/test-cases/test-3-architecture-broad.yaml +98 -0
- package/src/skills/cost-optimizer/SKILL.md +190 -0
- package/src/skills/cost-optimizer/test-cases/test-1-basic-comparison.yaml +75 -0
- package/src/skills/cost-optimizer/test-cases/test-2-budget-constraint.yaml +52 -0
- package/src/skills/cost-optimizer/test-cases/test-3-scale-requirement.yaml +63 -0
- package/src/skills/cost-optimizer/test-results/README.md +46 -0
- package/src/skills/design-system-architect/SKILL.md +107 -0
- package/src/skills/design-system-architect/test-cases/test-1-token-structure.yaml +23 -0
- package/src/skills/design-system-architect/test-cases/test-2-component-hierarchy.yaml +24 -0
- package/src/skills/design-system-architect/test-cases/test-3-accessibility-checklist.yaml +23 -0
- package/src/skills/diagrams-architect/SKILL.md +763 -0
- package/src/skills/diagrams-generator/SKILL.md +25 -0
- package/src/skills/diagrams-generator/test-cases/test-1.yaml +9 -0
- package/src/skills/diagrams-generator/test-cases/test-2.yaml +9 -0
- package/src/skills/diagrams-generator/test-cases/test-3.yaml +8 -0
- package/src/skills/docs-updater/README.md +48 -0
- package/src/skills/docs-updater/test-cases/test-1-placeholder.yaml +12 -0
- package/src/skills/docs-updater/test-cases/test-2-placeholder.yaml +12 -0
- package/src/skills/docs-updater/test-cases/test-3-placeholder.yaml +12 -0
- package/src/skills/dotnet-backend/SKILL.md +250 -0
- package/src/skills/e2e-playwright/README.md +506 -0
- package/src/skills/e2e-playwright/SKILL.md +457 -0
- package/src/skills/e2e-playwright/execute.js +373 -0
- package/src/skills/e2e-playwright/lib/utils.js +514 -0
- package/src/skills/e2e-playwright/package.json +33 -0
- package/src/skills/e2e-playwright/test-cases/TC-001-basic-navigation.yaml +54 -0
- package/src/skills/e2e-playwright/test-cases/TC-002-form-interaction.yaml +64 -0
- package/src/skills/e2e-playwright/test-cases/TC-003-specweave-integration.yaml +74 -0
- package/src/skills/e2e-playwright/test-cases/TC-004-accessibility-check.yaml +98 -0
- package/src/skills/figma-designer/SKILL.md +149 -0
- package/src/skills/figma-implementer/SKILL.md +148 -0
- package/src/skills/figma-mcp-connector/SKILL.md +136 -0
- package/src/skills/figma-mcp-connector/test-cases/test-1-read-file-desktop.yaml +22 -0
- package/src/skills/figma-mcp-connector/test-cases/test-2-read-file-framelink.yaml +21 -0
- package/src/skills/figma-mcp-connector/test-cases/test-3-error-handling.yaml +18 -0
- package/src/skills/figma-to-code/SKILL.md +128 -0
- package/src/skills/figma-to-code/test-cases/test-1-token-generation.yaml +29 -0
- package/src/skills/figma-to-code/test-cases/test-2-component-generation.yaml +27 -0
- package/src/skills/figma-to-code/test-cases/test-3-typescript-generation.yaml +28 -0
- package/src/skills/frontend/SKILL.md +177 -0
- package/src/skills/github-sync/SKILL.md +252 -0
- package/src/skills/github-sync/test-cases/test-1-placeholder.yaml +12 -0
- package/src/skills/github-sync/test-cases/test-2-placeholder.yaml +12 -0
- package/src/skills/github-sync/test-cases/test-3-placeholder.yaml +12 -0
- package/src/skills/hetzner-provisioner/README.md +308 -0
- package/src/skills/hetzner-provisioner/SKILL.md +251 -0
- package/src/skills/hetzner-provisioner/test-cases/test-1-basic-provision.yaml +71 -0
- package/src/skills/hetzner-provisioner/test-cases/test-2-postgres-provision.yaml +85 -0
- package/src/skills/hetzner-provisioner/test-cases/test-3-ssl-config.yaml +126 -0
- package/src/skills/hetzner-provisioner/test-results/README.md +259 -0
- package/src/skills/increment-planner/SKILL.md +889 -0
- package/src/skills/increment-planner/scripts/feature-utils.js +250 -0
- package/src/skills/increment-planner/test-cases/test-1-basic-feature.yaml +27 -0
- package/src/skills/increment-planner/test-cases/test-2-complex-feature.yaml +30 -0
- package/src/skills/increment-planner/test-cases/test-3-auto-numbering.yaml +24 -0
- package/src/skills/increment-quality-judge/SKILL.md +566 -0
- package/src/skills/increment-quality-judge/test-cases/test-1-good-spec.yaml +95 -0
- package/src/skills/increment-quality-judge/test-cases/test-2-poor-spec.yaml +108 -0
- package/src/skills/increment-quality-judge/test-cases/test-3-export-suggestions.yaml +87 -0
- package/src/skills/jira-sync/README.md +328 -0
- package/src/skills/jira-sync/SKILL.md +209 -0
- package/src/skills/jira-sync/test-cases/test-1.yaml +9 -0
- package/src/skills/jira-sync/test-cases/test-2.yaml +9 -0
- package/src/skills/jira-sync/test-cases/test-3.yaml +10 -0
- package/src/skills/nextjs/SKILL.md +176 -0
- package/src/skills/nodejs-backend/SKILL.md +181 -0
- package/src/skills/notification-system/test-cases/test-1-placeholder.yaml +12 -0
- package/src/skills/notification-system/test-cases/test-2-placeholder.yaml +12 -0
- package/src/skills/notification-system/test-cases/test-3-placeholder.yaml +12 -0
- package/src/skills/python-backend/SKILL.md +226 -0
- package/src/skills/role-orchestrator/README.md +197 -0
- package/src/skills/role-orchestrator/SKILL.md +1184 -0
- package/src/skills/role-orchestrator/test-cases/test-1-simple-product.yaml +98 -0
- package/src/skills/role-orchestrator/test-cases/test-2-quality-gate-failure.yaml +73 -0
- package/src/skills/role-orchestrator/test-cases/test-3-security-workflow.yaml +121 -0
- package/src/skills/role-orchestrator/test-cases/test-4-parallel-execution.yaml +145 -0
- package/src/skills/role-orchestrator/test-cases/test-5-feedback-loops.yaml +149 -0
- package/src/skills/skill-creator/LICENSE.txt +202 -0
- package/src/skills/skill-creator/SKILL.md +209 -0
- package/src/skills/skill-creator/scripts/init_skill.py +303 -0
- package/src/skills/skill-creator/scripts/package_skill.py +110 -0
- package/src/skills/skill-creator/scripts/quick_validate.py +65 -0
- package/src/skills/skill-creator/test-cases/test-1-placeholder.yaml +12 -0
- package/src/skills/skill-creator/test-cases/test-2-placeholder.yaml +12 -0
- package/src/skills/skill-creator/test-cases/test-3-placeholder.yaml +12 -0
- package/src/skills/skill-router/SKILL.md +497 -0
- package/src/skills/skill-router/test-cases/test-1-basic-routing.yaml +33 -0
- package/src/skills/skill-router/test-cases/test-2-ambiguous-request.yaml +42 -0
- package/src/skills/skill-router/test-cases/test-3-nested-orchestration.yaml +50 -0
- package/src/skills/spec-driven-brainstorming/README.md +264 -0
- package/src/skills/spec-driven-brainstorming/SKILL.md +439 -0
- package/src/skills/spec-driven-brainstorming/test-cases/TC-001-simple-idea-to-design.yaml +148 -0
- package/src/skills/spec-driven-brainstorming/test-cases/TC-002-complex-ultrathink-design.yaml +190 -0
- package/src/skills/spec-driven-brainstorming/test-cases/TC-003-unclear-requirements-socratic.yaml +233 -0
- package/src/skills/spec-driven-debugging/README.md +479 -0
- package/src/skills/spec-driven-debugging/SKILL.md +652 -0
- package/src/skills/spec-driven-debugging/test-cases/TC-001-simple-auth-bug.yaml +212 -0
- package/src/skills/spec-driven-debugging/test-cases/TC-002-race-condition-ultrathink.yaml +461 -0
- package/src/skills/spec-driven-debugging/test-cases/TC-003-brownfield-missing-spec.yaml +366 -0
- package/src/skills/spec-kit-expert/SKILL.md +1012 -0
- package/src/skills/spec-kit-expert/test-cases/test-1-placeholder.yaml +12 -0
- package/src/skills/spec-kit-expert/test-cases/test-2-placeholder.yaml +12 -0
- package/src/skills/spec-kit-expert/test-cases/test-3-placeholder.yaml +12 -0
- package/src/skills/specweave-ado-mapper/SKILL.md +501 -0
- package/src/skills/specweave-detector/SKILL.md +420 -0
- package/src/skills/specweave-detector/test-cases/test-1-basic-detection.yaml +37 -0
- package/src/skills/specweave-detector/test-cases/test-2-missing-config.yaml +37 -0
- package/src/skills/specweave-detector/test-cases/test-3-non-specweave-project.yaml +34 -0
- package/src/skills/specweave-jira-mapper/SKILL.md +500 -0
- package/src/skills/stripe-integrator/test-cases/test-1-placeholder.yaml +12 -0
- package/src/skills/stripe-integrator/test-cases/test-2-placeholder.yaml +12 -0
- package/src/skills/stripe-integrator/test-cases/test-3-placeholder.yaml +12 -0
- package/src/skills/task-builder/README.md +90 -0
- package/src/skills/task-builder/test-cases/test-1-placeholder.yaml +12 -0
- package/src/skills/task-builder/test-cases/test-2-placeholder.yaml +12 -0
- package/src/skills/task-builder/test-cases/test-3-placeholder.yaml +12 -0
- package/src/templates/.env.example +144 -0
- package/src/templates/.gitignore.template +81 -0
- package/src/templates/CLAUDE.md.template +383 -0
- package/src/templates/README.md.template +240 -0
- package/src/templates/config.yaml +333 -0
- package/src/templates/docs/README.md +124 -0
- package/src/templates/docs/adr-template.md +118 -0
- package/src/templates/docs/hld-template.md +220 -0
- package/src/templates/docs/lld-template.md +580 -0
- package/src/templates/docs/prd-template.md +132 -0
- package/src/templates/docs/rfc-template.md +229 -0
- package/src/templates/docs/runbook-template.md +298 -0
- package/src/templates/environments/minimal/.env.production +16 -0
- package/src/templates/environments/minimal/README.md +54 -0
- package/src/templates/environments/minimal/deploy-production.yml +52 -0
- package/src/templates/environments/progressive/.env.qa +28 -0
- package/src/templates/environments/progressive/README.md +129 -0
- package/src/templates/environments/progressive/deploy-production.yml +93 -0
- package/src/templates/environments/progressive/deploy-qa.yml +62 -0
- package/src/templates/environments/progressive/deploy-staging.yml +67 -0
- package/src/templates/environments/standard/.env.development +20 -0
- package/src/templates/environments/standard/.env.production +30 -0
- package/src/templates/environments/standard/.env.staging +23 -0
- package/src/templates/environments/standard/README.md +97 -0
- package/src/templates/environments/standard/deploy-production.yml +68 -0
- package/src/templates/environments/standard/deploy-staging.yml +61 -0
- package/src/templates/environments/standard/docker-compose.yml +43 -0
- package/src/templates/increment-metadata-template.yaml +138 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature Planning Utilities for SpecWeave
|
|
3
|
+
* Supports increment-planner skill with auto-numbering and name generation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Stop words to filter from feature descriptions
|
|
11
|
+
*/
|
|
12
|
+
const STOP_WORDS = new Set([
|
|
13
|
+
'a', 'an', 'the', 'and', 'or', 'but', 'for', 'with', 'to', 'from', 'in', 'on', 'at',
|
|
14
|
+
'by', 'of', 'as', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
|
|
15
|
+
'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could', 'should',
|
|
16
|
+
'can', 'may', 'might', 'must', 'i', 'you', 'we', 'they', 'it', 'this', 'that',
|
|
17
|
+
'want', 'need', 'help', 'please', 'create', 'make', 'build'
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Generate a short feature name from description
|
|
22
|
+
* @param {string} description - Feature description
|
|
23
|
+
* @returns {string} Short kebab-case name
|
|
24
|
+
*/
|
|
25
|
+
function generateShortName(description) {
|
|
26
|
+
// Lowercase and remove special characters
|
|
27
|
+
let cleaned = description
|
|
28
|
+
.toLowerCase()
|
|
29
|
+
.replace(/[^a-z0-9\s-]/g, ' ')
|
|
30
|
+
.trim();
|
|
31
|
+
|
|
32
|
+
// Split into words
|
|
33
|
+
let words = cleaned.split(/\s+/);
|
|
34
|
+
|
|
35
|
+
// Filter stop words
|
|
36
|
+
let meaningful = words.filter(word =>
|
|
37
|
+
word.length > 2 && !STOP_WORDS.has(word)
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
// Take first 2-4 most meaningful words
|
|
41
|
+
let selected = meaningful.slice(0, Math.min(4, meaningful.length));
|
|
42
|
+
|
|
43
|
+
// Join with hyphens
|
|
44
|
+
let shortName = selected.join('-');
|
|
45
|
+
|
|
46
|
+
// Enforce max 50 characters
|
|
47
|
+
if (shortName.length > 50) {
|
|
48
|
+
shortName = shortName.substring(0, 47) + '...';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return shortName || 'new-feature';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Get the next available feature number
|
|
56
|
+
* @param {string} featuresDir - Path to features directory (default: '.specweave/increments')
|
|
57
|
+
* @returns {string} Next feature number (zero-padded to 4 digits: 0001-9999)
|
|
58
|
+
*/
|
|
59
|
+
function getNextFeatureNumber(featuresDir = '.specweave/increments') {
|
|
60
|
+
let highest = 0;
|
|
61
|
+
|
|
62
|
+
if (fs.existsSync(featuresDir)) {
|
|
63
|
+
const entries = fs.readdirSync(featuresDir);
|
|
64
|
+
|
|
65
|
+
entries.forEach(entry => {
|
|
66
|
+
// Match BOTH 3-digit (legacy) and 4-digit formats to prevent conflicts
|
|
67
|
+
const match = entry.match(/^(\d{3,4})-/);
|
|
68
|
+
if (match) {
|
|
69
|
+
const num = parseInt(match[1], 10);
|
|
70
|
+
if (num > highest) {
|
|
71
|
+
highest = num;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const next = highest + 1;
|
|
78
|
+
|
|
79
|
+
// Always return 4-digit format
|
|
80
|
+
return String(next).padStart(4, '0');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Check if feature name already exists
|
|
85
|
+
* @param {string} shortName - Feature short name
|
|
86
|
+
* @param {string} featuresDir - Path to features directory
|
|
87
|
+
* @returns {boolean} True if exists
|
|
88
|
+
*/
|
|
89
|
+
function featureExists(shortName, featuresDir = '.specweave/increments') {
|
|
90
|
+
if (!fs.existsSync(featuresDir)) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const entries = fs.readdirSync(featuresDir);
|
|
95
|
+
return entries.some(entry => entry.endsWith(`-${shortName}`));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Check if increment number already exists (prevents duplicates like 0002, 0002)
|
|
100
|
+
* @param {string} incrementNumber - Increment number to check (e.g., '0001')
|
|
101
|
+
* @param {string} featuresDir - Path to features directory
|
|
102
|
+
* @returns {boolean} True if number already exists
|
|
103
|
+
*/
|
|
104
|
+
function incrementNumberExists(incrementNumber, featuresDir = '.specweave/increments') {
|
|
105
|
+
if (!fs.existsSync(featuresDir)) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const entries = fs.readdirSync(featuresDir);
|
|
110
|
+
|
|
111
|
+
// Normalize to 4-digit format for comparison
|
|
112
|
+
const normalizedNum = String(incrementNumber).padStart(4, '0');
|
|
113
|
+
|
|
114
|
+
return entries.some(entry => {
|
|
115
|
+
const match = entry.match(/^(\d{3,4})-/);
|
|
116
|
+
if (match) {
|
|
117
|
+
const entryNum = String(match[1]).padStart(4, '0');
|
|
118
|
+
return entryNum === normalizedNum;
|
|
119
|
+
}
|
|
120
|
+
return false;
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Create feature directory structure
|
|
126
|
+
* @param {string} featureNumber - Feature number (e.g., '0001')
|
|
127
|
+
* @param {string} shortName - Feature short name
|
|
128
|
+
* @param {string} featuresDir - Path to features directory
|
|
129
|
+
* @returns {string} Full feature path
|
|
130
|
+
* @throws {Error} If increment number already exists
|
|
131
|
+
*/
|
|
132
|
+
function createFeatureDirectory(featureNumber, shortName, featuresDir = '.specweave/increments') {
|
|
133
|
+
// Normalize to 4-digit format
|
|
134
|
+
const normalizedNumber = String(featureNumber).padStart(4, '0');
|
|
135
|
+
|
|
136
|
+
// Check for duplicate increment number
|
|
137
|
+
if (incrementNumberExists(normalizedNumber, featuresDir)) {
|
|
138
|
+
throw new Error(`Increment number ${normalizedNumber} already exists! Use getNextFeatureNumber() to get the next available number.`);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const featurePath = path.join(featuresDir, `${normalizedNumber}-${shortName}`);
|
|
142
|
+
|
|
143
|
+
if (!fs.existsSync(featuresDir)) {
|
|
144
|
+
fs.mkdirSync(featuresDir, { recursive: true });
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (!fs.existsSync(featurePath)) {
|
|
148
|
+
fs.mkdirSync(featurePath, { recursive: true });
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return featurePath;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Extract priority from description
|
|
156
|
+
* @param {string} description - Feature description
|
|
157
|
+
* @returns {string} Priority level (P1, P2, or P3)
|
|
158
|
+
*/
|
|
159
|
+
function extractPriority(description) {
|
|
160
|
+
const lower = description.toLowerCase();
|
|
161
|
+
|
|
162
|
+
// Check for explicit priority mentions
|
|
163
|
+
if (lower.includes('critical') || lower.includes('must have') || lower.includes('mvp')) {
|
|
164
|
+
return 'P1';
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (lower.includes('nice to have') || lower.includes('polish') || lower.includes('optional')) {
|
|
168
|
+
return 'P3';
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Default to P2 (important)
|
|
172
|
+
return 'P2';
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Get current date in YYYY-MM-DD format
|
|
177
|
+
* @returns {string} Current date
|
|
178
|
+
*/
|
|
179
|
+
function getCurrentDate() {
|
|
180
|
+
const now = new Date();
|
|
181
|
+
const year = now.getFullYear();
|
|
182
|
+
const month = String(now.getMonth() + 1).padStart(2, '0');
|
|
183
|
+
const day = String(now.getDate()).padStart(2, '0');
|
|
184
|
+
return `${year}-${month}-${day}`;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Parse feature description into structured data
|
|
189
|
+
* @param {string} description - Feature description
|
|
190
|
+
* @returns {object} Parsed feature data
|
|
191
|
+
*/
|
|
192
|
+
function parseFeatureDescription(description) {
|
|
193
|
+
return {
|
|
194
|
+
description,
|
|
195
|
+
shortName: generateShortName(description),
|
|
196
|
+
priority: extractPriority(description),
|
|
197
|
+
createdDate: getCurrentDate()
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
module.exports = {
|
|
202
|
+
generateShortName,
|
|
203
|
+
getNextFeatureNumber,
|
|
204
|
+
featureExists,
|
|
205
|
+
incrementNumberExists,
|
|
206
|
+
createFeatureDirectory,
|
|
207
|
+
extractPriority,
|
|
208
|
+
getCurrentDate,
|
|
209
|
+
parseFeatureDescription,
|
|
210
|
+
STOP_WORDS
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
// CLI usage
|
|
214
|
+
if (require.main === module) {
|
|
215
|
+
const args = process.argv.slice(2);
|
|
216
|
+
|
|
217
|
+
if (args.length === 0) {
|
|
218
|
+
console.log('Usage:');
|
|
219
|
+
console.log(' node feature-utils.js shortname "feature description"');
|
|
220
|
+
console.log(' node feature-utils.js next [features-dir]');
|
|
221
|
+
console.log(' node feature-utils.js parse "feature description"');
|
|
222
|
+
process.exit(0);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const command = args[0];
|
|
226
|
+
|
|
227
|
+
switch (command) {
|
|
228
|
+
case 'shortname':
|
|
229
|
+
if (args[1]) {
|
|
230
|
+
console.log(generateShortName(args[1]));
|
|
231
|
+
}
|
|
232
|
+
break;
|
|
233
|
+
|
|
234
|
+
case 'next':
|
|
235
|
+
const dir = args[1] || '.specweave/increments';
|
|
236
|
+
console.log(getNextFeatureNumber(dir));
|
|
237
|
+
break;
|
|
238
|
+
|
|
239
|
+
case 'parse':
|
|
240
|
+
if (args[1]) {
|
|
241
|
+
const parsed = parseFeatureDescription(args[1]);
|
|
242
|
+
console.log(JSON.stringify(parsed, null, 2));
|
|
243
|
+
}
|
|
244
|
+
break;
|
|
245
|
+
|
|
246
|
+
default:
|
|
247
|
+
console.error(`Unknown command: ${command}`);
|
|
248
|
+
process.exit(1);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "Basic Feature Planning"
|
|
3
|
+
description: "Tests if increment-planner can create a basic feature from a simple description"
|
|
4
|
+
input:
|
|
5
|
+
prompt: "Plan a feature for user authentication with email and password"
|
|
6
|
+
files: []
|
|
7
|
+
expected_output:
|
|
8
|
+
type: "files_generated"
|
|
9
|
+
files:
|
|
10
|
+
- "features/001-user-authentication/spec.md"
|
|
11
|
+
- "features/001-user-authentication/plan.md"
|
|
12
|
+
- "features/001-user-authentication/tasks.md"
|
|
13
|
+
- "features/001-user-authentication/tests.md"
|
|
14
|
+
- "features/001-user-authentication/context-manifest.yaml"
|
|
15
|
+
contains:
|
|
16
|
+
- "User authentication"
|
|
17
|
+
- "P1"
|
|
18
|
+
- "Acceptance Criteria"
|
|
19
|
+
- "Test-First"
|
|
20
|
+
validation:
|
|
21
|
+
- "All files exist in correct directory"
|
|
22
|
+
- "spec.md is technology-agnostic"
|
|
23
|
+
- "plan.md contains technical decisions"
|
|
24
|
+
- "tasks.md has test-first sequencing"
|
|
25
|
+
- "tests.md covers P1 user stories"
|
|
26
|
+
- "context-manifest.yaml has token budget"
|
|
27
|
+
---
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "Complex Feature with Multiple User Stories"
|
|
3
|
+
description: "Tests feature planning for a complex feature with multiple priorities"
|
|
4
|
+
input:
|
|
5
|
+
prompt: "Plan a feature for Stripe payment integration including subscriptions, one-time payments, and webhooks"
|
|
6
|
+
files: []
|
|
7
|
+
expected_output:
|
|
8
|
+
type: "files_generated"
|
|
9
|
+
files:
|
|
10
|
+
- "features/002-stripe-payment-integration/spec.md"
|
|
11
|
+
- "features/002-stripe-payment-integration/plan.md"
|
|
12
|
+
- "features/002-stripe-payment-integration/tasks.md"
|
|
13
|
+
- "features/002-stripe-payment-integration/tests.md"
|
|
14
|
+
- "features/002-stripe-payment-integration/context-manifest.yaml"
|
|
15
|
+
contains:
|
|
16
|
+
- "US1"
|
|
17
|
+
- "US2"
|
|
18
|
+
- "US3"
|
|
19
|
+
- "P1"
|
|
20
|
+
- "P2"
|
|
21
|
+
- "Stripe"
|
|
22
|
+
- "subscriptions"
|
|
23
|
+
- "webhooks"
|
|
24
|
+
validation:
|
|
25
|
+
- "Multiple user stories with different priorities"
|
|
26
|
+
- "P1/P2/P3 prioritization present"
|
|
27
|
+
- "tasks.md organized by user story"
|
|
28
|
+
- "tests.md has integration tests"
|
|
29
|
+
- "context-manifest.yaml references payment specs"
|
|
30
|
+
---
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "Auto-Numbering Feature Test"
|
|
3
|
+
description: "Tests that features are correctly auto-numbered when previous features exist"
|
|
4
|
+
input:
|
|
5
|
+
prompt: "Plan a feature for email notifications"
|
|
6
|
+
files:
|
|
7
|
+
- "features/001-user-authentication/"
|
|
8
|
+
- "features/002-stripe-payment-integration/"
|
|
9
|
+
expected_output:
|
|
10
|
+
type: "files_generated"
|
|
11
|
+
files:
|
|
12
|
+
- "features/003-email-notifications/spec.md"
|
|
13
|
+
- "features/003-email-notifications/plan.md"
|
|
14
|
+
- "features/003-email-notifications/tasks.md"
|
|
15
|
+
- "features/003-email-notifications/tests.md"
|
|
16
|
+
- "features/003-email-notifications/context-manifest.yaml"
|
|
17
|
+
contains:
|
|
18
|
+
- "feature: 003-email-notifications"
|
|
19
|
+
- "003"
|
|
20
|
+
validation:
|
|
21
|
+
- "Feature number is 003 (incremented from 002)"
|
|
22
|
+
- "No conflicts with existing features"
|
|
23
|
+
- "features/README.md updated with new feature"
|
|
24
|
+
---
|